普通视图

发现新文章,点击刷新页面。
昨天以前梦溪博客

浏览器报错Mixed Content

作者 cyril
2023年12月7日 04:34

今天新建了一个wordpress网站,在安装主题后一直报错,

Mixed Content

在搜索后了解到:
[scode type=”share”]HTML页面是通过HTTPS加载的,但是其他资源文件(如图片,视频,样式表文件,脚本)是使用HTTP方式加载的。之所以称为混合内容,是因为在一个网页中同时使用了HTTP和HTTPS,而最初的请求方式为
HTTPS。

现代浏览器可能会阻止此类内容,或者显示关于此类内容的警告,提醒用户此页面包含不安全的内容。阻止混合内容的浏览器可能会首先尝试将该内容的连接从HTTP
“升级”到HTTPS。[/scode]

可以在页面头部添加meta标签解决

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

这样可以把http连接转为https

同样还因为这个问题导致我的主题校验失败
我安装的是子比主题,因为域名在cloudfare做了cdn代理,所以请求是https,但是主题验证的时候发出的请求是http,导致一直出现网络错误,可以直接这样解决,或者先不通过cloudfare代理

Visual Studio Code 在终端运行 pnpm 你要如何运行这个文件

作者 cyril
2023年12月6日 03:05

2023-12-05T11:03:45.png

2023-12-05T11:04:00.png

在vscode终端中执行npm命令时,不会执行npm命令而是弹窗:“你要如何打开这个文件?”

经测试在cmd中正常执行npm命令,排除npm问题

原因:系统中存在npm文件,执行npm命令时操作的是这个npm文件

解决方案:使用get-command npm命令查询npm命令,查看右侧Source来源并删除此目录下npm文件

如果是pnpm出现同样的问题,那就使用get-command pnpm命令解决问题

VIte 是什么

作者 cyril
2023年12月5日 20:49

Vite 是一个旨在为现代 Web 项目提供更快速、更精简的开发体验的构建工具。
它由两个主要部分组成:一个开发服务器,通过原生 ES 模块提供丰富的功能增强,例如极快的模块热更新(HMR);一个构建命令,使用 Rollup 对您的代码进行打包,预配置以输出高度优化的静态资源以供生产使用。Vite 是一种有见地的工具,具有合理的默认设置。它还通过其插件 API 和 JavaScript API 提供了高度可扩展性,并支持完整的类型支持。
Vite 还支持通过插件实现对框架的支持或与其他工具的集成。您可以通过插件来实现对框架的支持或与其他工具的集成。
Vite 还支持通过插件实现对框架的支持或与其他工具的集成。您可以通过插件来实现对框架的支持或与其他工具的集成。

canvas实现动态时钟

作者 cyril
2023年11月21日 01:25

canvas实现动态时钟

2023-11-20T09:25:26.png

    <canvas id="can" width="500" height="500" style="background-color: pink;">

    </canvas>
   
</body>
<script>
    function showTime(){
        var now = new Date();
    var hours = now.getHours();
    var mins = now.getMinutes();
    var secs = now.getSeconds();
    hours = hours + mins/60;
    // 获取画布
    var canvas = document.getElementById("can")
    // 获取画笔
    var g = can.getContext("2d");
    //清理画布
    g.clearRect(0, 0, canvas.width, canvas.height);
    // 开启路径
    g.beginPath();
    g.strokeStyle = "white";
    g.lineWidth =2;
    g.arc(250, 250, 250, 0, Math.PI * 2, true)
    g.stroke();
    g.closePath();
    //表盘
    for(var i=0; i<12;i++){ 
    g.save();
    g.translate(250,250);
    g.beginPath();
    g.rotate(i*30*Math.PI/180)

    g.strokeStyle="red";
    g.lineWidth=5;
    g.moveTo(0,-225);
    g.lineTo(0,-205);
    g.stroke();
    g.closePath();
    g.restore();
}
    //时针
    g.save();
    g.translate(250,250);
    g.beginPath();
    g.rotate(hours*30*Math.PI/180);
    g.strokeStyle="red";
    g.lineWidth=7;
    g.moveTo(0,-50);
    g.lineTo(0,-0);
    g.stroke();
    g.closePath();
    g.restore();
     //分针
    g.save();
    g.translate(250,250);
    g.beginPath();
    g.rotate(mins*6*Math.PI/180);
    g.strokeStyle="red";
    g.lineWidth=5;
    g.moveTo(0,-100);
    g.lineTo(0,0);
    g.stroke();
    g.closePath();
    g.restore();
    //秒针
    g.save();
    g.translate(250,250);
    g.beginPath();
    g.rotate(secs*6*Math.PI/180);
    g.strokeStyle="red";
    g.lineWidth=3;
    g.moveTo(0,-160);
    g.lineTo(0,10);
    g.stroke();
    g.closePath();
    g.restore();
    }
    //每秒执行一次
    setInterval(showTime,1000);
    //先执行一次,消除延迟
    showTime();
</script>

大家吃什么呢 随机选择小程序下载

作者 cyril
2024年3月28日 20:16

扫码体验

![](https://secure2.wostatic.cn/static/xsj5DKapPS6yciFW2JZR9a/image.png?auth_key=1711627428-66pNsJewtRnPQBAHZLzfmx-0-6d4bb26c4bb183b8eb701acaeff4a753)

大家吃什么呢

大家吃什么呢是一款随机选择吃什么的抽奖小程序,选择困难症的福音。使用微信原生开发和vant组件。

2024-03-28T12:16:10.png

多种选择

内置多种选择,奶茶、早餐、正餐、夜宵等,可自主编辑

CPS

内置美团、饿了么CPS,可自行替换成自己的cps,获取收益。

或自行添加流量主

2024-03-28T12:15:37.png

AI编写

本小程序大部分代码基本都由chatgpt3.5完成,真的非常的强大,这里提供一个体验地址

http://chat.telloai.cn/

小程序下载地址

下载:https://wwp.lanzouq.com/iHcel1szk4mb 密码:4bax

人像转漫画 腾讯云API Dcloud 云空间

作者 cyril
2023年12月23日 14:42

face-cartoon代码

'use strict';
exports.main = async (event, context) => {
    console.log("event",event)
    //event为客户端上传的参数
    // Depends on tencentcloud-sdk-nodejs version 4.0.3 or higher
    const tencentcloud = require("tencentcloud-sdk-nodejs-ft");
    const FtClient = tencentcloud.ft.v20200304.Client;
    // 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
    // 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305
    // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
    const clientConfig = {
      credential: {
        secretId: "AKIDxz20qYBi7OrAZzPerAOSNJApbJ7qR4mQ",
        secretKey: "oNhnhQwDG6j8OTLzNZZLwMfx2sfFbjmh",
      },
      region: "ap-beijing",
      profile: {
        httpProfile: {
          endpoint: "ft.tencentcloudapi.com",
        },
      },
    };
    
    // 实例化要请求产品的client对象,clientProfile是可选的
    const client = new FtClient(clientConfig);
    const params = {
        "Url": event.Url
    };
    
    const img_base = client.FaceCartoonPic(params).then(
      (data) => {
        console.log("data",data);
        return data
      },
      (err) => {
        console.error("error", err);
      }
    );
    
    //返回数据给客户端
    return img_base
};


前端页面

<template>
    <view class="container">
        <view class="img_create">
            <img mode="scaleToFill" :src="img_base" />
        </view>
        <view class="btn">
            <button class="mini-btn" type="primary" size="mini" @tap="imageUpload">上传图片</button>
            <button class="mini-btn" type="warn" size="mini" @click="download">下载图片</button>
        </view>

        <ad unit-id="adunit-7dd03658ef466a2c" ad-type="video" ad-theme="white" bindload="adLoad" binderror="adError"
            bindclose="adClose"></ad>


    </view>
</template>

<script>
    export default {
        data() {
            return {
                img_base: 'https://mp-7adc7bdd-1455-4caf-bb14-bf1e145956b2.cdn.bspapp.com/cloudstorage/61ffaf10-a591-4322-a9f5-ded01a8284d9.jpg',
                filePath: ''
            }
        },
        //广告加载
        adLoad() {
            console.log('视频广告 广告加载成功')
        },
        adError(err) {
            console.error('视频广告 广告加载失败', err)
        },
        adClose() {
            console.log('视频广告 广告关闭')
        },
        methods: {
            //下载图片
            
            download() {
                const url = this.img_base
                uni.showLoading({
                    title: '加载中...'
                });
                //uni.downloadFile方法:下载文件资源到本地
                uni.downloadFile({
                    url: url, //图片完整地址 此处需自己手动修改为自己的图片地址
                    success: function(res) {
                        //uni.saveImageToPhotosAlbum方法:保存图片到系统相册
                        uni.saveImageToPhotosAlbum({
                            filePath: res.tempFilePath, //图片文件路径
                            success: function(data) {
                                uni.hideLoading(); //隐藏 loading 提示框
                                uni.showModal({
                                    title: '提示',
                                    content: '保存成功',
                                    modalType: false,
                                })
                            },
                            // 接口调用失败的回调函数
                            fail: function(err) {
                                if (err.errMsg === "saveImageToPhotosAlbum:fail:auth denied" || err
                                    .errMsg === "saveImageToPhotosAlbum:fail auth deny" || err
                                    .errMsg === "saveImageToPhotosAlbum:fail authorize no response"
                                    ) {
                                    uni.showModal({
                                        title: '提示',
                                        content: '需要您授权保存相册',
                                        modalType: false,
                                        success: modalSuccess => {
                                            uni.openSetting({
                                                success(settingdata) {
                                                    console.log("settingdata",
                                                        settingdata)
                                                    if (settingdata
                                                        .authSetting[
                                                            'scope.writePhotosAlbum'
                                                            ]) {
                                                        uni.showModal({
                                                            title: '提示',
                                                            content: '获取权限成功,再次点击图片即可保存',
                                                            modalType: false,
                                                        })
                                                    } else {
                                                        uni.showModal({
                                                            title: '提示',
                                                            content: '获取权限失败,将无法保存到相册哦~',
                                                            modalType: false,
                                                        })
                                                    }
                                                },
                                                fail(failData) {
                                                    console.log("failData",
                                                        failData)
                                                },
                                                complete(finishData) {
                                                    console.log("finishData",
                                                        finishData)
                                                }
                                            })
                                        }
                                    })
                                }
                            },
                            complete(res) {
                                uni.hideLoading(); //隐藏 loading 提示框
                            }
                        })
                    }
                })


            },


            saveImage() {
                let imageName = Date.parse(new Date())
                if (this.saveImageBase == null) {
                    uni.showToast({
                        title: '请先转换图片',
                        icon: "none",
                        duration: 5000
                    })
                } else {
                    let filePath = uni.env.USER_DATA_PATH + '/' + imageName + '.png'
                    let data = this.saveImageBase //写入的文本或二进制数据
                    uni.getFileSystemManager().writeFile({
                        filePath: filePath, //创建一个临时文件名
                        data: data, //写入的文本或二进制数据
                        encoding: 'base64', //写入当前文件的字符编码
                        success: res => {
                            uni.saveImageToPhotosAlbum({
                                filePath: filePath,
                                success: function(res) {
                                    console.log(res);
                                    uni.hideLoading();
                                    uni.showToast({
                                        title: '保存成功',
                                        icon: "none",
                                        duration: 5000
                                    })
                                },
                                fail: function(err) {
                                    uni.hideLoading();
                                    // console.log(err.errMsg);
                                }
                            })
                        },
                        fail: err => {
                            uni.hideLoading();
                            //console.log(err)
                        }
                    })
                }
            },
            //upload image
            imageUpload() {
                var that = this
                uni.chooseImage({
                    count: 1, //默认9
                    sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
                    sourceType: ['album'], //从相册选择
                    success(res) {
                        uni.showLoading({
                            title: '制作中...',
                            mask: true
                        });
                        let filePath = res.tempFilePaths[0]
                        that.filePath = res.tempFilePaths[0]
                        uniCloud.uploadFile({
                            filePath: filePath,
                            cloudPath: 'imname.jpg',
                            onUploadProgress: function(progressEvent) {
                                console.log(progressEvent);
                                var percentCompleted = Math.round(
                                    (progressEvent.loaded * 100) / progressEvent.total
                                );
                            },
                            success(res) {
                                console.log('上传成功', res.fileID);

                                that.getResult(res.fileID)
                            },
                            fail(err) {
                                console.log(err);
                                uni.hideLoading()
                            },
                            complete() {

                            }
                        });

                    }

                });
            },
            //请求图片制作
            async getResult(e) {
                uniCloud.callFunction({
                        name: 'face-cartoon',
                        data: {
                            Url: e
                        }
                    })
                    .then(res => {
                        uni.hideLoading()
                        //拼接base64
                        this.img_base = "data:image/png;base64," + res.result.ResultImage
                    });
            }
        },

    }
</script>

<style lang="scss">
    .container {
        padding: 20px;
        font-size: 14px;
        line-height: 24px;

        .img_create {
            display: flex;
            justify-content: center;

            img {
                width: 98%;
                border-radius: 15rpx;
                box-shadow: 0rpx 2rpx 2rpx 2rpx rgba(0, 0, 0, 0.3)
            }

            margin-bottom: 50rpx;
        }

        .btn {
            margin-bottom: 50rpx;
            display: flex;
            justify-content: space-around;
        }
    }
</style>

Visual Studio Code 在终端运行 pnpm 你要如何运行这个文件

作者 cyril
2023年12月5日 19:05

2023-12-05T11:03:45.png

2023-12-05T11:04:00.png

在vscode终端中执行npm命令时,不会执行npm命令而是弹窗:“你要如何打开这个文件?”

经测试在cmd中正常执行npm命令,排除npm问题

原因:系统中存在npm文件,执行npm命令时操作的是这个npm文件

解决方案:使用get-command npm命令查询npm命令,查看右侧Source来源并删除此目录下npm文件

如果是pnpm出现同样的问题,那就使用get-command pnpm命令解决问题

VIte 是什么

作者 cyril
2023年12月5日 12:49

Vite 是一个旨在为现代 Web 项目提供更快速、更精简的开发体验的构建工具。
它由两个主要部分组成:一个开发服务器,通过原生 ES 模块提供丰富的功能增强,例如极快的模块热更新(HMR);一个构建命令,使用 Rollup 对您的代码进行打包,预配置以输出高度优化的静态资源以供生产使用。Vite 是一种有见地的工具,具有合理的默认设置。它还通过其插件 API 和 JavaScript API 提供了高度可扩展性,并支持完整的类型支持。
Vite 还支持通过插件实现对框架的支持或与其他工具的集成。您可以通过插件来实现对框架的支持或与其他工具的集成。
Vite 还支持通过插件实现对框架的支持或与其他工具的集成。您可以通过插件来实现对框架的支持或与其他工具的集成。

宝塔开心版8.0.2 / 宝塔面板安装脚本

作者 cyril
2023年11月29日 20:23

2分钟装好面板,一键管理服务器

集成LAMP/LNMP环境安装,网站、FTP、数据库、文件管理、软件安装等功能

开心版仅供学习研究使用,切勿用于正式生产环境

宝塔开心版介绍

· 无需手机登录:不再有手机登录提示,或按照提示输入任意手机号密码即可模拟绑定;
· 安全:剥离了所有与宝塔官方的通信、上报、下发;并且不与本站开心版服务器通信;
· 免费:提升为企业会员,免费使用软件商店中的所有[企业版插件]、[专业版插件]、[运行环境]、[免费插件]、[宝塔插件];部分[第三方应用]安装可能会失败;
· 解决方案:所有功能与原版一致,如有任何问题请参考宝塔官方解决方案;
· 面板修复:开心版不与官方通信,所以无法判断贵站情况,建议使用升级代码修复/或安装宝塔官方版再安装开心版(小概率出现异常,大概率只重装面板不影响网站运行);
· 其他提示:如果发现[软件商店]空白,大多是服务器与你本地的网络问题,请清理本地缓存/切换浏览器的访客模式访问/切换本地代理IP;
· 本站声明:开心版基于官方代码、仅做通信剥离、代码未加密、未添加任何新增代码!
· 友情提示:宝塔开心版绝不存在任何后门、挖矿等消耗CPU等情况,经与众多站长合作排查大概归纳为:建站使用的程序或环境存在漏洞/使用过其他脚本或测速脚本后才安装宝塔开心版/暴露了端口或网站后台等安全因素所致;
· 最新版本的宝塔面板会有赞助链接,仅加入了A链接,没有新增任何其他内容..被墙域名解决方案、LOC也在用的抗投诉服务器、三网双程优化服务器、跳板机系统,均为良心服务,亲身使用确实靠谱,值得推荐!

系统兼容性顺序:

Centos 7.6 > Debian10 > Ubuntu 20.04 > Cenots8.x > Ubuntu 18.04 > 其它系统

提示:Centos官方已宣布在2020年停止对Centos6的维护更新,各大软件开发商也逐渐停止对Centos6的兼容,新服务器不建议使用Centos6;

CentOS 7.6+、Ubuntu18.04+、Debian10.0+,确保是干净的操作系统,没有安装过其它环境安装的Apache/Nginx/php/MySQL/pgsql/gitlab/java 已有环境、网站在运行的不可安装。

Linux宝塔面板安装脚本

使用 SSH 连接工具,如 跳板机 连接到您的 Linux 服务器后,挂载磁盘 ,根据系统执行相应命令开始安装(大约2分钟完成面板安装)。

Centos安装脚本

yum install -y wget && wget -O install.sh http://www.btkaixin.net/install/install_6.0.sh && sh install.sh

Ubuntu/Debian安装脚本

wget -O install.sh http://www.btkaixin.net/install/install_6.0.sh && bash install.sh

一键更新脚本

curl http://www.btkaixin.net/install/update6.sh|bash

安装主控需要的环境及源的网络较为复杂,可能会频繁安装失败,请多次尝试安装(可能需要安装3~7次以上)就能安装成功
安装完成并进入主控端,即可获取被控端的安装脚本
注意:推荐使用Chrome、火狐、edge浏览器,国产浏览器(极速模式)

管理宝塔

安装云安全监控

if [ -f /usr/bin/curl ];then curl -sSO http://www.btkaixin.net/install/install_btmonitor.sh;else wget -O install_btmonitor.sh http://www.btkaixin.net/install/install_btmonitor.sh;fi;bash install_btmonitor.sh

卸载云安全监控
卸载主控

wget http://www.btkaixin.net/install/install_btmonitor.sh && bash install_btmonitor.sh uninstall

卸载Linux被控

wget http://www.btkaixin.net/install/btmonitoragent.sh && bash btmonitoragent.sh uninstall

卸载Windows被控,使用cmd执行命令,删除服务,最后进入C盘手动删除 btmonitoragent 目录

cd C:\btmonitoragent
nssm.exe remove BT-MonitorAgent confirm

命令行工具
主控命令行工具箱
btm
==================云安全监控命令行======================
重启主控服务 2) 查看登录地址及安全入口
停止主控服务 4) 查看运行状态
查看错误日志 6) 修改管理员密码(自动生成随机密码)
关闭basic_auth 8) 修改管理员密码(手动输入密码)
取消域名绑定 10) 修改安全入口(手动输入)
取消IP绑定限制 12) 修改端口(手动输入)
修复主控(检查错误并更新云安全监控到最新版)
无法访问?(云安全监控故障检测自动修复程序-超强力版)
关闭动态口令认证
退出或按组合键[ctrl+c] ======================================================

    请输入对应数字进行命令行操作[0-15]:

查看主控访问地址

btm default

修改主控管理员密码

btm 8

修改主控安全入口

btm 10

修改主控端口

btm 12

修复主控

btm 13

被控命令行
启动被控

btmonitoragent start

停止被控

btmonitoragent stop

查看被控日志

tail -n200 /usr/local/btmonitoragent/logs/logs.log

夏柔API管理系统安装

作者 cyril
2023年11月19日 11:54

准备

体验传送门

API首页
本次安装为服务器安装,宝塔面板
系统:centos
需要提前准备好域名和服务器
GIT地址:https://github.com/050310Y/freeapi.git
可以download下载后上传,也可以直接在服务器git clone
这次才用下载上传部署方法
下载完成后,在宝塔界面添加站点,填入域名,新建数据库,如果没有域名,直接填IP也可以
打开根目录,上传刚刚下载好的源码,上传并解压至根目录

修改 /config/database.php 配置数据库项

导入数据库,访问前台

--------------- 搭建教程 ---------------
1.数据库信息配置在路径【config/database.php】文件中


-- 默认数据库账号密码:apiv_aa1_cn

2.导入根目录下的【data.sql】数据库文件

3.设置网站运行目录为根目录【public】目录

--------------- 网站信息 ---------------
后台地址 /admin/login.html
后台地址
账户 admin 密码 123456

ps:伪静态在public目录下,nginx和apache分别对应文件 nginx.htaccess和.htaccess

对于网络不好的同学,可以直接网盘下载。

资源下载地址:

下载:https://wwvu.lanzouq.com/iiaaE1fauiwh 密码:2ude

推荐一款导航网站源码 花森门户|橘子导航

作者 cyril
2023年11月15日 19:01

在找源码的过程中无意发现,作者人很好,也一直帮忙在解答问题。

尝试了一晚,在宝塔搭建了该项目,大家可以先体验下

如有需要可以添加到书签哦

[button color="primary" icon="" url="http://nav.cyrilstudio.top/" type=""]橘子导航[/button]


花森门户

码云仓库地址:https://gitee.com/HuaSenJioJio/huasenjio-compose

Github 仓库地址:https://github.com/huasenjio/huasenjio-compose

📌 关于

花森系列网站增添新作品,(huasenjio-compose)官方仓库,基于 vue.js、node.js、docker-compose、redis、mongodb、jenkins 组合构建的容器应用。如果我的项目给您带来帮助,请点一个 star(🌟)!您的鼓励和支持,对我真的很重要!

💪 开源列表

✅ 花森门户容器版(huasenjio-compose

✅ 花森门户静态版(huasen-protal

✅ 花森脚手架(huasen-cli

☑️ 花森低代码平台 (预研)

☑️ 花森流程引擎(预研)

🤩 在线体验

由于服务器配置过于垃圾,首次访问较慢,请耐心等待,如果加载卡死,则重新刷新网页。不是代码写得烂,相反我已进行性能优化,并且经过实践验证,服务器配置较好的情况下,访问速度很快!

1.网址导航

2.博客

3.个人引导页

💡 平台简介

花森门户由浏览器主页网址导航博客系统后台管理系统组成,浏览器主页收录资源网站,涵盖了日常生活、娱乐、学习、影视、考研、工作、科技、实用工具等领域。博客系统,定期分享实用教程、计算机知识、资源软件等文章,致力于提供高效上网冲浪环境的公益性平台!

📙 功能清单

官网

✅ 界面响应式适配,不同设备完美呈现;

✅ 数据离线存储,无需登录,畅享所有,支持数据拷贝恢复;

✅ 云端备份,多设备数据同步;

✅ 自定义网站收录,收藏精品站点;

✅ 鼠标右键改色,创建专属皮肤;

✅ 更换皮肤壁纸;

✅ 多引擎搜索框,支持百度热词提示;

✅ 站内链接搜索,支持从名称、描述、备注搜索站点,一键直达网站;

✅ 邮箱登录注册;

✅ 极简模式,干净简洁;

✅ 订阅切换;

✅ 实时天气;

✅ Markdown 文章阅读,支持三级锚点目录;

☑️ ChatGPT;

☑️ 提交链接;

☑️ ...

后台管理

✅ 实时访客统计,记录 PV、UV、IP、反向链接、设备,精准掌控流量(不涉及敏感信息);

✅ 服务器状态监听,记录 CPU、内存、磁盘使用占比;

✅ Markdown 文章发布,支持右键粘贴图片;

✅ 订阅源管理,一键管理订阅源、栏目、网链;

✅ 账户管理,包括用户、管理员、黑名单信息管理;

✅ 图标制作,支持文字、上传、爬取三种方式生成图标;

✅ 日志管理;

✅ 动态脚本执行面板;

✅ 文件管理,支持图片、视频、PDF、文档等文件存储;

✅ 新增图标库选择功能;

✅ 批量删除文件;

✅ 配置管理页面,支持更换品牌名、LOGO、令牌、页脚、邮箱、壁纸等信息;

✅ 路由页面标签化管理,支持页面缓存;

☑️ PDF 在线阅读;

☑️ 提交链接审核;

☑️ ...

后台服务

✅ 自研的并发处理器,轻松抗下 1000 并发;

✅ 多容器一键部署,经典的 MVC 架构;

✅ 黑名单拦截;

✅ 权限管理,支持 jwt 身份校验;

✅ 数据加密传输,支持对称、非对称加密传输;

✅ 邮件发送;

✅ 日志系统;

✅ 定时任务;

✅ Websocket 实时通讯;

✅ 多线程处理;

✅ 文件上传;

✅ 跨域处理;

☑️ 资源防盗链;

☑️ SEO 优化;

☑️ ...

✨ 界面功能预览

快照更新于 2023 年 11 月 11 日

1.响应式适配

amP73Q5ctpU9sf4

2.首页+搜索+右键换肤

bwT5saFxQz2RYon

3.极简模式

xM3tNHzoKils7P5

4.自定义收录

woaujxGCKnWt8PB

5.皮肤主题

Lj3gREk8dnxbIHZ

6.文章展示

W5NyJahVl2pM1mi

7.文章阅读

jnPcSV6ApTkvZdx

8.数据仪表盘

or8l51b9wna7dpE

9.文章发布

lk4BwPiAq7jUxgY

10.栏目管理

Kvn2Fp6ASDylX1P

11.网链管理

JsEeUoIrNZKpXnb

12.文件管理

Z1kPSa5TzofYhes

13.配置页面

wk5ji93VzFNSAlE

🧩 技术架构

前端基于 Vue.js(2.6.x)、ElementUI、Tailwindcss、Axios 等技术开发的 Web 应用,服务端基于 Node.js、Mongodb、Redis、Express 开发的服务框架,使用 Nginx 作为代理服务器转发请求,选择 jenkins 实现 CI/CD,借助 docker 进行一键容器化部署。

PuyTDEVxoYajkOn

🔨 快速部署

2023/07/28 部署方式:

1.常规部署

2.宝塔部署

3.一键脚本部署(推荐)

方式1:常规部署

⚠️ 打开弹幕和查看评论区

视频教程:https://www.bilibili.com/video/BV1G44y1Q7MV

🏁 测试环境

  1. Centos 7.4;
  2. 腾讯云服务器 1 核 2G(学生机);

🏁 安装依赖

一.Git

安装 git 版本管理工具,直接拉取源码到服务器,免去通过 xfpt 上传源码文件的繁琐过程。

(1)安装 wandisco 仓库包

yum install http://opensource.wandisco.com/centos/7/git/x86_64/wandisco-git-release-7-2.noarch.rpm

(2)安装 git 安装包

yum -y install git

(3)验证版本

git version
二.Docker

(1)卸载旧版本

yum remove -y docker \
  docker-client \
  docker-client-latest \
  docker-common \
  docker-latest \
  docker-latest-logrotate \
  docker-logrotate \
  docker-selinux \
  docker-engine-selinux \
  docker-engine

(2)安装依赖工具包

yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2

(3)设置 yum 源

sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum makecache fast

(4)安装 docker

yum install -y docker-ce

(5)启动 docker

systemctl start docker.service

(6)设置开机自启动

systemctl enable docker.service

(7)设置权限

sudo chmod a+rw /var/run/docker.sock

(8)查看版本

命令行执行docker version如下命令,输出有 Client 和 Server 服务,则说明运行正常。

1PzjM5mTcHDUByW

(9)安装 vim 工具

如果系统没有自带 vim 编辑器,则使用如下命令进行安装。

yum -y install vim*

(10)添加镜像源配置文件

默认通过官方镜像源拉取,速度特别,并且容易卡死,所以需要替换镜像源,如果目录下不存在 daemon.json 配置文件,则新建配置文件,执行 vim /etc/docker/daemon.json 命令,输入配置如下:

{
  "registry-mirrors": [
    "https://registry.docker-cn.com",
    "http://hub-mirror.c.163.com",
    "https://docker.mirrors.ustc.edu.cn"
  ],
  "ipv6":false
}

(11)重载配置

⚠️ 不然配置不会生效

执行sudo systemctl daemon-reload命令

(12)重启 docker

⚠️ 不然配置不会生效

执行sudo systemctl restart docker命令

三.Docker-compose

安装 docker-compose 服务,负责对 docker 容器进行集群和快速编排。

(1)下载资源

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

(2)设置权限

sudo chmod +x /usr/local/bin/docker-compose

(3)建立软连接

不建立软连接,可能无法使用 docker-compose 命令。

ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

(4)查看版本

docker-compose --version

🏁 运行容器

通过上一步,我们已经安装好 git、docker、docker-compose 服务,接下来我们拉取源码,直接运行容器。

(1)通过 git 拉取源码

git clone https://github.com/huasenjio/huasenjio-compose.git

(2)进入 huasenjio-compose 目录

cd huasenjio-compose

(3)运行容器

执行运行容器命令后,docker 将自动拉取安装配置 nginx、mongodb、redis、jenkins、后端服务,第一次会比较缓慢,请耐心等待,如果遇到卡死的情况,使用ctrl + c终止命令,然后重复执行运行容器命令即可。

docker-compose up -d

(4)访问站点

容器启动成功之后,我们在浏览器地址栏输入如下地址:

官网:协议://ip/portal/
后台管理:协议://ip/admin/
默认管理员:admin@qq.com/12345

方式2:宝塔部署

⚠️ 打开弹幕和查看评论区

视频教程:https://www.bilibili.com/video/BV1xA411z7QA

🏁 测试环境

  1. Centos 7.4;
  2. 腾讯云服务器 1 核 2G(学生机);
  3. 宝塔面板正式版;

🏁 流程

进入宝塔面板,安装 docker,拉取 git 源码,修改 docker-compose.yml 文件,添加 compose 模版,添加运行项目。如果宝塔面板已安装 nginx,需要修改 docker-compose.yml 配置文件的 nginx 的运行端口,否则端口冲突,无法启动容器。

方式3:一键脚本部署

⚠️ 打开弹幕和查看评论区

视频教程:https://www.bilibili.com/video/BV1gu4y1X7Kf/

🏁 测试环境

  1. Centos 7.4;
  2. 腾讯云服务器 1 核 2G(学生机);

🏁 流程

进入服务器,执行curl -O http://n.huasen.cc/huasen-store/open-sh/install.sh ; chmod +x install.sh ; ./install.sh命令,下载安装脚本并且执行。如果运行失败,重新运行即可。更多操作脚本,请查阅 huasenjio-compose/bin/readme.md 文档。

❓ 常见 QA

(1)按照步骤操作,导航、博客、后台管理网站可以直接访问?

是的,项目采取容器化配置,只要一次安装运行成功,即可访问使用,无需其他繁琐配置。

(2)为什么容器运行失败?

运行容器时,请确保 80、37017、7379、8080、3000、8181 端口不被占用,可以通过netstat -anp | grep 端口号检查端口占用情况,如果不幸已经有服务占用端口,则需要修改docker-compose.yml中对应容器的端口后,重新执行运行容器命令。

(3)运行成功,但是还是无法访问到站点?

如果服务已经正常启动,但是无法访问站点,需要检查一下服务器防火墙和安全组配置,是否限制 80 端口的访问,可以使用端口检测工具,进行检测。

(4)用户注册时,为什么邮箱验证码无法发送?

(4-1)部署前配置

由于邮箱验证码功能依赖 nodemailer 库实现,需要部署之前修改/huasenjio-compose/huasen-server/config.js中的QQ_MAIL配置项,更改成自己的申请邮箱地址和 mtp 通行码。

(4-2)部署后配置(推荐)

进入后台管理,点击状态栏的配置图标,修改 mail 选项,设置正确的 host、port、auth信息。

(5)mongodb 数据库的存储位置?

工程根目录下huasen-mongo/volume文件夹,就是数据库的数据文件夹。

(6)如何删除容器,重新启动容器?

进入 huasenjio-compose 目录,打开终端,通过docker-compose down,停止容器,删除容器。

(7)如何重新构建镜像?

进入 huasenjio-compose 目录,打开终端,通过docker-compose build --no-cache,不使用缓存,重新构建镜像。

(8)如何操作服务器防火墙?

开启防火墙:systemctl start firewalld
关闭防火墙:systemctl stop firewalld
查看防火墙:systemctl status firewalld
查看指定端口:firewall-cmd --query-port=8080/tcp
打开指定端口:firewall-cmd --add-port=8080/tcp --permanent
重载端口数据:firewall-cmd --reload
关闭指定端口:firewall-cmd --permanent --remove-port=8080/tcp

(9)如何配置放开安全组?

因为服务器提供商的应用界面不同,所以省略教程,大家平时使用阿里云、腾讯云、华为云等服务器提供商的服务器,都是可以轻易地百度到安全组的操作教程!

(10)如何升级网站?

(10-1)使用脚本

进入项目根目录,使用 chmod u+x ./bin/* 为脚本设置可执行权限,然后执行 ./bin/upgrade.sh,耐心等待,拉取新代码,升级网站。

(10-2)使用 jenkins

⚠️《📽 视频教程》章节列有视频教程

网站采用 docker-compose 编排容器,一键部署网站的同时,也在 8080 端口安装 jenkins 用于实现 CI/CD ,另外注意 jenkins 会占用大概 20%的内存,如果不使用可以关闭,进入项目根目录,执行 docker-compose stop jenkins,完成停止 jenkins 容器。

(11)如何修改前端界面?

⚠️ 需要 node.js 环境

进入官网的源码路径 /huasenjio-compose/huasen-frontend/portal 的终端,执行 npm install,安装依赖,然后执行 npm run serve 启动项目进行开发,改动代码之后,使用 npm run build 打包代码,构建后的代码输出在 /huasenjio-compose/huasen-server/public/webapp/portal 下,需要拷贝到服务器的对应位置,最后执行 /huasenjio-compose/bin/update.sh 脚本更新网站。

(12)如何修改后台管理界面?

⚠️ 需要 node.js 环境

进入后台管理的源码路径 /huasenjio-compose/huasen-frontend/admin 的终端,执行 npm install,安装依赖,然后执行 npm run serve 启动项目进行开发,改动代码之后,使用 npm run build 打包代码,构建后的代码输出在 /huasenjio-compose/huasen-server/public/webapp/admin 下,需要拷贝到服务器的对应位置,最后执行 /huasenjio-compose/bin/update.sh 脚本更新网站。

(13)如何修改后端服务?

⚠️ 需要 node.js 环境

进入项目根目录 /huasen-compose 项目执行 docker-compose up -d redis mongo 提前开启本地 redis、mongo 服务,然后进入后端服务代码路径 /huasen-compose/huasen-server,执行 npm install,安装依赖,通过 npm run dev 启动后端服务开发,最后拷贝整个/huasen-compose/server 到服务器的对应位置,执行 /huasen-compose/bin/update.sh 脚本更新网站。

(14)如何修改 nginx 的运行端口?

进入项目根目录,打开docker-compose.yml,修改 published 属性,端口号建议选 3000-10000 范围,然后执行 /huasen-compose/bin/update.sh 脚本更新网站。

(15)如何备份迁移网站?

拷贝整个项目文件夹迁移至新服务器,然后执行 /huasen-compose/bin/update.sh 脚本,网站自动完成刷新重启。

(16)显示部署成功之后,我访问网站,老是打开 up 的主页?

遇到重定向到主页的情况,说明网站部署没问题,只是访问的地址不对,根据 http://ip(域名):nginx端口/portal 格式检查一下。截止2023年9月1日后台管理已支持动态配置重定向地址,打开系统配置页面,设置重定向链接。

📽 视频教程

(1)通过 docker-compose 安装教程

https://www.bilibili.com/video/BV1G44y1Q7MV

(2)通过宝塔面板安装教程

https://www.bilibili.com/video/BV1xA411z7QA

(3)自动化部署教程

⚠️ 视频中的示例脚本已过时,以文档内提供的 shell 脚本为准!

https://www.bilibili.com/video/BV1vg4y1E7xy

(3-1)构建完成后执行的 shell 脚本

⚠️ 注意确保路径正确
# 设置权限
chmod u+x ./bin/*
# 执行脚本
./bin/upgrade-jenkins-init.sh

(3-2)远程执行的 shell 脚本

⚠️ 注意确保路径正确
# 设置权限
chmod u+x /root/huasen-compose/huasen-jenkins-cache/bin/*
# 执行脚本
/root/huasen-compose/huasen-jenkins-cache/bin/upgrade-jenkins.sh

🐛 开发者指南

⚠️ 以下内容适合有编程基础的小伙伴观看

目录结构

├── bin                                    // 快捷操作脚本
├── huasen-mongo                 // mongodb 数据库配置和数据
├── huasen-nginx                 // nginx 配置
├── huasen-redis                 // redis 配置和数据
└── huasen-server                // 后端服务
  ├── app.js                     // 服务入口文件
  ├── setting.json            // 网站配置文件
  └── config.js               // 服务配置文件
├── huasen-store           // 静态文件仓库
├── huasen-jenkins         // jenkins 配置
├── docker-compose.yml     // docker-compose 配置文件
└── huasen-frontend        // 界面源码
  ├── admin                          // 后台管理界面源码
  ├── portal                         // 前台站点源码
  └── guide                          // 个人引导页源码

本地启动调试

一.官网

⚠️ 进入/huasenjio-compose/huasen-frontend/portal 目录下执行命令

(1)安装依赖

npm install

(2)运行程序

npm run serve

(3)打包构建

npm run build

二.后台管理

⚠️ 进入/huasenjio-compose/huasen-frontend/admin 目录下执行命令

(1)安装依赖

npm install

(2)运行程序

npm run serve

(3)打包构建

npm run build

三.后台服务

⚠️ 进入/huasenjio-compose/huasen-server 目录下执行命令

(1)安装依赖

npm install

(2)运行程序

进入项目根目录执行 docker-compose up -d redis mongo 提前开启本地 redis、mongo 服务

npm run dev

❌ 声明

仅供学习参考,未经授权,禁止商业使用!

🥳 联系我们

由于涉及知识面较广,无法使用文字全面讲解,可以关注我的 Bilibili 账号,后续更新视频教程,感兴趣的小伙伴可以添加站长微信 ,进入技术交流群!

🐧 企鹅 QQ:184820911

😸 微信 :huasencc(站长邀请进入交流群)

📮 邮箱 :184820911@qq.com

📺 bilibili:花森酱

❤️ 支持

如果项目帮助到大家,可以为我的 bilibili 视频,送上免费的点赞和硬币。另外,阔绰的小伙伴可以请我喝一杯蜜雪冰城🥤~

vM5uLVcEabZeoJF

Docker笔记 Docker安装使用教程

作者 cyril
2023年11月14日 14:23

Docker 是什么?
Docker 是一个开源的容器引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者和系统管理员在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括 VMs(虚拟机)、bare metal、OpenStack 集群、云端、数据中心和其他的基础应用平台。容器是完全使用沙箱机制,相互之间不会有任何接口。
为啥要用Docker?
为啥要用Docker?这要从目前软件行业的痛点来讲起
• 1、软件更新发布及部署低效,过程繁琐且需要人工介入
• 2、环境一致性难以保证
• 3、不同环境之间迁移成本太高
有了Docker可以很大程度解决上面的问题。
首先,Docker的使用简单至极,从开发的角度来看就是三步走:构建,运输,运行。其中关键步骤就是构建环节,即打包镜像文件。但是从测试和运维的角度来看,那就只有两步:复制,运行。有了这个镜像,那么想复制到哪运行都可以,完全和平台无关了。同时Docker这种容器技术隔离出了独立的运行空间,不会和其他应用争用系统资源了以及还不需要考虑应用之间相互影响,想想就开心。
其次,因为在构建镜像的时候就处理完了服务程序对于系统的所有依赖,所以在你使用的时候,你可以忽略掉原本程序的依赖以及开发语言。对测试和运维而言,更多专注于自己的业务内容上。
最后,Docker于开发者而言提供了一种开发环境的管理办法,与测试人员而言保证了环境的同步,于运维人员提供了可移植的标准化部署流程。
Docker 能干啥?
• 构建容易分发简单
• 隔离应用解除依赖
• 快速部署测完就销
Docker的应用场景在哪??

  1. 本地依赖(Local Dependency)
    你需要在本地系统快速尝试 Magento,或者为一个项目使用 MySQL?还是希望尝试大部分开源项目?那就使用 Docker 吧,它将帮你节省大量时间。Docker 能提升开发者的开发效率,让我们快速搭建开发环境。
    开发环境的机器通常内存比较小,此前使用虚拟的时候,经常需要为开发环境的机器加内存,而通过 Docker 可以轻易的让几十个服务在 Docker 中跑起来。
  2. 搭建环境(Build Environment)
    如果你希望构建源码,但发现没有准备好合适的环境。
    那么使用 Docker是一个值得考虑的方案。毕竟如果使用传统的方法一个一个地安装软件,一大堆软件安装下来确实十分费时间,使用容器技术省时省力,何乐而不为?它能让你将运行环境和配置放在代码中然后部署,同一个 Docker 的配置可以在不同的环境中使用,这样就降低了硬件要求和应用环境之间耦合度。这里有一个值得一看的例子: docker golang builder。
  3. 微服务(Microservices)
    你在使用微服务吗?微服务架构将一个整体式的应用拆分成松耦合的单个服务。
    那不妨考虑一下 Docker,你可以将每个服务打包为一个docker镜像并使用docker-compose 来模拟生产环境(checkout docker networks)。最开始实践的时候可能会比较费时费力,但长远地来看,最终将产生巨大的生产力。
  4. 自动测试(Automated testing)
    试想这样一个问题,如何编写自动化的集成测试用例,这些测试用例无需花很长时间来开始运行,使用者也可轻松管理。这里不是指在 Docker 中运行测试用例,而是将测试用例与镜像紧密运行在一起。当你针对一个 docker 镜像编写测试用例时会有一个很大的优势。下面简单介绍一下我的测试流程:运行两个 docker 镜像(app + db),在 MySQL 启动时加载数据,并在 app docker 上使用 API。可查看此脚本以获取快速的示例。
  5. 部署过程(Deployment process)
    你可以使用 docker 镜像进行自我部署。许多主流的主机提供商都支持托管 docker,如果你拥有一个具有 shell 访问权限的专用节点/vm,那么事情将变得更容易。只需要设置好docker,并在你想要的端口上运行你的镜像即可。
  6. 持续部署(Continuous Deployment)
    都说 Docker 天生适合持续集成/持续部署,在部署中使用Docker,持续部署将变得非常简单,并会在进入新的镜像后重新开始。关于这个部分的自动化工作,现在已经有许多方案以供选择,Kubernetes就是一个耳熟能详的名字。Kubernetes是容器集群管理系统,是一个开源的平台,可以实现容器集群的自动化部署、自动扩缩容、维护等功能。
  7. 多租户环境(Multi-tenancy)
    Docker 有意思的一个使用场景是在多租户的应用中,它可以避免关键应用的重写。如果你将应用程序服务公开给多个租户(租户指一组用户,例如组织),使用单租户方案设计的应用程序如果用上了 sub-domain + docker 可以快速获得提供多租户的服务。
    关于这个场景的一个例子是为物联网的应用开发一个快速、易用的多租户环境。这种多租户的基本代码非常复杂,很难处理,重新规划这样一个应用不但消耗时间,也浪费金钱。使用Docker,可以为每一个租户的应用层的多个实例创建隔离的环境,这不仅简单而且成本低廉,当然这一切得益于 Docker 环境的启动速度和其高效的 diff 命令。
  8. 来自一台机器的多个 APP(Multiple apps from one machine)
    这与上面提到的微服务有些联系,但即使你没有使用微服务,只是提供服务,Docker仍可以很好地管理单个机器上的所有服务。你应该使用文件夹挂载来为每个基于数据的 docker 镜像保留数据。
  9. 扩容 QPS(Scaling QPS)
    Docker 通过创建另一个容器来帮助你轻松地进行水平扩展。如果遇到巨大的高峰流量,Docker可以帮助你解决问题 —— 只需添加更多的机器并增加负载均衡器背后运行的容器数量。
    想全面了解的朋友可以参考:太全了|万字详解Docker架构原理、功能及使用
    Docker与Openstack对比

Docker 生态概览
Docker安装
root@centos7 ~]# yum install docker -y
[root@centos7 ~]# systemctl start docker
下载镜像文件
[root@centos7 ~]# docker pull centos:latest
Trying to pull repository docker.io/library/centos ...
centos7: Pulling from docker.io/library/centos
93857f76ae30: Pull complete
Digest: sha256:4eda692c08e0a065ae91d74e82fff4af3da307b4341ad61fa61771cc4659af60
[root@centos7 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/centos centos7 a8493f5f50ff 3 days ago 192.5 MB
删除镜像
[root@centos7 ~]# docker rmi a8493f5f50ff ##容器ID
Docker容器创建与管理
1)创建容器
方法一:
[root@centos7 ~]# docker run centos /bin/echo "nihao" ##创建容器
nihao
[root@centos7 ~]# docker ps -a ##查看所有容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3c113f9a4f1b centos "/bin/echo nihao" 43 seconds ago Exited (0) 41 seconds ago boring_liskov
这里没有指定容器名称,自动命名,状态是自动退出
方法二:创建一个自定义名称的容器
[root@centos7 ~]# docker run --name mgg -t -i centos /bin/bash
名称 分配伪终端 -i 处于打开状态
[root@2db7f1389dbd /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 22:46 ? 00:00:00 /bin/bash
root 13 1 0 22:49 ? 00:00:00 ps -ef
[root@centos7 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2db7f1389dbd centos "/bin/bash" 4 minutes ago Up 4 minutes mgg
docker ps -a是显示所有容器包括没有运行的(同virsh list --all)
2)进入、退出、启动容器
[root@2db7f1389dbd /]# exit ##退出容器
exit
[root@centos7 ~]# docker start 2db7f1389dbd ##启动容器
2db7f1389dbd
[root@centos7 ~]# docker attach 2db7f1389dbd ##进入容器(必须是启动状态下)
[root@2db7f1389dbd /]# hostname
2db7f1389dbd
这种进入方式,退出后容器就进入Down状态,如下
[root@2db7f1389dbd /]# exit
exit
[root@centos7 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3)使用nsenter命令进入容器
[root@centos7 ~]# nsenter --help
Usage:
nsenter [options] [...]
Run a program with namespaces of other processes.
Options:
-t, --target target process to get namespaces from
-m, --mount[=] enter mount namespace
-u, --uts[=] enter UTS namespace (hostname etc)
-i, --ipc[=] enter System V IPC namespace
-n, --net[=] enter network namespace
-p, --pid[=] enter pid namespace
-U, --user[=] enter user namespace
-S, --setuid set uid in entered namespace
-G, --setgid set gid in entered namespace
--preserve-credentials do not touch uids or gids
-r, --root[=

] set the root directory
-w, --wd[=] set the working directory
-F, --no-fork do not fork before exec'ing
-Z, --follow-context set SELinux context according to --target PID
-h, --help display this help and exit
-V, --version output version information and exit
获取容器的PID
[root@centos7 ~]# docker inspect --format "{{.State.Pid}}" 2db7f1389dbd
4580
[root@centos7 ~]# nsenter -t 4580 -u -i -n -p
[root@2db7f1389dbd ~]# hostname
2db7f1389dbd
[root@2db7f1389dbd ~]# exit
logout
[root@centos7 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2db7f1389dbd centos "/bin/bash" 22 minutes ago Up 7 minutes mgg
4)删除容器
[root@centos7 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2db7f1389dbd centos "/bin/bash" 31 minutes ago Up 16 minutes mgg
3c113f9a4f1b centos "/bin/echo nihao" 38 minutes ago Exited (0) 38 minutes ago boring_liskov
[root@centos7 ~]# docker rm 3c113f9a4f1b ##接名称也可以,删除一个停止的容器
3c113f9a4f1b
[root@centos7 ~]# docker rm -f 3c113f9a4f1b ##删除一个正在运行的容器
[root@centos7 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2db7f1389dbd centos "/bin/bash" 31 minutes ago Up 16 minutes mgg
[root@centos7 ~]# docker run --rm centos /bin/echo "hello" ##创建时自动删除,用于测试
[root@centos7 ~]#docker --kill $(docker ps -a -q) ##删除正在运行的容器
Docker网络模式
Dokcer 通过使用 Linux 桥接提供容器之间的通信,Docker的网络模式有四种
分别是以下四种模式:
• host 模式,使用--net=host 指定。
• container 模式,使用--net=container:NAMEorID 指定。
• none 模式,使用--net=none 指定。
• bridge 模式,使用--net=bridge 指定,默认配置
• host 模式
如果容器使用 host 模式,那么容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡与配置 IP 等,而是使用宿主机的 IP 和端口。就和直接跑在宿主机中一样。但是容器的文件系统、进程列表等还是和宿主机隔离的。
• container 模式
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡与配置 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他方面仍然是隔离的。
• none模式
此模式不同于前两种,Docker 容器有自己的 Network Namespace,但是,Docker容器没有任何网络配置。而是需要我们手动给 Docker容器添加网卡、配置 IP 等。
• bridge 模式
此模式是Docker默认的网络设置,此模式会为每一个容器分配Network Namespace,并将一个主机上的Docker容器连接到一个虚拟网桥上。
更多关于Docker容器网络介绍请参考:Docker容器网络-基础篇,Docker容器网络-实现篇。
Docker数据存储
docker管理数据的方式有两种:
• 数据卷
• 数据卷容器
默认容器的数据是保存在容器的可读写层,当容器被删除时其上的数据也会丢失,所以为了实现数据的持久性则需要选择一种数据持久技术来保存数据。官方提供了三种存储方式:Volumes、Bind mounts和tmpfs。
数据存储方式
从现在开始,我们学习 Docker 容器的数据存储方式,你也可以先了解一下Docker 数据持久化的三种方案。
Bind mount 会覆盖容器中的文件,而 volume mount 则不会。即如果容器中已有文件,则会将文件同步到主机的目录上。此方式与 Linux 系统的 mount 方式很相似,即是会覆盖容器内已存在的目录或文件,但并不会改变容器内原有的文件,当 umount 后容器内原有的文件就会还原。

数据卷(Volumes)
• 由docker创建和管理,且与主机的核心功能隔离
• 无论是命名还是匿名数据卷,都存储在/var/lib/docker/volumes/下面
• 定义的数据卷可以在多个容器中同时使用,且不会自动删除
• 允许容器将内容保存到远端、云服务提供商、加密内容等等
挂在主机目录(Bind mounts)
• 与数据卷相比,挂在主机目录具有有限的功能
• 应用的文件或者目录事先不需要存在,用时会自动创建
• 该方式允许访问容器的敏感文件,可能会产生安全隐患
内存映射(tmpfs)
• 仅存储在容器的内存中,永远不会写入文件系统
• swarm服务使用tmpfs挂载将敏感信息挂载到容器中
数据卷 - volumes
数据卷是存储在 Docker 容器的特定目录下面
优势说明
Docker Volumes 机制通常用来给 Docker 容器保存持久化数据,使用 Volumes 有很多优势:
• 更容易进行备份和数据迁移
• 使用 Docker CLI 命令或者 Docker API 来管理
• 可以在 Linux 和 Windows 操作系统上使用
• 可以更安全得在多个容器中共享
• Volume drivers 允许容器将内容保存到远端、云服务提供商、加密 volume 内容
• 新 Volume 的内容可以被容器预先填充
Volumes 通常也优于容器的可写层,使用 Volumes 不会增加容器的体积,并且 Volumes 的内容存储在外部独立于容器的生命周期。如果容器不产生持久化数据,可以考虑使用 tmpfs 内存映射(只保存在容器的内存中)的方式来避免数据存储在其他可能的地方,避免增加容器的体积。
使用说明
最开始的时候 -v 或者 --volume 选项是给单独容器使用,而 --mount 选项是给集群服务使用。但是从 Docker 17.06 开始,也可以在单独容器上使用 --mount。通常来讲 --mount 选项也更加具体和详细。-v 选项将所有选项集中到一个值,而 --mount 选项将可选项分开。如果需要指定 volume driver 选项,那么必须使用 --mount 选项。

创建一个数据卷

$ docker volume create my-vol

查看所有的数据卷

$ docker volume ls

查看指定数据卷的信息

$ docker volume inspect my-vol
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]

移除指定数据卷的

$ docker volume rm my-vol

清除无主的数据卷

$ docker volume prune

启动一个挂载数据卷的容器

$ docker run -d -P --name web \
-v my-vol:/wepapp \
training/webapp python app.py

$ docker run -d -P --name web \
--mount source=my-vol,target=/webapp \
training/webapp python app.py

启动一个挂载数据卷的服务

$ docker service create -d --name devtest-service \
--mount source=myvol2,target=/app \
nginx:latest

挂载为只读模式

$ docker run -d --name=nginxtest \
-v nginx-vol:/usr/share/nginx/html:ro \
nginx:latest

type 可以分为 bind、volume、tmpfs, 默认为 volume

source 用于设置数据卷的名称,匿名数据卷可以省略

target 表示需要挂载到容器里面的地方

readonly 表示挂载的内容为只读模式,可选

volume-opt 表示可以使用多次,可选

$ docker run -d --name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \
nginx:latest
[3] 挂载远程数据卷

插件 sshfs 允许您轻松地在容器中挂载远程文件夹

下载该插件

$ docker plugin install --grant-all-permissions vieux/sshfs

使用该驱动创建 ssh 数据卷

$ docker volume create --driver vieux/sshfs \
-o sshcmd=test@node2:/home/test \
-o password=testpassword \
-o port=3336 \
sshvolume

启动该驱动程序创建卷创建容器

如果两个容器配置了可信关系,就不需要设置 volume-opt 密码了

$ docker run -d \
--name sshfs-container \
--volume-driver vieux/sshfs \
--mount src=sshvolume,target=/app, \
volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \
nginx:latest

挂载主机目录 - bind mounts
挂载主机目录是将主机中的特定目录直接挂在到容器内部使用
使用说明

使用bind模式启动容器

$ docker run -d -it --name devtest \
-v "$(pwd)"/target:/app \
nginx:latest
$ docker run -d -it --name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app \
nginx:latest

看下对应的信息

$ docker inspect devtest
"Mounts": [
{
"Type": "bind",
"Source": "/tmp/source/target",
"Destination": "/app",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
]

挂载为只读模式

$ docker run -d -it --name devtest \
-v "$(pwd)"/target:/app:ro \
nginx:latest
$ docker run -d -it --name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app,readonly \
nginx:latest
特殊属性

$ docker run -d -it --name devtest \
-v "$(pwd)"/target:/app \
-v "$(pwd)"/target:/app2:ro,rslave \
nginx:latest
$ docker run -d -it --name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app \
--mount type=bind,source="$(pwd)"/target,target=/app2,readonly,bind-propagation=rslave \
nginx:latest
内存映射 - tmpfs
内存映射是将内存映射到容器内供容器内部使用
优势说明
最开始 --tmpfs 是给单独容器使用,而 --mount 选项是给 swarm 集群服务使用的。但是,从 Docker 17.06 开始,也可以在单独容器上使用 --mount 了。通常说来,--mount 更明确,更冗长。最大的区别是 --tmpfs 标志不支持任何可配置选项。其中 --tmpfs 只能在容器中使用,而 swarm 集群则必须使用 --mount 来使用 tmpfs 内存映射。
使用说明

容器上使用

$ docker run -d -it --name tmptest \
--tmpfs /app \
nginx:latest
$ docker run -d -it --name tmptest \
--mount type=tmpfs,destination=/app \
nginx:latest
日志驱动 - logs
在容器外部查看容器内部的日志输出情况,便于排除和监控问题
可以利用 docker logs 命令,查看 Docker 容器内部应用程序运行时所产生的日志。可以免除首先进入 Docker 容器,再打开应用程序的日志文件的过程。docker logs 会监控容器中操作系统的标准输出设备(STDOUT),一旦 STDOUT 有数据产生,就会将这些数据传输到另一个设备中,则被称为日志驱动(Logging Driver)。

动态查看日志内容

$ docker logs -f netdata
Docker 是怎样做到的呢?我们使用 docker info 命令,可以看到 Docker 容器的相关信息,其中有一项 Logging Driver 的字段。

当前所设置的日志驱动类型

$ docker info | grep 'Logging Driver'
Logging Driver: json-file

我们可以在 docker run 命令中通过 --log-driver 参数来设置具体的 Docker 日志驱动,也可以通过 --log-opt 参数来指定对应日志驱动的相关选项。
docker run -d -p 80:80 --name nginx \
--log-driver json-file \ # 设置日志驱动
--log-opt max-size=10m \ # 表示 JSON 文件最大为10MB,超过则生成新的文件
--log-opt max-file=3 \ # 表示 JSON 文件最多保存3个,超过则删除多余文件
nginx

当然,可以在配置文件中添加,全局生效

$ cat /etc/docker/daemon.json
{
"log-driver": "syslog"
}

修改配置之后重启服务

$ sudo systemctl restart docker
额外,需要注意的是,默认情况下,Docker 将日志存储到一个日志文件。

检查日志文件路径

$ docker inspect --format='{{.LogPath}}' netdata
/var/lib/docker/containers/556553bcb5xxx13cbc588a4-json.log

查看实时日志信息

$ tail -f docker inspect --format='{{.LogPath}}' netdata
上述内容参考: https://escapelife.github.io/...
Docker Command 介绍
安装完成 docker 容器服务之后,需要了解如何操作它?在 shell 命令行下直接输入 docker 就可以查看帮助信息,如下。
[root@master ~]# docker
Usage: docker COMMAND
A self-sufficient runtime for containers
Options:
--config string Location of client config files (default "/root/.docker") -D, --debug Enable debug mode
--help Print usage -H, --host list Daemon socket(s) to connect to (default []) -l, --log-level string Set the logging level ("debug", "info", "warn", "error", "fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/root/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit
Management Commands:
container Manage containers
image Manage images
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
secret Manage Docker secrets
service Manage services
stack Manage Docker stacks
swarm Manage Swarm
system Manage Docker
volume Manage volumes
Commands:
attach Attach to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container's filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes
命令很多,重点介绍这 20 个,请详细阅读下面的文章:
这 20 个 Docker Command,有几个是你会的?
Docker file
Docker file 简单介绍
Docker 可以使用 Dockerfile 的内容来自动构建镜像。Dockerfile 也是一个文件,其中有创建镜像、运行指令等一系列的命令,且每行只支持一个运行命令。
Docker file 分为四部分组成:
• 基础镜像信
• 维护者信息
• 镜像操作指令
• 容器启动时执行指令
dockerfile 指令忽略大小写,建议大写,#作为注释,每行只支持一条指令,指令可以带多个参数。
dockerfile 指令有:
• 构建指令:用于构建 image,其指定的操作不会在运行 image 的容器中执行。
• 设置指令:用于设置 image 的属性,其指定的操作会在运行 image 的容器中执行。
Dockerfile 指令
Dockerfile 指令一共有以下种:
• 1、FROM
用来指定基础镜像,然后通过在基础镜像上构建新的镜像,基础镜像一般有远程或本地仓库。并且 Dockerfile 文件第一行必须的 FROM 指令,如果一个 Dockerfile 需要创建多个镜像,可以使用多个 FROM 指令。

具体使用用法如下:

FROM < image_name > #默认是 latest 版本
FROM <image:version> #指定版本
• 2、MAINTAINER
指定镜像的创建者信息

具体使用法如下:

MAINTAINER < name >
• 3、RUN
运行所有基础镜像能支持的命令,同样也可以使用多条 RUN 指令,可以使用\来换行

具体使用法如下:

RUN < command >
RUN ["executable", "param1", "param2" ... ] (exec form)
• 4、CMD
用于容器启动时的指定操作,它可以是命令,也可以是脚本,但只执行一次,如果有多少默认只会执行最后一个。

具体使用法如下:

CMD [“executable” ,”Param1”, “param2”]使用exec执行,推荐
CMD command param1 param2,在/bin/sh 上执行
CMD [“Param1”, “param2”] 提供给 ENTRYPOINT 做默认参数。
• 5、EXPOSE
指定容器的端口映射(容器与物理机),运行容器时加上-p 参数指定 EXPOSE 设置的端口。EXPOSE 可以设置多个端口号,相应地运行容器配套多次使用-p 参数。可以通过 docker port +容器需要映射的端口号和容器 ID 来参考宿主机的映射端口。

具体使用法如下:

EXPOSE [port1 , port2 ............]
• 6、ENV
在镜像中用于设置环境变量的,然后 RUN 命令可以使用此设置的环境变量,在容器启动后也以通过 docker inspect 查看环境变量,可以通过 docker run --env key=value 来设置或修改环境变量。

具体使用法如下:

ENV
ENV JAVA_HOME /usr/local/jdk
• 7、ADD
复制指定的源文件、目录、URL 到容器的指定目录中。所有拷贝到 container 中的文件和文件夹权限为 0755,uid 和 gid 为 0。
如果源是一个目录,那么会将该目录下的所有文件添加到 container 中,不包括目录;
如果源文件是可识别的压缩格式,则 docker 会帮忙解压缩(注意压缩格式);
如果源是文件且目标目录中不使用斜杠结束,则会将目标目录视为文件,源的内容会写入目标目录;
如果源是文件且目标目录中使用斜杠结束,则会源文件拷贝到目标目录下。

具体使用法如下:

ADD <源> <目标>
• 8、COPY
复制本地主机的源(默认为 Dockerfile 所在的目录)到容器中的目标中,目标路径不存在时会自动创建。

具体使用法如下:

COPY <源> <目标>
COPY web/index.html /var/web/
• 路径必须是绝对路径,如果不存在,会自动创建对应目录
• 路径必须是 Dockerfile 所在路径的相对路径
• 如果是一个目录,只会复制目录下的内容,而目录本身则不会被复制
• 9、ENTRYPOINT
指定容器启动后执行的命令,多行只执行最后一行。并且不可被 docker run 提供的参数覆盖。

具体使用法如下:

ENTRYPOINT "command" "param1" "param2"
• 10、VOLUME
创建一个可以从本地主机或其它容器挂载的挂载点,一般用于存放数据。与 docker run -v 也可以实现此功能。

具体使用法如下:

VOLUME [directory_name]
VOLUME /docker_data
• 11、USER
指定容器运行时使用的用户或 UID,后面 RUN、CMD、ENTRYPIONT 都会使用此用户来运行命令。

具体使用法如下:

USER [username/uid]
• 12、WORKDIR
指定 RUN、CMD、ENTRYPIONT 指定的命令的运行目录。可以使用多个 WORKDIR 指令,后续参数如果是相对路径,则会基于之前的命令指定的路径。如:WORKDIR /data   WORKDIR work。最终的路径就是/data/work。path 路径也可以是环境变量。

具体使用方法如下:

WORKDIR [path]
• 13、ONBUILD
配置当前所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。就是,这个镜像创建后,如果其它镜像以这个镜像为基础,会先执行这个镜像的 ONBUILD 命令。

具体使用法如下:

ONBUILD [INSTRUCTION]
通过 Dockerfile 快速构建镜像
接下来,我们通过构建一个 Tomcat 镜像,来演示 Dockerfile 的使用方法,前提是安装 Docker 环境,如何安装 Docker 环境就不在此赘述了。请猛戳下面的文字:
[root@master tomcat]# ll
总用量 190504
-rw-r--r-- 1 root root 9552281 6月 7 15:07 apache-tomcat-8.5.31.tar.gz
-rw-r--r-- 1 root root 32 7月 3 09:41 index.jsp
-rw-r--r-- 1 root root 185515842 9月 20 2017 jdk-8u144-linux-x64.tar.gz
[root@master tomcat]# cat index.jsp
welcome to mingongge's web site
[root@master tomcat]# pwd
/root/docker/tomcat
[root@master tomcat]# vim Dockerfile

config file start

FROM centos
MAINTAINER mingongge <微信公众号:民工哥技术之路>

add jdk and tomcat software

ADD jdk-8u144-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-8.5.31.tar.gz /usr/local/
ADD index.jsp /usr/local/apache-tomcat-8.5.31/webapps/ROOT/

config java and tomcat ENV

ENV JAVA_HOME /usr/local/jdk1.8.0\_144
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.31/
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin

config listen port of tomcat

EXPOSE 8080

config startup command of tomcat

CMD /usr/local/apache-tomcat-8.5.31/bin/catalina.sh run

end of config-file

构建过程
[root@master tomcat]# docker build -t tomcat-web . #这个.不用注释了吧相信懂的人自然懂的
Sending build context to Docker daemon 195.1 MB
Step 1/11 : FROM centos
---> 49f7960eb7e4
Step 2/11 : MAINTAINER mingongge <微信公众号:民工哥技术之路>
---> Running in afac1e218299
---> a404621fac22
Removing intermediate container afac1e218299
Step 3/11 : ADD jdk-8u144-linux-x64.tar.gz /usr/local/
---> 4e22dafc2f76
Removing intermediate container b1b23c6f202a
Step 4/11 : ADD apache-tomcat-8.5.31.tar.gz /usr/local/
---> 1efe59301d59
Removing intermediate container aa78d5441a0a
Step 5/11 : ADD index.jsp /usr/local/apache-tomcat-8.5.31/webapps/ROOT/
---> f09236522370
Removing intermediate container eb54e6eb963a
Step 6/11 : ENV JAVA_HOME /usr/local/jdk1.8.0\_144
---> Running in 3aa91b03d2d1
---> b497c5482fe0
Removing intermediate container 3aa91b03d2d1
Step 7/11 : ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
---> Running in f2649b5069be
---> 9cedb218a8df
Removing intermediate container f2649b5069be
Step 8/11 : ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.31/
---> Running in 39ef620232d9
---> ccab256164fe
Removing intermediate container 39ef620232d9
Step 9/11 : ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
---> Running in a58944d03d4a
---> f57de761a759
Removing intermediate container a58944d03d4a
Step 10/11 : EXPOSE 8080
---> Running in 30681437d265
---> b906dcc26584
Removing intermediate container 30681437d265
Step 11/11 : CMD /usr/local/apache-tomcat-8.5.31/bin/catalina.sh run
---> Running in 437790cc642a
---> 95204158ee68
Removing intermediate container 437790cc642a
Successfully built 95204158ee68
通过构建的镜像启动容器
[root@master tomcat]# docker run -d -p 8080:8080 tomcat-web
b5b65bee5aedea2f48edb276c543c15c913166bf489088678c5a44fe9769ef45
[root@master tomcat]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b5b65bee5aed tomcat-web "/bin/sh -c '/usr/..." 5 seconds ago Up 4 seconds 0.0.0.0:8080->8080/tcp vigilant_heisenberg
访问容器
浏览器输入http://server-ip:8080, 结果如下:

Docker三剑客
容器技术|Docker三剑客之Compose
容器技术|Docker三剑客之docker-machine
打造高逼格、可视化的Docker容器监控系统平台
私有镜像仓库搭建
当我们执行docker pull xxx的时候,docker默认是从registry.docker.com这个地址上去查找我们所需要的镜像文件,然后执行下载操作。这类的镜像仓库就是docker默认的公共仓库,所有人都可以直接查看或下载、使用,但是呢,基于网络原因,下载速度有限制比较慢。因此,我们在公司内部内网环境中使用dokcer,一般不会将镜像文件上传到公网公共库中。但内部共享使用就是个问题,所以,私有仓库就由此产生了。
什么是私有仓库?
私有仓库,就是本地(内网环境)组建的一个与公网公共库功能相似的镜像仓库。组建好之后,我们就可以将打包好的镜像提交到私有仓库中,这样内网其它用户也可以使用这个镜像文件。
本文使用官方提供的registry镜像来组建企业内网的私有镜像仓库
环境介绍
两台安装好docker环境的主机
• 服务端:192.168.3.82 私有仓库服务器在,运行registry容器
• 客户端:192.168.3.83 测试客户端,用于上传、下载镜像文件
安装布署过程
下载官方registry镜像文件
[root@master ~]# docker pull registry
Using default tag: latest
Trying to pull repository docker.io/library/registry ...
latest: Pulling from docker.io/library/registry
81033e7c1d6a: Pull complete
b235084c2315: Pull complete
c692f3a6894b: Pull complete
ba2177f3a70e: Pull complete
a8d793620947: Pull complete
Digest: sha256:672d519d7fd7bbc7a448d17956ebeefe225d5eb27509d8dc5ce67ecb4a0bce54
Status: Downloaded newer image for docker.io/registry:latest
[root@master ~]# docker images |grep registry
docker.io/registry latest d1fd7d86a825 5 months ago 33.3 MB
运行registry容器
[root@master ~]# mkdir /docker/registry -p
[root@master ~]# docker run -itd -v /docker/registry/:/docker/registry -p 5000:5000 --restart=always --name registry registry:latest
26d0b91a267f684f9da68f01d869b31dbc037ee6e7bf255d8fb435a22b857a0e
[root@master ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
26d0b91a267f registry:latest "/entrypoint.sh /e..." 4 seconds ago Up 3 seconds 0.0.0.0:5000->5000/tcp registry
参数说明
1)-itd:在容器中打开一个伪终端进行交互操作,并在后台运行;
2)-v:把宿主机的/docker/registry目录绑定到容器/docker/registry目录(这个目录是registry容器中存放镜像文件的目录),来实现数据的持久化;
3)-p:映射端口;访问宿主机的5000端口就访问到registry容器的服务了;
4)--restart=always:这是重启的策略,假如这个容器异常退出会自动重启容器;
5)--name registry:创建容器命名为registry,可自定义任何名称;
6)registry:latest:这个是刚才pull下来的镜像;
查看远程仓库镜像文件
[root@master ~]# curl http://localhost:5000/v2/_catalog
{"repositories":[]}
同样也可以使用浏览器访问http://server-ip:5000/v2/_cat... 结果相同,都是空的没有任何文件。
客户端操作
修改下载的镜像源
[root@slave1 ~]# vim /etc/docker/daemon.json
{
"registry-mirrors":["https://registry.docker-cn.com"]
}
[root@slave1 ~]# systemctl restart docker
下载测试镜像
[root@slave1 ~]# docker pull nginx
Using default tag: latest
Trying to pull repository docker.io/library/nginx ...
latest: Pulling from docker.io/library/nginx
683abbb4ea60: Pull complete
6ff57cbc007a: Pull complete
162f7aebbf40: Pull complete
Digest: sha256:636dd2749d9a363e5b57557672a9ebc7c6d041c88d9aef184308d7434296feea
Status: Downloaded newer image for docker.io/nginx:latest
给镜像打TAG
[root@slave1 ~]# docker tag nginx:latest 192.168.3.82:5000/nginx:v1
[root@slave1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.3.82:5000/nginx v1 649dcb69b782 8 hours ago 109 MB
docker.io/nginx latest 649dcb69b782 8 hours ago 109 MB
上传镜像
[root@slave1 ~]# docker push 192.168.3.82:5000/nginx:v1
The push refers to a repository [192.168.3.82:5000/nginx]
Get https://192.168.3.82:5000/v1/_ping: http: server gave HTTP response to HTTPS client

注意这里出现报错提示,从提示信息可以看出需要使用https的方式才能上传,解决方案如下:

[root@slave1 ~]# vim /etc/docker/daemon.json
{
"registry-mirrors":["https://registry.docker-cn.com"],
"insecure-registries":["192.168.3.82:5000"]
}

添加私有镜像服务器的地址,注意书写格式为json,有严格的书写要求,需要重启docker服务生效配置

[root@slave1 ~]# systemctl restart docker
[root@slave1 ~]# docker push 192.168.3.82:5000/nginx:v1
The push refers to a repository [192.168.3.82:5000/nginx]
6ee5b085558c: Pushed
78f25536dafc: Pushed
9c46f426bcb7: Pushed
v1: digest: sha256:edad5e71815c79108ddbd1d42123ee13ba2d8050ad27cfa72c531986d03ee4e7 size: 948
重新查看镜像仓库
[root@master ~]# curl http://localhost:5000/v2/_catalog
{"repositories":["nginx"]}
[root@master ~]# curl http://localhost:5000/v2/nginx/tags/list
{"name":"nginx","tags":["v1"]}

查看有哪些版本

测试下载

首先删除客户端主机之前从公共库下载下来的镜像文件

[root@slave1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.3.82:5000/nginx v1 649dcb69b782 10 hours ago 109 MB
docker.io/nginx latest 649dcb69b782 10 hours ago 109 MB
[root@slave1 ~]# docker image rmi -f 649dcb69b782
Untagged: 192.168.3.82:5000/nginx:v1
Untagged: 192.168.3.82:5000/nginx@sha256:edad5e71815c79108ddbd1d42123ee13ba2d8050ad27cfa72c531986d03ee4e7
Untagged: docker.io/nginx:latest
Untagged: docker.io/nginx@sha256:636dd2749d9a363e5b57557672a9ebc7c6d041c88d9aef184308d7434296feea
Deleted: sha256:649dcb69b782d4e281c92ed2918a21fa63322a6605017e295ea75907c84f4d1e
Deleted: sha256:bf7cb208a5a1da265666ad5ab3cf10f0bec1f4bcb0ba8d957e2e485e3ac2b463
Deleted: sha256:55d02c20aa07136ab07ab47f4b20b97be7a0f34e01a88b3e046a728863b5621c
Deleted: sha256:9c46f426bcb704beffafc951290ee7fe05efddbc7406500e7d0a3785538b8735
[root@slave1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE

此时客户端所有的镜像文件全部删除

[root@slave1 ~]# docker pull 192.168.3.82:5000/nginx:v1
Trying to pull repository 192.168.3.82:5000/nginx ...
v1: Pulling from 192.168.3.82:5000/nginx
683abbb4ea60: Pull complete
6ff57cbc007a: Pull complete
162f7aebbf40: Pull complete
Digest: sha256:edad5e71815c79108ddbd1d42123ee13ba2d8050ad27cfa72c531986d03ee4e7
Status: Downloaded newer image for 192.168.3.82:5000/nginx:v1
[root@slave1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.3.82:5000/nginx v1 649dcb69b782 11 hours ago 109 MB

可以看出,客户端已正常从远端服务器拉取到所需要的镜像文件,其它内网服务器也可以正常共享这台镜像服

以上步骤就是通过使用docker Registry快速搭建私有镜像仓库的过程与测试。我也其实也可以通过:利用 Harbor 搭建企业级私有镜像仓库。
Docker可视化工具
Docker是一项非常流行的容器技术,现在在各行各业有着广泛的使用。不过如何管理Docker容器是一个问题,所以我今天向大家介绍两款Docker可视化工具,希望对大家有所帮助。
Portainer
Portainer是一款Docker可视化管理工具,允许我们在网页中方便的查看和管理Docker容器。

要使用Portainer很简单,运行下面两条命令即可。这些命令会创建一个Portainer专用的卷,然后在8000和9000端口创建容器并运行。
$ docker volume create portainer_data$ docker run --name portainer -d -p 8000:8000 -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
然后在浏览器打开对应地址,就会发现成功运行了。第一次运行的时候需要设置账号,然后选择要管理的 Docker 主机。

设置账号

选择要管理的主机
之后就可以看到本机上运行的 Docker 容器了,点击它们还可以进行容器的管理。左边的条目可以管理卷、创建容器、查看主机信息等等。基本上该有的功能都有了,这也是我推荐的一个工具。

LazyDocker
LazyDocker 是基于终端的一个可视化查询工具,支持键盘操作和鼠标点击。相比 Portainer 来说可能不那么专业,不过对于开发者来说可能反而更加好用了。因为一般开发者都是使用命令行来运行 Docker,偶尔需要图形化查看的时候,就可以使用 LazyDocker 这个工具。

官网演示图
安装 LazyDocker 也非常简单,运行下面的命令即可。
docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock -v ~/.config/lazydocker:/.config/jesseduffield/lazydocker \lazyteam/lazydocker
当然如果发现 LazyDocker 挺好用,准备经常使用的话,还可以把它做成缩写添加到 shell 配置文件中,这样就可以将它变成一个简单的命令。例如我用的是 zsh,就将下面这样添加到.zshrc 文件中。以后就可以直接用 lzd 来调用 LazyDocker 了。
alias lzd='docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock -v ~/.config/lazydocker:/.config/jesseduffield/lazydocker lazyteam/lazydocker'
然后就可以在终端中查看 Docker 容器、镜像和卷的信息了。LazyDocker 支持键盘操作和鼠标点击,直接用鼠标点击就可以查看对应信息了。

需要注意如果你的终端 LazyDocker 的图形显示的是乱的,不用担心,只不过是显示字体的问题。重新设置一下终端字体就可以解决了。
以上内容来自:https://www.toutiao.com/i6780...
Docker 社区已经创建了许多开源工具,它们能帮我们处理各种用例。作者在本文中推荐了 5 款认为最有用的 Docker 工具,分别是 Watchtower(自动更新 Docker 容器)、docker-gc(容器和镜像的垃圾回收)、docker-slim(容器瘦身)、 rocker:突破 Dockerfile 的限制,以及 ctop(容器的类顶层接口)。
Docker 社区已经创建了许多开源工具,它们所能帮你处理的用例甚至会超出你的想象。
你可以在网上找到很多酷炫的 Docker 工具,其中大部分是开源的,都可以在 Github 上找到。在过去的两年里,我非常热衷于 Docker,在大多数开发项目中都使用了它。当你开始使用 Docker 后,你会发现它适用的场景比你最初预想的还更多。你会希望 Docker 尽可能为你多做一点事,而它不会让你失望的!
Docker 社区非常活跃,每天都会出现许多有用的工具,时时关注社区中发生的所有创新是很困难的。为了帮助你,我收集了一些我在日常工作中使用的又有趣又实用的 Docker 工具,这些工具提升了我的工作效率,减少了原本需要手工完成的工作。
向大家推荐一些实用工具:你应该知道的 5 个开源 Docker 工具...,Docker 服务终端 UI 管理工具,大家最终根据自己的使用习惯与实际生产需求来选择合适自己的工具来管理 Docker 容器。
Docker 容器监控系统
随着线上服务的全面 docker 化,对 docker 容器的监控就很重要了。SA 的监控系统是物理机的监控,在一个物理机跑多个容器的情况下,我们是没法从一个监控图表里面区分各个容器的资源占用情况的。
推荐大家看看这篇:打造高逼格、可视化的 Docker 容器监控系统平台
Docker 日志管理最佳实践
10 个冷门但又非常实用的 Docker 使用技巧
在平时的工作中,docker 接触得很多,除了经常使用的 docker run ,docker stop 等命令,docker 还有很多十分有用但是却不经常使用的命令,下面就来总结一下:

  1. docker top
    这个命令是用来查看一个容器里面的进程信息的,比如你想查看一个 nginx 容器里面有几个 nginx 进程的时候,就可以这么做:
    docker top 3b307a09d20d
    UID PID PPID C STIME TTY TIME CMD
    root 805 787 0 Jul13 ? 00:00:00 nginx: master process nginx -g daemon off;
    systemd+ 941 805 0 Jul13 ? 00:03:18 nginx: worker process
  2. docker load && docker save
    我一般使用这两个命令去下载打包 Kubernetes 的镜像,因为你知道的国内的网速并不像国外那么快。
    docker save 可以把一个镜像保存到 tar 文件中,你可以这么做:
    ~ docker save registry:2.7.1 >registry-2.7.1.tar

    同时 docker load 可以把镜像从 tar 文件导入到 docker 中

    ~ docker load < registry-2.7.1.tar

  3. docker search
    这个命令可以帮助你在命令行中方便的搜索 DockerHub 中的镜像,比如:
    ~ docker search nginx
    NAME DESCRIPTION STARS OFFICIAL AUTOMATED
    nginx Official build of Nginx. 13519 [OK]
    jwilder/nginx-proxy Automated Nginx reverse proxy for docker con… 1846 [OK]
    richarvey/nginx-php-fpm Container running Nginx + PHP-FPM capable of… 780 [OK]
    linuxserver/nginx An Nginx container, brought to you by LinuxS… 123
    bitnami/nginx Bitnami nginx Docker Image 87 [OK]
    tiangolo/nginx-rtmp Docker image with Nginx using the nginx-rtmp… 85 [OK]
    jc21/nginx-proxy-manager Docker container for managing Nginx proxy ho… 73
    alfg/nginx-rtmp NGINX, nginx-rtmp-module and FFmpeg from sou… 71 [OK]
    nginxdemos/hello NGINX webserver that serves a simple page co… 57 [OK]
    jlesage/nginx-proxy-manager Docker container for Nginx Proxy Manager 53 [OK]
    nginx/nginx-ingress NGINX Ingress Controller for Kubernetes 37
    ......
    当然这个功能在国内可能不会特别好用,因为......
  4. docker events
    这个命令可以帮助你实时获取 docker 的各种事件信息,比如创建了一个容器什么的。
    ~ docker events
    2020-07-28T21:28:46.000403018+08:00 image load sha256:432bf69f0427b52cad10897342eaf23521b7d973566354118e9a59c4d31b5fae (name=sha256:432bf69f0427b52cad10897342eaf23521b7d973566354118e9a59c4d31b5fae)
  5. docker update
    当你 docker run 了之后却发现里面有一些参数并不是你想要的状态比如你设置的 nginx 容器 cpu 或者内存太小,这个时候你就可以使用 docker update 去修改这些参数。
    ~ docker update nginx --cpus 2
  6. docker history
    当你修改了一个镜像,但是忘记了每一层的修改命令,或者你想查看一个镜像是怎么构建的时候就可以使用这个命令,比如:
    ~ docker history traefik:v2.1.6
    IMAGE CREATED CREATED BY SIZE COMMENT
    5212a87ddaba 5 months ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
    5 months ago /bin/sh -c #(nop) CMD ["traefik"] 0B
    5 months ago /bin/sh -c #(nop) ENTRYPOINT ["/entrypoint.… 0B
    5 months ago /bin/sh -c #(nop) EXPOSE 80 0B
    5 months ago /bin/sh -c #(nop) COPY file:59a219a1fb7a9dc8… 419B
    5 months ago /bin/sh -c set -ex; apkArch="$(apk --print-… 52.9MB
    5 months ago /bin/sh -c apk --no-cache add ca-certificate… 1.85MB
    6 months ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
    6 months ago /bin/sh -c #(nop) ADD file:a1906f14a4e217a49… 4.81MB
  7. docker wait
    这个命令可以查看容器的退出状态,比如:
    ~ docker wait 7f7f0522a7d0
    0
    这样你就可以知道这个容器是正常退出的还是异常退出的了。
  8. docker pause && docker unpause
    当你运行了一个容器但是想要暂停它运行的时候,你就可以使用这个命令。
    ~ docker pause 7f7f0522a7d0
  9. docker diff
    当你运行了一个容器,但是你不知道容器里修改了哪一些文件的时候可以使用这个命令,比如:
    ~ docker diff 38c59255bf6e
    C /etc
    A /etc/localtime
    C /var
    C /var/lib
    A /var/lib/registry
  10. docker stats
    这个是 docker 内置的监控命令,当你想要查看当前主机下所有容器占用内存和 cpu 的情况的时候就可以使用这个命令。
    ~ docker stats
    CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
    1c5ade04e7f9 redis 0.08% 17.53MiB / 47.01GiB 0.04% 10.9GB / 37GB 0B / 0B 4
    afe6d4ebe409 kafka-exporter 0.09% 16.91MiB / 47.01GiB 0.04% 1.97GB / 1.53GB 752MB / 0B 23
    f0c7c01a9c34 kafka-docker_zookeeper 0.01% 308.8MiB / 47.01GiB 0.64% 20.2MB / 12.2MB 971MB / 3.29MB 28
    da8c5008955f kafka-docker_kafka-manager 0.08% 393.2MiB / 47.01GiB 0.82% 1.56MB / 2.61MB 1.14GB / 0B 60
    c8d51c583c49 kafka-docker_kafka 1.63% 1.256GiB / 47.01GiB 2.67% 30.4GB / 48.9GB 22.3GB / 5.77GB 85
    ......
    原文:http://suo.im/6n2lLa
    学习 Docker,新手最容易犯的 11 个错误!
    很多人最终还是决定使用 Docker 解决问题。 Docker 的优点很多,比如:
    • 1、一体化——将操作系统、库版本、配置文件、应用程序等全部打包装在容器里。从而保证 QA 所测试的镜像 (image) 会携带同样的行为到达生产环境。
    • 2、轻量——内存占用极小,只为主要过程分配内存。
    • 3、快读——一键启动,就像启动常见的 linux 过程一样快。
    尽管如此,众多用户仍然只是把容器当做常见的虚拟机,而忘记了容器的一个重要特性:
    正因为这一特点,一些用户需要改变他们对容器的观念,为了更好的使用与发挥 Docker 容器的价值,有一些事情是绝对不应该做的:
    1.不要在容器(container)中存储数据
    容器可能会被中断、被替换或遭到破坏。在容器中运行的 1.0 版应用程序很容易就会被 1.1 版取代,而不会对数据造成影响或导致数据丢失。因此,如果需要存储数据,请存储在卷 (volume) 中。在这一情况下,还应注意两个容器是否会在同一个卷上写入数据,这将导致损坏。请确保应用程序适用于写入共享的数据存储。
  11. 不要分两部分传送应用程序 有些人把容器当作虚拟机
    所以他们大多会认为,应该将应用程序部署到现有正在运行的容器中。在需要不断部署和调试的开发阶段,可能确实如此;但对于 QA 和生产的持续交付 (CD) 渠道,应用程序应当是镜像的一部分。切记:容器转瞬即逝。
  12. 不要创建大尺寸镜像
    大尺寸的镜像难以分配。请确保仅使用必需文件和库来运行应用程序。不要安装不必要的数据包,也不要运行“更新”(yum update),这些操作会把大量文件下载到新的镜像层。
  13. 不要使用单层镜像
    为了有效利用多层文件系统,请始终为操作系统创建属于自己的基本镜像层,然后为用户名定义创建一个层,为运行时安装创建一个层,为配置创建一个层,最后再为应用程序创建一个层。这样,重新创建、管理和分配镜像就会容易些。
  14. 不要从正在运行的容器中创建镜像
    换句话说,不要使用"docker commit"命令来创建镜像。这一镜像创建方法不可复制,因此应完全避免使用。请始终使用 Dockerfile 或其他任何可完全复制的 S21(从源代码到镜像)方法,如此一来,如果存储在源代码控制存储库 (GIT) 中,就可以跟踪 Dockerfile 的变更情况。
  15. 不要只使用“最新版”标签
    最新版标签就像 Maven 用户的“快照”(SNAPSHOT) 一样。容器具有多层文件系统这一基本特征,所以我们鼓励使用标签。相信谁也不愿意在构建了几个月的镜像后,突然发现应用程序因为父层(即 Dockerfile 中的 FROM)被新版本取代而无法运行(新版本无法向后兼容或从构建缓存中检索的“最新“版有误)这样的意外吧?在生产过程中部署容器时也应避免使用”最新版“标签,这是因为无法跟踪当前运行的镜像版本。
  16. 不要在单个容器中运行一个以上进程
    容器只运行一个进程(HTTP 守护进程、应用程序服务器、数据库)时效果最佳,但如果运行一个以上进程,在管理和检索日志以及单独更新进程时就会遇到很多麻烦。
  17. 不要在镜像中存储证书及使用环境变量
    不要在镜像中对任何用户名/密码进行硬编码操作。请使用环境变量从容器外部检索信息。Postgres 镜像就是这一原理的极佳诠释。
  18. 不要以 root 权限运行进程
    “默认情况下,Docker 容器以 root 用户权限运行。随着 Docker 技术日趋成熟,能够使用的安全默认选项越来越多。目前,要求 root 对其他用户来说较为危险,另外,不是所有环境都能够使用 root。镜像应使用 USER 指令来为容器的运行指定非 root 用户。”(摘自《Docker 镜像作者指南》(Guidance for Docker Image Authors))
  19. 不要依赖 IP 地址
    每个容器都有自己的内部 IP 地址,如果启动然后停止容器,内部 IP 地址可能会发生变化。如果你的应用程序或微服务需要和另一个容器进行通信,请使用环境变量在容器之间传递相应的主机名和端口。
  20. 监控容器 Docker
    监控已经越来越受到开发者们的重视,实时监控 Docker 的方法,这里推荐 Cloudinsight。 不同于一些需要自写脚本的监控手段,Cloudinsight 作为一家免费的 SaaS 服务,能够一键监控 Docker,且拥有很棒的可视化界面。除此之外,Cloudinsight 还支持多种操作系统、数据库等的监控,能够一体化展示所有被监控的系统基础组件的性能数据。
    原文:https://my.oschina.net/cllgee...
    Jenkins 与 Docker 的自动化 CI/CD 实战
    一、发布流程设计

工作流程:
• 开发人员提交代码到 Git 版本仓库;
• Jenkins 人工/定时触发项目构建;
• Jenkins 拉取代码、代码编码、打包镜像、推送到镜像仓库;
• Jenkins 在 Docker 主机创建容器并发布。

三、 部署过程
1,部署 git
如果公司内部有直接克隆就可以
git clone git@192.168.0.31:/home/git/solo.git
2,部署 Jenkins 环境
部署传送门:Jenkins+Maven+Svn 实现代码自动打包与发布

3,部署私有镜像仓库
注意:docker 仓库 由于 https 认证,所有需要 pull 的客户端,需要修改配置文件
[root@linux-node1 ~]# vim /etc/sysconfig/docker

Modify these options if you want to change the way the docker daemon runs

OPTIONS='--selinux-enabled --insecure-registry 192.168.56.11:5000'
4,所有主机安装 docker
1)安装依赖包
yum install -y yum-utils device-mapper-persistent-data lvm2`
2)添加 Docker 软件包源:
yum-config-manager
--add-repo
https://download.docker.com/linux/centos/docker-ce.repo
3)安装 Docker CE
yum install docker-ce -y`
4)配置加速器
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://bc437cce.m.daocloud.io`

因为默认源会去国外获取数据,所以会慢可以超时,这是我们就需要配置加速器指向国内源https://www.daocloud.io/

5)启动并开机启动

systemctl start docker

systemctl enable docker

四、构建基础镜像
【Apache、Nginx、Tomcat、LNMP、LAMP、LNTP】
JAVA 程序必须有 JDK 环境才可以运行,为了减少镜像大小及提高性能,这里直接把 JDK 放到宿主机上,容器以挂载形式使用。
1,安装 jdk

rz 把 tar 包上传,解压后放到指定目录

rz.......
tar -zxvf jdk-8u60-linux-x64.tar.gz
mv jdk1.8.0\_60 /usr/local/jdk1.8
2,拟写 Dockerfile

cat Dockerfile

FROM centos:7

他的妈妈是谁

MAINTAINER www.aliangedu.com

他的爸爸是谁

ENV VERSION=8.5.33

tomcat 版本

ENV JAVA_HOME /usr/local/jdk

jdk 绝对路径

RUN yum install wget -y

运行的命令

RUN wget http://mirrors.shu.edu.cn/apache/tomcat/tomcat-8/v${VERSION}/bin/apache-tomcat-${VERSION}.tar.gz &&
tar zxf apache-tomcat-${VERSION}.tar.gz &&
mv apache-tomcat-${VERSION} /usr/local/tomcat &&
rm -rf apache-tomcat-${VERSION}.tar.gz /usr/local/tomcat/webapps/* &&
mkdir /usr/local/tomcat/webapps/ROOT
EXPOSE 8080

程序使用的端口

CMD /usr/local/tomcat/bin/catalina.sh run

执行 tomcat 目录下的启动脚本,这里面遇到坑,就是-v 将宿主机 jdk 目录挂在到容器/usr/local/jdk 时候,因为镜像按照 dockerfile 去打,那么在执行命令的时候就会找不到路径,所以我临时删除了,EXPOSE 与 CMD 2 行,然后重新打包,使用 -p 指定端口,然后进入容器,手工启动 tomcat 的方式,进行

3,构建镜像
docker build -t 192.168.56.11:5000/tomcat-85:latest -f dockerfile .

最后这个点。代表当前路径,在制作镜像时,会记录上下文内容

4,上传到 docker 镜像仓库
root@node02 scripts]# docker push 192.168.56.11:5000/tomcat-85:latest
5,启动镜像 测试
[root@node02 scripts]# docker run -it -d -p 8080:8080 -v /usr/local/jdk1.8:/usr/local/jdk 192.168.56.11:5000/tomcat-8:latest
[root@3addff07c464 ROOT]# echo "123" >index.jsp

五、Jenkins 配置
1.主页面 -> 系统管理 -> 全局工具配置
指定 JDK、Maven 路径,Git 保持默认:

2.jenkins 安装必要插件
主页面 -> 系统管理 ->管理插件:
安装 SSH 与 Git Parameter 插件。
插件说明:
• 》SSH:用于 SSH 远程 Docker 主机执行 Shell 命令
• 》Git Parameter:动态获取 Git 仓库 Branch、Tag

3,配置 SSH 插件
第一步:先创建一个用于连接 Docker 主机的凭证 (有权限的用户)
主页面 -> 凭据 -> 系统 -> 右击全局凭据 -> 添加凭据:

输入连接 Docker 主机的用户名和密码:

第二步:添加 SSH 远程主机
主页面 -> 系统管理 -> 系统设置 -> SSH remote hosts:

问题:当以普通用户身份去使用 docker images 时,出现以下错误:

六、将从 github 上下载的 JAVA 项目,上传到自己的 gitlab 仓库

git clone https://github.com/b3log/solo

cd solo

移除旧的推送地址,添加新的:

git remote remove origin

git remote add origin git@gitlab.example.com:qqq/solo.git

提交代码到 Git 仓库并创建 tag:

touch src/main/webapp/a.html

git add .

git commit -m “a”

创建标签:

git tag 1.0.0

推送到 Git 服务器:

git push origin 1.0.0

登陆 gitlab 查看 solo 项目:

七、Jenkins 创建项目并发布测试
1.主页面 -> 新建任务 -> 输入任务名称,构建一个 Maven 项目:

注意:如果没有显示“构建一个 Maven 项目”选项,需要在管理插件里安装“Maven Integration plugin”插件。
配置 Git 参数化构建:

2.动态获取 Git 仓库 tag,与用户交互选择 Tag 发布:【也可以设置分支】

3.指定项目 Git 仓库地址:

修改*/master 为$Tag,Tag是上面动态获取的变量名,表示根据用户选择打代码版本。
4.设置maven构建命令选项:
clean package -Dmaven.test.skip=ture

利用pom.xml文件构建项目。
在Jenkins本机镜像构建与推送到镜像仓库,并SSH远程连接到Docker主机使用推送的镜像创建容器:

上图中 命令内容如下:
REPOSITORY=192.168.56.11:5000/solo:${Tag}

构建镜像

cat > Dockerfile << EOF
FROM 192.168.56.11:5000/tomcat-8:latest
RUN rm -rf /usr/local/tomcat/webapps/ROOT
COPY target/*.war /usr/local/tomcat/webapps/ROOT.war
CMD ["/usr/local/tomcat/bin/catalina.sh", "run"]
EOF
docker build -t $REPOSITORY .

上传镜像

docker push $REPOSITORY

上图中 Command 内容如下:
REPOSITORY=192.168.56.11:5000/solo:${Tag}

部署

sudo docker rm -f blog-solo |true
sudo docker image rm $REPOSITORY |true
sudo docker container run -d --name blog-solo -v /usr/local/jdk1.8:/usr/local/jdk -p 8080:8080 $REPOSITORY

-d 后台运行 ,-v 挂在目录,-p 映射端口,后面是镜像

注:容器名称 blog-solo,暴露宿主机端口 8080,即使用宿主机 IP 192.168.56.12:8080 访问 blog-solo 项目。
blog-solo 项目已配置完成,开始构建:
选择 tag,开始构建:

点击左下角构建历史里,右击第一个查看控制台输出:

构建详细内容

构建成功
访问:192.168.56.12:8080 查看部署结果

调整项目访问地址
进入容器,切换到项目目录
vi WEB-INF/classes/latke.properties

Server

Browser visit protocol

serverScheme=http

Browser visit domain name

serverHost=192.168.56.12

Browser visit port, 80 as usual, THIS IS NOT SERVER LISTEN PORT!

serverPort=8080
调整后,重启 tomcat,再次验证,OK,结果如下:

至此,自动化 CI 环境搭建完成,你可以模拟提交代码并打 tag 测试自动化发布流程。
八、问题总结:
查看 docker.sock 权限
[root@node03 ~]# ll /var/run/docker.sock
srw-rw---- 1 root docker 0 9月 4 21:55 /var/run/docker.sock

解决方法:【免 sudo 使用 docker images 】
[root@node03 ~]# sudo groupadd docker

groupadd:“docker”组已存在

[root@node03 ~]# sudo gpasswd -a jenkins docker

正在将用户“jenkins”加入到“docker”组中

[root@node03 ~]# sudo service docker restart

重启服务

[root@node03 ~]# newgrp - docker

重新加载 group 组信息,一定要输入这条命令,否则无法加载最新组内容,因为有缓存

原文:https://www.toutiao.com/a6602...
使用 GitLab CI 和 Docker 自动部署 Spring Boot 应用
Docker 常见疑难杂症解决方案

这里主要是为了记录在使用 Docker 的时候遇到的问题及其处理解决方法。

1.Docker 迁移存储目录
默认情况系统会将 Docker 容器存放在/var/lib/docker 目录下
问题起因:今天通过监控系统,发现公司其中一台服务器的磁盘快慢,随即上去看了下,发现 /var/lib/docker 这个目录特别大。由上述原因,我们都知道,在 /var/lib/docker 中存储的都是相关于容器的存储,所以也不能随便的将其删除掉。
那就准备迁移 docker 的存储目录吧,或者对 /var 设备进行扩容来达到相同的目的。更多关于 dockerd 的详细参数,请点击查看 官方文档 地址。
但是需要注意的一点就是,尽量不要用软链, 因为一些 docker 容器编排系统不支持这样做,比如我们所熟知的 k8s 就在内。

发现容器启动不了了

ERROR:cannot create temporary directory!

查看系统存储情况

$ du -h --max-depth=1
解决方法1:添加软链接

1.停止docker服务

$ sudo systemctl stop docker

2.开始迁移目录

$ sudo mv /var/lib/docker /data/

3.添加软链接

sudo ln -s /data/docker /var/lib/docker

4.启动docker服务

$ sudo systemctl start docker
解决方法2:改动 docker 配置文件

3.改动docker启动配置文件

$ sudo vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --graph=/data/docker/

4.改动docker启动配置文件

$ sudo vim /etc/docker/daemon.json
{

"live-restore": true,
"graph": [ "/data/docker/" ]

}
操作注意事项:在迁移 docker 目录的时候注意使用的命令,要么使用 mv 命令直接移动,要么使用 cp 命令复制文件,但是需要注意同时复制文件权限和对应属性,不然在使用的时候可能会存在权限问题。如果容器中,也是使用 root 用户,则不会存在该问题,但是也是需要按照正确的操作来迁移目录。

使用mv命令

$ sudo mv /var/lib/docker /data/docker

使用cp命令

$ sudo cp -arv /data/docker /data2/docker
下图中,就是因为启动的容器使用的是普通用户运行进程的,且在运行当中需要使用 /tmp 目录,结果提示没有权限。在我们导入容器镜像的时候,其实是会将容器启动时需要的各个目录的权限和属性都赋予了。如果我们直接是 cp 命令单纯复制文件内容的话,就会出现属性不一致的情况,同时还会有一定的安全问题。

2.Docker 设备空间不足
Increase Docker container size from default 10GB on rhel7.
问题起因一:容器在导入或者启动的时候,如果提示磁盘空间不足的,那么多半是真的因为物理磁盘空间真的有问题导致的。如下所示,我们可以看到 / 分区确实满了。

查看物理磁盘空间

$ df -Th
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 40G 40G 0G 100% /
tmpfs 7.8G 0 7.8G 0% /dev/shm
/dev/vdb1 493G 289G 179G 62% /mnt
如果发现真的是物理磁盘空间满了的话,就需要查看到底是什么占据了如此大的空间,导致因为容器没有空间无法启动。其中,docker 自带的命令就是一个很好的能够帮助我们发现问题的工具。

查看基本信息

硬件驱动使用的是devicemapper,空间池为docker-252

磁盘可用容量仅剩16.78MB,可用供我们使用

$ docker info
Containers: 1
Images: 28
Storage Driver: devicemapper
Pool Name: docker-252:1-787932-pool
Pool Blocksize: 65.54 kB
Backing Filesystem: extfs
Data file: /dev/loop0
Metadata file: /dev/loop1
Data Space Used: 1.225 GB
Data Space Total: 107.4 GB
Data Space Available: 16.78 MB
Metadata Space Used: 2.073 MB
Metadata Space Total: 2.147 GB
解决方法:通过查看信息,我们知道正是因为 docker 可用的磁盘空间不足,所以导致启动的时候没有足够的空间进行加载启动镜像。解决的方法也很简单,第一就是清理无效数据文件释放磁盘空间(清除日志),第二就是修改 docker 数据的存放路径(大分区)。

显示哪些容器目录具有最大的日志文件

$ du -d1 -h /var/lib/docker/containers | sort -h

清除您选择的容器日志文件的内容

$ cat /dev/null > /var/lib/docker/containers/container_id/container_log_name
问题起因二:显然我遇到的不是上一种情况,而是在启动容器的时候,容器启动之后不久就显示是 unhealthy 的状态,通过如下日志发现,原来是复制配置文件启动的时候,提示磁盘空间不足。
后面发现是因为 CentOS7 的系统使用的 docker 容器默认的创建大小就是 10G 而已,然而我们使用的容器却超过了这个限制,导致无法启动时提示空间不足。
2019-08-16 11:11:15,816 INFO spawned: 'app-demo' with pid 835
2019-08-16 11:11:16,268 INFO exited: app (exit status 1; not expected)
2019-08-16 11:11:17,270 INFO gave up: app entered FATAL state, too many start retries too quickly
cp: cannot create regular file '/etc/supervisor/conf.d/grpc-app-demo.conf': No space left on device
cp: cannot create regular file '/etc/supervisor/conf.d/grpc-app-demo.conf': No space left on device
cp: cannot create regular file '/etc/supervisor/conf.d/grpc-app-demo.conf': No space left on device
cp: cannot create regular file '/etc/supervisor/conf.d/grpc-app-demo.conf': No space left on device
解决方法1:改动 docker 启动配置文件

/etc/docker/daemon.json

{

"live-restore": true,
"storage-opt": [ "dm.basesize=20G" ]

}
解决方法2:改动 systemctl 的 docker 启动文件

1.stop the docker service

$ sudo systemctl stop docker

2.rm exised container

$ sudo rm -rf /var/lib/docker

2.edit your docker service file

$ sudo vim /usr/lib/systemd/system/docker.service

3.find the execution line

ExecStart=/usr/bin/dockerd
and change it to:
ExecStart=/usr/bin/dockerd --storage-opt dm.basesize=20G

4.start docker service again

$ sudo systemctl start docker

5.reload daemon

$ sudo systemctl daemon-reload
问题起因三:还有一种情况也会让容器无法启动,并提示磁盘空间不足,但是使用命令查看发现并不是因为物理磁盘真的不足导致的。而是,因为对于分区的 inode 节点数满了导致的。

报错信息

No space left on device
解决方法:因为 ext3 文件系统使用 inode table 存储 inode 信息,而 xfs 文件系统使用 B+ tree 来进行存储。考虑到性能问题,默认情况下这个 B+ tree 只会使用前 1TB 空间,当这 1TB 空间被写满后,就会导致无法写入 inode 信息,报磁盘空间不足的错误。我们可以在 mount 时,指定 inode64 即可将这个 B+ tree 使用的空间扩展到整个文件系统。

查看系统的inode节点使用情况

$ sudo df -i

尝试重新挂载

$ sudo mount -o remount -o noatime,nodiratime,inode64,nobarrier /dev/vda1
补充知识:文件储存在硬盘上,硬盘的最小存储单位叫做“扇区”(Sector)。每个扇区储存 512 字节(相当于0.5KB)。操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个“块”(block)。这种由多个扇区组成的”块”,是文件存取的最小单位。”块”的大小,最常见的是4KB,即连续八个 sector 组成一个 block 块。文件数据都储存在”块”中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做“索引节点”(inode)。每一个文件都有对应的 inode,里面包含了除了文件名以外的所有文件信息。
inode 也会消耗硬盘空间,所以硬盘格式化的时候,操作系统自动将硬盘分成两个区域。一个是数据区,存放文件数据;另一个是 inode 区(inode table),存放 inode 所包含的信息。每个 inode 节点的大小,一般是 128 字节或 256 字节。inode 节点的总数,在格式化时就给定,一般是每1KB或每2KB就设置一个 inode 节点。

每个节点信息的内容

$ stat check_port_live.sh
File: check_port_live.sh
Size: 225 Blocks: 8 IO Block: 4096 regular file
Device: 822h/2082d Inode: 99621663 Links: 1
Access: (0755/-rwxr-xr-x) Uid: ( 1006/ escape) Gid: ( 1006/ escape)
Access: 2019-07-29 14:59:59.498076903 +0800
Modify: 2019-07-29 14:59:59.498076903 +0800
Change: 2019-07-29 23:20:27.834866649 +0800
Birth: -

磁盘的inode使用情况

$ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
udev 16478355 801 16477554 1% /dev
tmpfs 16487639 2521 16485118 1% /run
/dev/sdc2 244162560 4788436 239374124 2% /
tmpfs 16487639 5 16487634 1% /dev/shm
3.Docker 缺共享链接库
Docker 命令需要对/tmp 目录下面有访问权限
问题起因:给系统安装完 compose 之后,查看版本的时候,提示缺少一个名为 libz.so.1 的共享链接库。第一反应就是,是不是系统少安装那个软件包导致的。随即,搜索了一下,将相关的依赖包都给安装了,却还是提示同样的问题。

提示错误信息

$ docker-compose --version
error while loading shared libraries: libz.so.1: failed to map segment from shared object: Operation not permitted
解决方法:后来发现,是因为系统中 docker 没有对 /tmp 目录的访问权限导致,需要重新将其挂载一次,就可以解决了。

重新挂载

$ sudo mount /tmp -o remount,exec
4.Docker 容器文件损坏
对 dockerd 的配置有可能会影响到系统稳定
问题起因:容器文件损坏,经常会导致容器无法操作。正常的 docker 命令已经无法操控这台容器了,无法关闭、重启、删除。正巧,前天就需要这个的问题,主要的原因是因为重新对 docker 的默认容器进行了重新的分配限制导致的。

操作容器遇到类似的错误

b'devicemapper: Error running deviceCreate (CreateSnapDeviceRaw) dm_task_run failed'
解决方法:可以通过以下操作将容器删除/重建。

1.关闭docker

$ sudo systemctl stop docker

2.删除容器文件

$ sudo rm -rf /var/lib/docker/containers

3.重新整理容器元数据

$ sudo thin_check /var/lib/docker/devicemapper/devicemapper/metadata
$ sudo thin_check --clear-needs-check-flag /var/lib/docker/devicemapper/devicemapper/metadata

4.重启docker

$ sudo systemctl start docker
5.Docker 容器优雅重启
不停止服务器上面运行的容器,重启 dockerd 服务是多么好的一件事
问题起因:默认情况下,当 Docker 守护程序终止时,它会关闭正在运行的容器。从 Docker-ce 1.12 开始,可以在配置文件中添加 live-restore 参数,以便在守护程序变得不可用时容器保持运行。需要注意的是 Windows 平台暂时还是不支持该参数的配置。

Keep containers alive during daemon downtime

$ sudo vim /etc/docker/daemon.yaml
{
"live-restore": true
}

在守护进程停机期间保持容器存活

$ sudo dockerd --live-restore

只能使用reload重载

相当于发送SIGHUP信号量给dockerd守护进程

$ sudo systemctl reload docker

但是对应网络的设置需要restart才能生效

$ sudo systemctl restart docker
解决方法:可以通过以下操作将容器删除/重建。

/etc/docker/daemon.yaml

{

"registry-mirrors": ["https://vec0xydj.mirror.aliyuncs.com"],  # 配置获取官方镜像的仓库地址
"experimental": true,  # 启用实验功能
"default-runtime": "nvidia",  # 容器的默认OCI运行时(默认为runc)
"live-restore": true,  # 重启dockerd服务的时候容易不终止
"runtimes": {  # 配置容器运行时
    "nvidia": {
        "path": "/usr/bin/nvidia-container-runtime",
        "runtimeArgs": []
    }
},
"default-address-pools": [  # 配置容器使用的子网地址池
    {
        "scope": "local",
        "base":"172.17.0.0/12",
        "size":24
    }
]

}
6.Docker 容器无法删除
找不到对应容器进程是最吓人的
问题起因:今天遇到 docker 容器无法停止/终止/删除,以为这个容器可能又出现了 dockerd 守护进程托管的情况,但是通过ps -ef 无法查到对应的运行进程。哎,后来开始开始查 supervisor 以及 Dockerfile 中的进程,都没有。这种情况的可能原因是容器启动之后,之后,主机因任何原因重新启动并且没有优雅地终止容器。剩下的文件现在阻止你重新生成旧名称的新容器,因为系统认为旧容器仍然存在。

删除容器

$ sudo docker rm -f f8e8c3..
Error response from daemon: Conflict, cannot remove the default name of the container
解决方法:找到 /var/lib/docker/containers/ 下的对应容器的文件夹,将其删除,然后重启一下 dockerd 即可。我们会发现,之前无法删除的容器没有了。

删除容器文件

$ sudo rm -rf /var/lib/docker/containers/f8e8c3...65720

重启服务

$ sudo systemctl restart docker.service
7.Docker 容器中文异常
容器存在问题话,记得优先在官网查询
问题起因:今天登陆之前部署的 MySQL 数据库查询,发现使用 SQL 语句无法查询中文字段,即使直接输入中文都没有办法显示。

查看容器支持的字符集

root@b18f56aa1e15:# locale -a
C
C.UTF-8
POSIX
解决方法:Docker 部署的 MySQL 系统使用的是 POSIX 字符集。然而 POSIX 字符集是不支持中文的,而 C.UTF-8 是支持中文的只要把系统中的环境 LANG 改为 "C.UTF-8" 格式即可解决问题。同理,在 K8S 进入 pod 不能输入中文也可用此方法解决。

临时解决

docker exec -it some-mysql env LANG=C.UTF-8 /bin/bash

永久解决

docker run --name some-mysql

-e MYSQL_ROOT_PASSWORD=my-secret-pw 
-d mysql:tag --character-set-server=utf8mb4 
--collation-server=utf8mb4_unicode_ci

8.Docker 容器网络互通
了解 Docker 的四种网络模型
问题起因:在本机部署 Nginx 容器想代理本机启动的 Python 后端服务程序,但是对代码服务如下的配置,结果访问的时候一直提示 502 错误。

启动Nginx服务

$ docker run -d -p 80:80 $PWD:/etc/nginx nginx
nginx
server {

...
location /api {
    proxy_pass http://localhost:8080
}
...

}
解决方法:后面发现是因为 nginx.conf 配置文件中的 localhost 配置的有问题,由于 Nginx 是在容器中运行,所以 localhost 为容器中的 localhost,而非本机的 localhost,所以导致无法访问。
可以将 nginx.conf 中的 localhost 改为宿主机的 IP 地址,就可以解决 502 的错误。

查询宿主机IP地址 => 172.17.0.1

$ ip addr show docker0
docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default

link/ether 02:42:d5:4c:f2:1e brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
   valid_lft forever preferred_lft forever
inet6 fe80::42:d5ff:fe4c:f21e/64 scope link
   valid_lft forever preferred_lft forever

nginx
server {

...
location /api {
    proxy_pass http://172.17.0.1:8080
}
...

}
当容器使用 host 网络时,容器与宿主共用网络,这样就能在容器中访问宿主机网络,那么容器的 localhost 就是宿主机的 localhost 了。

服务的启动方式有所改变(没有映射出来端口)

因为本身与宿主机共用了网络,宿主机暴露端口等同于容器中暴露端口

$ docker run -d -p 80:80 --network=host $PWD:/etc/nginx nginxx
9.Docker 容器总线错误
总线错误看到的时候还是挺吓人了
问题起因:在 docker 容器中运行程序的时候,提示 bus error 错误。

总线报错

$ inv app.user_op --name=zhangsan
Bus error (core dumped)
解决方法:原因是在 docker 运行的时候,shm 分区设置太小导致 share memory 不够。不设置 –shm-size 参数时,docker 给容器默认分配的 shm 大小为 64M,导致程序启动时不足。

启动docker的时候加上--shm-size参数(单位为b,k,m或g)

$ docker run -it --rm --shm-size=200m pytorch/pytorch:latest
解决方法:还有一种情况就是容器内的磁盘空间不足,也会导致 bus error 的报错,所以清除多余文件或者目录,就可以解决了。

磁盘空间不足

$ df -Th
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 1T 1T 0G 100% /
shm tmpfs 64M 24K 64M 1% /dev/shm
10.Docker NFS 挂载报错
总线错误看到的时候还是挺吓人了
问题起因:我们将服务部署到 openshift 集群中,启动服务调用资源文件的时候,报错信息如下所示。从报错信息中,得知是在 Python3 程序执行 read_file() 读取文件的内容,给文件加锁的时候报错了。但是奇怪的是,本地调试的时候发现服务都是可以正常运行的,文件加锁也是没问题的。后来发现,在 openshift 集群中使用的是 NFS 挂 载的共享磁盘。

报错信息

Traceback (most recent call last):

......
File "xxx/utils/storage.py", line 34, in xxx.utils.storage.LocalStorage.read_file

OSError: [Errno 9] Bad file descriptor

文件加锁代码

...

with open(self.mount(path), 'rb') as fileobj:
    fcntl.flock(fileobj, fcntl.LOCK_EX)
    data = fileobj.read()
return data

...
解决方法:从下面的信息得知,要在 Linux 中使用 flock() 的话,就需要升级内核版本到 2.6.11+ 才行。后来才发现,这实际上是由 RedHat 內核中的一个错误引起的,并在 kernel-3.10.0-693.18.1.el7 版本中得到修复。所以对于 NFSv3 和 NFSv4 服务而已,就需要升级 Linux 内核版本才能够解决这个问题。

https://t.codebug.vip/questions-930901.htm

$ In Linux kernels up to 2.6.11, flock() does not lock files over NFS (i.e.,
the scope of locks was limited to the local system). [...] Since Linux 2.6.12,
NFS clients support flock() locks by emulating them as byte-range locks on the entire file.
11.Docker 默认使用网段
__
启动的容器网络无法相互通信,很是奇怪!
问题起因:我们在使用 Docker 启动服务的时候,发现有时候服务之前可以相互连通,而有时间启动的多个服务之前却出现了无法访问的情况。究其原因,发现原来是因为使用的内部私有地址网段不一致导致的。有点服务启动到了 172.17 - 172.31 的网段,有的服务跑到了 192.169.0 - 192.168.224 的网段,这样导致服务启动之后出现无法访问的情况。

解决方法:上述问题的处理方式,就是手动指定 Docker 服务的启动网段,就可以了。

查看docker容器配置

$ cat /etc/docker/daemon.json
{

"registry-mirrors": ["https://vec0xydj.mirror.aliyuncs.com"],
"default-address-pools":[{"base":"172.17.0.0/12","size":24}],
"experimental": true,
"default-runtime": "nvidia",
"live-restore": true,
"runtimes": {
    "nvidia": {
        "path": "/usr/bin/nvidia-container-runtime",
        "runtimeArgs": []
    }
}

}
12.Docker 服务启动串台
__
使用 docker-compose 命令各自启动两组服务,发现服务会串台!
问题起因:在两个不同名称的目录目录下面,使用 docker-compose 来启动服务,发现当 A 组服务启动完毕之后,再启动 B 组服务的时候,发现 A 组当中对应的一部分服务又重新启动了一次,这就非常奇怪了!因为这个问题的存在会导致,A 组服务和 B 组服务无法同时启动。之前还以为是工具的 Bug,后来请教了“上峰”,才知道了原因,恍然大悟。

服务目录结构如下所示

A: /data1/app/docker-compose.yml
B: /data2/app/docker-compose.yml
解决方法:发现 A 和 B 两组服务会串台的原因,原来是 docker-compose 会给启动的容器加 label 标签,然后根据这些 label 标签来识别和判断对应的容器服务是由谁启动的、谁来管理的,等等。而这里,我们需要关注的 label 变量是 com.docker.compose.project,其对应的值是使用启动配置文件的目录的最底层子目录名称,即上面的 app 就是对应的值。我们可以发现, A 和 B 两组服务对应的值都是 app,所以启动的时候被认为是同一个,这就出现了上述的问题。如果需要深入了解的话,可以去看对应源代码。

可以将目录结构调整为如下所示

A: /data/app1/docker-compose.yml
B: /data/app2/docker-compose.yml
A: /data1/app-old/docker-compose.yml
B: /data2/app-new/docker-compose.yml
或者使用 docker-compose 命令提供的参数 -p 来规避该问题的发生。

指定项目项目名称

$ docker-compose -f ./docker-compose.yml -p app1 up -d
13.Docker 命令调用报错
__
在编写脚本的时候常常会执行 docker 相关的命令,但是需要注意使用细节!
问题起因:CI 更新环境执行了一个脚本,但是脚本执行过程中报错了,如下所示。通过对应的输出信息,可以看到提示说正在执行的设备不是一个 tty。

随即,查看了脚本发现报错地方是执行了一个 exec 的 docker 命令,大致如下所示。很奇怪的是,手动执行或直接调脚本的时候,怎么都是没有问题的,但是等到 CI 调用的时候怎么都是有问题。后来好好看下下面这个命令,注意到 -it 这个参数了。

脚本调用docker命令

docker exec -it <container_name> psql -Upostgres ......
我们可以一起看下 exec 命令的这两个参数,自然就差不多理解了。
-i/-interactive #即使没有附加也保持 STDIN 打开;如果你需要执行命令则需要开启这个选项
-t/–tty #分配一个伪终端进行执行;一个连接用户的终端与容器 stdin 和 stdout 的桥梁
解决方法:docker exec 的参数 -t 是指 Allocate a pseudo-TTY 的意思,而 CI 在执行 job 的时候并不是在 TTY 终端中执行,所以 -t 这个参数会报错。

14.Docker 定时任务异常
__
在 Crontab 定时任务中也存在 Docker 命令执行异常的情况!
问题起因:今天发现了一个问题,就是在备份 Mysql 数据库的时候,使用 docker 容器进行备份,然后使用 Crontab 定时任务来触发备份。但是发现备份的 MySQL 数据库居然是空的,但是手动执行对应命令切是好的,很奇怪。

Crontab定时任务

0 /6

docker exec -it <container_name> sh -c 
    'exec mysqldump --all-databases -uroot -ppassword ......'

解决方法:后来发现是因为执行的 docker 命令多个 -i 导致的。因为 Crontab 命令执行的时候,并不是交互式的,所以需要把这个去掉才可以。总结就是,如果你需要回显的话则需要 -t 选项,如果需要交互式会话则需要 -i 选项。
-i/-interactive #即使没有附加也保持 STDIN 打开;如果你需要执行命令则需要开启这个选项
-t/–tty #分配一个伪终端进行执行;一个连接用户的终端与容器 stdin 和 stdout 的桥梁
15.Docker 变量使用引号
__
compose 里边环境变量带不带引号的问题!
问题起因:使用过 compose 的同学可能都遇到过,我们在编写启动配置文件的时候,添加环境变量的时候到底是使用单引号、双引号还是不使用引号。时间长了,可能我们总是三者是一样的,可以相互使用。但是,直到最后我们发现坑越来越多,越来越隐晦。
反正我是遇到过很多是因为添加引号导致的服务启动问题,后来得出的结论就是一律不适用引号。裸奔,体验前所未有的爽快!直到现在看到了 Github 中对应的 issus 之后,才终于破案了。

TESTVAR="test"

在Compose中进行引用TESTVAR变量,无法找到

TESTVAR=test

在Compose中进行引用TESTVAR变量,可以找到

docker run -it --rm -e TESTVAR="test" test:latest

后来发现docker本身其实已经正确地处理了引号的使用
解决方法:得到的结论就是,因为 Compose 解析 yaml 配置文件,发现引号也进行了解释包装。这就导致原本的 TESTVAR="test" 被解析成了 'TESTVAR="test"',所以我们在引用的时候就无法获取到对应的值。现在解决方法就是,不管是我们直接在配置文件添加环境变量或者使用 env_file 配置文件,能不使用引号就不适用引号。

  1. Docker 删除镜像报错
    __
    无法删除镜像,归根到底还是有地方用到了!
    问题起因:清理服器磁盘空间的时候,删除某个镜像的时候提示如下信息。提示需要强制删除,但是发现及时执行了强制删除依旧没有效果。

    删除镜像

    $ docker rmi 3ccxxxx2e862
    Error response from daemon: conflict: unable to delete 3ccxxxx2e862 (cannot be forced) - image has dependent child images

    强制删除

    $ dcoker rmi -f 3ccxxxx2e862
    Error response from daemon: conflict: unable to delete 3ccxxxx2e862 (cannot be forced) - image has dependent child images
    解决方法:后来才发现,出现这个原因主要是因为 TAG,即存在其他镜像引用了这个镜像。这里我们可以使用如下命令查看对应镜像文件的依赖关系,然后根据对应 TAG 来删除镜像。

    查询依赖 - image_id表示镜像名称

    $ docker image inspect --format='{{.RepoTags}} {{.Id}} {{.Parent}}' $(docker image ls -q --filter since=<image_id>)

    根据TAG删除镜像

    $ docker rmi -f c565xxxxc87f
    bash

    删除悬空镜像

    $ docker rmi $(docker images --filter "dangling=true" -q --no-trunc)
    17.Docker 普通用户切换
    __
    切换 Docker 启动用户的话,还是需要注意下权限问题的!
    问题起因:我们都知道在 Docker 容器里面使用 root 用户的话,是不安全的,很容易出现越权的安全问题,所以一般情况下,我们都会使用普通用户来代替 root 进行服务的启动和管理的。今天给一个服务切换用户的时候,发现 Nginx 服务一直无法启动,提示如下权限问题。因为对应的配置文件也没有配置 var 相关的目录,无奈 🤷‍♀ !️

    Nginx报错信息

    nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (13: Permission denied)
    2020/11/12 15:25:47 [emerg] 23#23: mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)
    解决方法:后来发现还是 nginx.conf 配置文件,配置的有问题,需要将 Nginx 服务启动时候需要的文件都配置到一个无权限的目录,即可解决。
    nginx
    user www-data;
    worker_processes 1;
    error_log /data/logs/master_error.log warn;
    pid /dev/shm/nginx.pid;
    events {
    worker_connections 1024;
    }
    http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    gzip on;
    sendfile on;
    tcp_nopush on;
    keepalive_timeout 65;
    client_body_temp_path /tmp/client_body;
    fastcgi_temp_path /tmp/fastcgi_temp;
    proxy_temp_path /tmp/proxy_temp;
    scgi_temp_path /tmp/scgi_temp;
    uwsgi_temp_path /tmp/uwsgi_temp;
    include /etc/nginx/conf.d/*.conf;
    }

Stirling PDF:免费、强大的一站式PDF开源操作工具

作者 cyril
2023年11月14日 09:03

[button color="black" icon="" url="http://pdf.cyrilstudio.top/" type=""]免费体验[/button]

PDF是一种便携式文档格式,由Adobe
Systems公司开发,用于创建、分享和存储电子文档。它的独特之处在于能够在不同操作系统和设备上保持文档的一致性呈现,无需担心字体或格式问题。PDF文件通常包含文本、图像、链接和多媒体元素,可以通过PDF阅读器来查看和编辑。这种格式广泛用于电子书、法律文件、商业报告、表格等各种领域,因其可靠性和广泛兼容性而备受欢迎。
PDF文件还支持加密和数字签名,提供了一定的安全性,适用于保护敏感信息的需要。总之,PDF是一种功能强大且广泛应用的电子文档格式,适用于各种文档管理和共享需求。

工具介绍

Stirling-PDF是一款基于 Web 的 PDF 操作工具,是一个高效而强大的本地托管应用程序,为您提供广泛的 PDF 文件处理功能。可满足各种 PDF 处理需求。您可以使用它来执行多种操作,例如拆分、合并、转换、重新排列、添加图像、旋转和压缩 PDF 文件。这个本地托管的 Web 应用程序具有出色的性能,能够在本地环境中运行,为您提供更高的数据安全性。不论您是处理文档、电子书还是其他 PDF 相关任务,这个工具都将成为您的得力助手,满足您的一切 PDF 处理需求。
Stirling PDF页面
Stirling PDF允许您在 PDF 文件上执行各种操作,包括拆分、合并、转换、重新组织、添加图像、旋转、压缩等等。

Stirling PDF 功能页面

隐私保护

Stirling PDF 不会发起任何与记录或跟踪相关的外部请求。

所有文件和 PDF 都要么完全在客户端上处理,要么仅在任务执行期间在服务器内存中,或者仅在任务执行期间存储在临时文件中。用户已经下载的文件在那时已经从服务器上删除。

主要功能

  1. 完整的交互式 GUI,用于合并/拆分/旋转/移动 PDF 及其页面
  2. 将 PDF 拆分为多个文件,指定页面号或提取所有页面为单独的文件
  3. 合并多个 PDF 到一个单一的结果文件中
  4. 将 PDF 转换为图像以及从图像转换为 PDF
  5. 重新组织 PDF 页面的顺序
  6. 添加/生成签名
  7. 将 PDF 格式化为多页页面
  8. 按设定的百分比调整页面内容大小
  9. 调整对比度
  10. 裁剪 PDF
  11. 自动拆分 PDF(带有物理扫描的页面分隔符)
  12. 压平 PDF
  13. 修复 PDF
  14. 检测并删除空白页面
  15. 比较两个 PDF 并显示文本差异
  16. 向 PDF 添加图像
  17. 以 90 度为单位旋转 PDF
  18. 压缩 PDF 以减小文件大小(使用 OCRMyPDF)
  19. 添加和删除密码
  20. 设置 PDF 权限
  21. 添加水印
  22. 将任何常见文件转换为 PDF(使用 LibreOffice)
  23. 将 PDF 转换为 Word/Powerpoint/其他格式(使用 LibreOffice)
  24. 将 HTML 转换为 PDF
  25. 将 URL 转换为 PDF
  26. 从 PDF 中提取图像
  27. 从扫描中提取图像
  28. 添加页码
  29. 通过检测 PDF 头部文本自动重命名文件
  30. 对 PDF 进行 OCR(使用 OCRMyPDF)
  31. PDF/A 转换(使用 OCRMyPDF)
  32. 编辑元数据
  33. 支持暗黑模式
  34. 自定义下载选项
  35. 并行文件处理和下载
  36. 提供用于与外部脚本集成的 API
  37. 无论您是需要简单的 PDF 操作还是复杂的任务,Stirling PDF 都将满足您的需求。

使用步骤

1.下载和安装:首先,从GitHub下载 Stirling-PDF 的最新版本,并按照安装向导进行安装。
2.启动软件:安装完成后,启动 Stirling-PDF 软件。
3.选择操作:在软件界面上,选择您想要执行的操作,如合并、拆分、转换或加密。
4.选择文件:根据您选择的操作类型,选择相应的 PDF 文件。您可以通过点击"添加文件"按钮或将文件拖放到软件窗口中来选择文件。
5.配置参数:根据需要,配置合并、拆分、转换或加密的参数。例如,如果您选择转换功能,选择目标文件格式和保存位置。
6.执行操作:确认参数设置后,点击"开始"或"执行"按钮开始执行所选操作。
7.查看结果:操作完成后,您可以在软件界面或指定的目标文件夹中查看结果。

命令行安装

运行容器

docker run -d \
   --restart unless-stopped \
   --name spdf \
   -p 8077:8080 \
   frooodle/s-pdf

官方安装

docker run -d \
  -p 8080:8080 \
  -v /location/of/trainingData:/usr/share/tesseract-ocr/4.00/tessdata \
  -v /location/of/extraConfigs:/configs \
  -e DOCKER_ENABLE_SECURITY=false \
  --name stirling-pdf \
  frooodle/s-pdf:latest
  
  
  Can also add these for customisation but are not required
  
  -v /location/of/customFiles:/customFiles \

[button color="light" icon="" url="https://github.com/Frooodle/Stirling-PDF" type=""]源码[/button]

俄罗斯摄影师Georgy Chernyadyev 后期大神 最全教程免费分享

作者 cyril
2023年11月5日 12:22

简介

俄罗斯网红摄影师Georgy Chernyadyev(Георгий Чернядьев)善于拍摄人像,而他的作品都带有强烈的俄罗斯韵味。高饱和的色调,和油画般质感与日系人像有着鲜明的对比。正因为此,他在社交网络上也备受追捧。

此外,他的作品也都带有浓重的个人风格,摄影师多用16:9画幅来强调画面的故事性,而且对场景与主体之间的关系都处理的非常和谐。

Georgy Chernyadyev所拍摄的女性风格很多变,但无论是知性还是性感,优雅还是狂野,他都能将最美的一面挖掘并呈现在观众面前。

百度网盘经常抽风,我把Georgy的教程重新分享了一遍,需要的速度保存。

Lesson-02

链接:https://pan.baidu.com/s/1t-GsLSjp-jPFQXN-ph8-Eg?pwd=ophd

提取码:ophd

Lesson-10

链接:https://pan.baidu.com/s/1mfzzHqE_VZWfFyHsksIEkA?pwd=u9ti

提取码:u9ti

Lesson-13

链接:https://pan.baidu.com/s/1mVTQFYPoM3Y4fS2Qebm4Yw?pwd=m715

提取码:m715

Lesson-15

链接:https://pan.baidu.com/s/1Z0kVQDNFYsvjd5UavM7nQg?pwd=056w

提取码:056w

Lesson-20

链接:https://pan.baidu.com/s/1chOl1trfAcSTIJaPcDgv1A?pwd=lai3

提取码:lai3

Lesson-27

链接:https://pan.baidu.com/s/1ksXpek2NsoB5UURug2Grbg?pwd=e1ws

提取码:e1ws

Lesson-32

链接:https://pan.baidu.com/s/1YY4oROxcxCce6DYgEzPuyQ?pwd=ht48

提取码:ht48

Lesson-33

链接:https://pan.baidu.com/s/1-I7IXtoFmJNucE-ISGcSyQ?pwd=wzlf

提取码:wzlf

Lesson-34

链接:https://pan.baidu.com/s/1mfzzHqE_VZWfFyHsksIEkA?pwd=u9ti

提取码:u9ti

Lesson-35

链接:https://pan.baidu.com/s/1ET60A7G0BSUUCiQ0TRd0Ag?pwd=fhxu

提取码:fhxu

Lesson-36

链接:https://pan.baidu.com/s/1kOl6DV73abrUdcyOgKjcVQ?pwd=bm6t

提取码:bm6t

Lesson-44

链接:https://pan.baidu.com/s/1HT_7aI8XYlB1Fi7N0fAmKw?pwd=rcxw

提取码:rcxw

Lesson-49

链接:https://pan.baidu.com/s/1ESiNzqs4UfrfLc_refmT9w?pwd=8dna

提取码:8dna

Lesson-51

链接:https://pan.baidu.com/s/1uNatRW6bb8FjxEeQ0UsKFg?pwd=pxk6

提取码:pxk6

Lesson-57

链接:https://pan.baidu.com/s/1rFevTCKfQmUVUhPiDH0pZQ?pwd=nazh

提取码:nazh

Lesson-59

链接:https://pan.baidu.com/s/1aVtTlw4PY79AZefJJWzahA?pwd=t88p

提取码:t88p

Lesson-60

链接:https://pan.baidu.com/s/1YNpRfVLInToccbYHqz7pSQ?pwd=wge6

提取码:wge6

Lesson-64

链接:https://pan.baidu.com/s/19nf27Y0ODu0nx_meiaUCkQ?pwd=uftp

提取码:uftp

Lesson-66

链接:https://pan.baidu.com/s/1fXcHbZkA0y_zwihY4oGzKw?pwd=xuze

提取码:xuze

Iphone7 手机维修

作者 cyril
2023年11月2日 18:31

家里有一台iPhone7的手机电池鼓包了,一直闲置,就想着能不能自己买块电池装上去,维修好卖二手,就从淘宝花50买了块电池。
手机拆机内部图
手机本来已经被电池鼓包顶开了,全靠充电口处 的螺丝卡住,有一颗螺丝已经滑丝了,废了好大的劲才成功拆开。结果发现貌似摄像头排线也断了,淘宝询价,要30元,不知道二手能不能卖30了。
电池成功拆下
这个手机本就是买的京东二手机,现在已经把电池成功取出了,坐等淘宝电池到手安装,通电就可以测试这台手机是否能点亮了。


奸商,其他淘宝店问了一下,不到15元,包邮到家!!!

❌
❌