2020年5月

最常见的CD方法是金丝雀和蓝绿部署。

进行蓝绿部署期间,IT会与当前版本一起部署一个新的组件或应用程序版本。新版本(绿)被部署到生产中并对其进行测试,与此同时当前版本(蓝)依旧可以使用。如果新版本的代码运行良好,那么所有用户将会切换到新版本中。

金丝雀部署也有两个版本:当前版本和更新版本。IT开始将一小部分用户请求路由到新版本。代码和用户的行为会被持续监控。如果错误率或用户投诉并没有增加,则路由到新版本的请求份额将逐渐增加(例如,1%、10%、50%最后到100%)。一旦所有请求都发送到新版本中,那么旧版本就会自动退休或删除。

docker本质就是宿主机的一个进程,docker是通过namespace实现资源隔离,通过cgroup实现资源限制,通过写时复制技术(copy-on-write)实现了高效的文件操作(类似虚拟机的磁盘比如分配500g并不是实际占用物理磁盘500g)
1)namespaces 名称空间
19895418-0f820d7b1324d4d5.jpg
2)control Group 控制组cgroup的特点是:
cgroup的api以一个伪文件系统的实现方式,用户的程序可以通过文件系统实现cgroup的组件管理
cgroup的组件管理操作单元可以细粒度到线程级别,另外用户可以创建和销毁cgroup,从而实现资源载分配和再利用
所有资源管理的功能都以子系统的方式实现,接口统一子任务创建之初与其父任务处于同一个cgroup的控制组

四大功能:
资源限制:可以对任务使用的资源总额进行限制
优先级分配:通过分配的cpu时间片数量以及磁盘IO带宽大小,实际上相当于控制了任务运行优先级
资源统计:可以统计系统的资源使用量,如cpu时长,内存用量等
任务控制:cgroup可以对任务执行挂起、恢复等操作

nginx

docker pull nginx

docker run --name nginx -p 8081:80 -d nginx

mkdir -p ~/docker-data/nginx/www ~/docker-data/nginx/logs ~/docker-data/nginx/conf

拷贝容器内 Nginx 默认配置文件到本地当前目录下的 conf 目录,容器 ID 可以查看 docker ps 命令输入中的第一列:

执行docker cp执行将本地主机的index.html复制到docker容器中。

docker cp 本地主机文件路径 nginx容器id://usr/share/nginx/html
docker cp nginx容器id://usr/share/nginx/html/index.html 本地主机文件路径

docker cp <容器id>:/etc/nginx/nginx.conf ~/docker-data/nginx/conf

www: 目录将映射为 nginx 容器配置的虚拟目录。

logs: 目录将映射为 nginx 容器的日志目录。

conf: 目录里的配置文件将映射为 nginx 容器的配置文件。

docker run -d -p 8082:80 --name nginx-web -v ~/docker-data/nginx/www:/usr/share/nginx/html -v ~/docker-data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf -v ~/docker-data/nginx/logs:/var/log/nginx nginx

docker exec -it nginx-web bash

如果要重新载入 NGINX 可以使用以下命令发送 HUP 信号到容器:

docker kill -s HUP container-name

重启 NGINX 容器命令:

docker restart container-name

Redis

docker search redis
docker pull redis
docker run --name redis -d -p 6339:6339 redis
docker run -p 6379:6379 -v $PWD/data:/data -d redis redis-server --appendonly yes
docker run --name redis-6379 -p 6379:6379 -v $PWD/data:/data -d --restart=always redis redis-server --appendonly yes --requirepass "123456"

-p 6379:6379 : 将容器内端口映射到宿主机端口(右边映射到左边)

-v /data/docker/redis/data:/data : 将主机中当前目录下的data挂载到容器的/data

redis-server –appendonly yes : 在容器执行redis-server启动命令,并打开redis持久化配置

requirepass “your passwd” : 设置认证密码

–restart=always : 随 docker 启动而启动

–restart=unless-stopped : 如果容器正常 stopped,然后机器重启或 docker 服务重启,这种情况下容器将不会被 restart。

docker exec -it e55caa redis-cli
docker exec -it e55caa redis-cli -a <密码>

keys *
keys auth.*
get auth.userid.203
set key "value"

auth "yourpassword"

MongoDB

docker pull mongo

docker run --name mongo -p 27017:27017 -v ~/docker-data/mongo:/data/lib -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=admin -d mongo

docker exec -it mongo bash
mongo -u admin -p admin

help

show dbs

use springbucks
db.createUser(

{
    user: "springbucks",
    pwd: "springbucks",
    roles: [
        { role: "readWrite", db: "springbucks" }
    ]
}

)

show users

Mysql

docker pull mysql

docker run --name mysql -d -p 3306:3306 -v ~/docker-data/mysql:/var/lib/mysql -e MYSQL_DATABASE=springbucks -e MYSQL_USER=springbucks -e MYSQL_PASSWORD=springbucks -e MYSQL_ROOT_PASSWORD=root_password mysql

docker run --name mysql -d -p 3306:3306 -v ~/docker-data/mysql:/var/lib/mysql -e MYSQL_DATABASE=ssms -e MYSQL_USER=root -e MYSQL_PASSWORD=root -e MYSQL_ROOT_PASSWORD=root mysql

docker exec -it mysql bash
mysql -h localhost -P 3306 -u springbucks -p

show databases;
use springbucks;
show tables;

修改密码

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root账户密码';

常用命令

导出整个数据库

mysqldump -u 用户名 -p –default-character-set=latin1 数据库名 > 导出的文件名(数据库默认编码是latin1)
mysqldump -u root -p test > test.sql

导出一个表

mysqldump -u 用户名 -p 数据库名 表名> 导出的文件名
mysqldump -u root -p test users> test_users.sql

导出一个数据库结构

mysqldump -u root -p -d –add-drop-table test >d:test.sql

-d 没有数据 –add-drop-table 在每个create语句之前增加一个drop table

导入数据库

1. source 导入数据

source test.sql

2. 使用mysqldump命令

mysqldump -u username -p dbname < filename.sql

3. 使用mysql命令

mysql -u username -p -D dbname < filename.sql

库操作

创建数据库

命令:create database <数据库名>

create database test;

显示所有的数据库

命令:show databases (注意:最后有个s)

删除数据库

命令:drop database <数据库名>

连接数据库

命令:use <数据库名>

查看当前使用的数据库

select database();

当前数据库包含的表信息:

show tables; (注意:最后有个s)

表操作

命令:create table <表名> ( <字段名> <类型> [,..<字段名n> <类型n>]);

mysql> create table MyClass(

id int(4) not null primary key auto_increment,
name char(20) not null,
sex int(4) not null default ’′,
degree double(16,2));

获取表结构

命令:desc 表名,或者show columns from 表名

DESCRIBE MyClass
desc MyClass;
show columns from MyClass;

删除表

命令:drop table <表名>

rabbitmq

docker pull rabbitmq

docker pull rabbitmq:3.7-management # 一般用这个

docker run --name rabbitmq -d -p5672:5672 -p 15671:15672 -e RABBITMQ_DEFAULT_USER=spring -e RABBITMQ_DEFAULT_PASS=spring rabbitmq:3.7-management

gitlab

docker pull gitlab/gitlab-ce

docker run --detach \
--hostname gitlab.example.com \
--publish 22443:443 --publish 20280:80 --publish 20222:22 \
--name gitlab \
--restart always \
--volume ~/docker-data/gitlab/config:/etc/gitlab \
--volume ~/docker-data/gitlab/logs:/var/log/gitlab \
--volume ~/docker-data/gitlab/data:/var/opt/gitlab \
gitlab/gitlab-ce:latest

逐行解释

1. 后台运行

2. 设置主机名或域名

3. 本地端口的映射

4. gitlab-ce 的镜像运行成为一个容器,这里是对容器的命名

5. 设置重启方式,always 代表一直开启,服务器开机后也会自动开启的

6. 将 gitlab 的配置文件目录映射到 ~/docker-data/gitlab/config 目录中

7. 将 gitlab 的log文件目录映射到 ~/docker-data/gitlab/logs 目录中

8. 将 gitlab 的数据文件目录映射到 ~/docker-data/gitlab/data 目录中

9. 需要运行的镜像

查看容器列表

docker container ls

查看系统 ip

ip addr

打开 gitlab

http://xxx:20280

设置密码

用 root 登录

swarm docker-compose.yml

version: "3"

services:
gitlab:

image: 'gitlab/gitlab-ce:latest'
ports:
  - '20280:80'
  - '22443:443'
  - '20222:22'
volumes:
  - /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
  - /etc/timezone:/etc/timezone:ro
  - '~/docker-data/gitlab/config:/etc/gitlab'
  - '~/docker-data/gitlab/logs:/var/log/gitlab'
  - '~/docker-data/gitlab/data:/var/opt/gitlab'
deploy:
  restart_policy:
    condition: on-failure
    delay: 5s
    max_attempts: 3
  resources:
    limits:
      cpus: "2"
      memory: 2048M
logging:
  driver: "json-file"
  options:
    max-size: "20m"
    max-file: "2"

docker-compose.yml

version: "2.2"

services:
gitlab-web:

image: 'gitlab/gitlab-ce:latest'
restart: always
hostname: 'gitlab.example.com'
environment:
  GITLAB_OMNIBUS_CONFIG: |
    external_url 'https://gitlab.example.com'
    # Add any other gitlab.rb configuration here, each on its own line
ports:
  - '80:80'
  - '443:443'
  - '22:22'
volumes:
  - '/srv/gitlab/config:/etc/gitlab'
  - '/srv/gitlab/logs:/var/log/gitlab'
  - '/srv/gitlab/data:/var/opt/gitlab'
cpus: '0.5'
mem_limit: 2048m

jenkins

docker pull jenkins/jenkins

docker run -d -p 8090:8080 -p 50000:50000 -v ~/docker-data/jenkins:/var/jenkins_home --name jenkins jenkins/jenkins

-p 8090:8080 将镜像的8080端口映射到服务器的8090端口

-p 50000:50000 将镜像的50000端口映射到服务器的50000端口

-v jenkins:/var/jenkins_home jenkins_home目录为jenkins工作目录,我们将硬盘上的一个目录挂载到这个位置,方便后续更新镜像后继续使用原来的工作目录。

-v /etc/localtime:/etc/localtime 让容器使用和服务器同样的时间设置。

--name jenkins 给容器起一个别名

获取密码

docker exec jenkins tail /var/jenkins_home/secrets/initialAdminPassword

可能遇到的问题

1. touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied

Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?

需要修改下目录权限, 因为当映射本地数据卷时,~/docker-data/jenkins目录的拥有者为root用户,而容器中jenkins user的uid为1000

执行如下命令即可:

chown -R 1000:1000 ~/docker-data/jenkins

2. 如果一直在 Please wait while Jenkins is getting ready to work ..., 是网络问题,需要添加国内镜像

需要你进入jenkins的工作目录,打开

vi ~/docker-data/jenkins/hudson.model.UpdateCenter.xml

https://updates.jenkins.io/update-center.json 改成 http://mirror.xmission.com/jenkins/updates/update-center.json

其他镜像源

1. 清华大学 https://mirrors.tuna.tsinghua.edu.cn/jenkins/

2. 华为 https://mirrors.huaweicloud.com/jenkins/

3. 腾讯云 https://mirrors.cloud.tencent.com/jenkins/

4. 北京理工大 http://mirror.bit.edu.cn/jenkins/

5. USTC http://mirrors.ustc.edu.cn/jenkins/

registry

docker image 私有仓库

建议使用 harbor 或 Nexus3 搭建私有仓库

docker-register-web

docker pull joxit/docker-registry-ui

docker pull registry

docker run -d -p 5000:5000 --restart always --name registry registry:2

docker run -d -p 5000:5000 --restart=always --name registry registry

docker run -d \

-p 5000:5000 \
-v /opt/data/registry:/var/lib/registry \
registry

推送本地仓库

docker tag IMAGE[:TAG] [REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]。

使用 docker tag 将 ubuntu:latest 这个镜像标记为 127.0.0.1:5000/ubuntu:latest

docker tag ubuntu:latest 127.0.0.1:5000/ubuntu:latest
docker push 127.0.0.1:5000/ubuntu:latest

用 curl 查看仓库中的镜像。

curl 127.0.0.1:5000/v2/_catalog

注意

如果你不想使用 127.0.0.1:5000 作为仓库地址,比如想让本网段的其他主机也能把镜像推送到私有仓库。

你就得把例如 192.168.199.100:5000 这样的内网地址作为私有仓库地址,这时你会发现无法成功推送镜像。

这是因为 Docker 默认不允许非 HTTPS 方式推送镜像。我们可以通过 Docker 的配置选项来取消这个限制,或者查看下一节配置能够通过 HTTPS 访问的私有仓库。

对于使用 systemd 的系统,请在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件)

{
"registry-mirror": [

"https://registry.docker-cn.com"

],
"insecure-registries": [

"192.168.199.100:5000"

]
}

svn

docker pull garethflowers/svn-server

docker run \

--name svn-server \
--detach \
--volume /home/svn:/var/opt/svn \
--publish 3690:3690 \
garethflowers/svn-server

创建新仓库

docker exec -it svn-server svnadmin create repo

当前仓库下

!!!注意!!!配置文件不要注释!!!

!!!注意!!!配置文件不要注释!!!

!!!注意!!!配置文件不要注释!!!

资源仓库配置,修改 conf/svnserve.conf

vim conf/svnserve.conf

[general]
anon-access=none # 匿名用户不可读写,也可设置为只读 read
auth-access=write # 授权用户可读可写
password-db=passwd # 密码文件路径,相对于当前目录
authz-db=authz # 访问控制文件
realm=/var/opt/svn/repo # 认证命名空间,会在认证提示界面显示,并作为凭证缓存的关键字,可以写仓库名称比如repo

realm=repo

配置账号与密码,修改 conf/passwd 文件,格式为“账号 = 密码”

[users]

harry = harryssecret

sally = sallyssecret

admin=123456

配置账户权限,修改 conf/authz 文件

[groups]
owner=admin

[/] # / 表示所有仓库
admin=rw # 用户 admin 在所有仓库拥有读写权限

[repo:/] # 表示以下用户在仓库 svn 的所有目录有相应权限
@owner=rw # 表示 owner 组下的用户拥有读写权限

防火墙开放端口

firewall-cmd --zone=public --add-port=3690/tcp --permanent
firewall-cmd --reload

重启 svn-server

docker restart svn-server

常用命令

检出仓库

svn checkout svn://localhost:3690/repo --username admin

svn checkout svn://localhost:3690/repo /Users/leo/repo --username admin

svn co svn://localhost/repo --username admin --password 123456

提交文件

echo abc > test.txt
svn add test.txt
svn commit -m 'test'

查看仓库中的文件

svn list test.txt

还原文件

svn revert test.txt

docker-compose.yml

version: "2.2"

services:
svn:

image: 'garethflowers/svn-server:latest'
restart: unless-stopped
ports:
  - '3690:3690'
volumes:
  - /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
  - /etc/timezone:/etc/timezone:ro
  - '/mnt/docker-data/svn/home:/var/opt/svn'
cpus: '1'
mem_limit: 1024m
logging:
  driver: "json-file"
  options:
    max-size: "20m"
    max-file: "2"

nginx-proxy

自动化 Nginx 反向代理 Docker, nginx-proxy 启动一个容器来运行 nginx 和 docker-gen。 在主机上的容器启动和停止时 docker-gen 会生成 nginx 反向代理配置并且重新加载 nginx。

version: '2'

services:
nginx-proxy:

image: jwilder/nginx-proxy
ports:
  - "80:80"
volumes:
  - /var/run/docker.sock:/tmp/docker.sock:ro

whoami:

image: jwilder/whoami
environment:
  # - VIRTUAL_HOST=whoami.local # 定义访问改容器的域名
  - VIRTUAL_HOST=xinlichao.cn,www.xinlichao.cn
  - VIRTUAL_PORT=8000

curl -H "Host: whoami.local" localhost

指令 解释
FROM FROM debian:stretch 表示以 debian:stretch 作为基础镜像进行构建
RUN RUN 后面跟的就是一些 shell 命令,通过&&将这些脚本连接在了一行执行,这么做的原因是为了减少镜像的层数
ENV 设置环境变量
ARG 和 ENV 的效果一样,都是设置环境变量。ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量
COPY 复制文件,COPY [–chown=:] <源路径>… <目标路径>
ADD 跟 COPY 性质一样,ADD 支持 URL,自动解压 tar 等压缩文件
CMD 指定默认的容器主进程的启动命令, CMD [“nginx”, “-g”, “daemon off;”]
ENTRYPOINT 一个 Dockerfile 只能有一个 ENTRYPOINT,跟 CMD 区别是 ENTRYPOINT 可以指定参数
VOLUME 定义匿名卷, 容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中
EXPOSE 声明端口, EXPOSE <端口 1> [<端口 2>…]
WORKDIR 指定 RUN 工作目录, WORKDIR <工作目录路径>

优化
编写 .dockerignore 文件排除不需要的文件和目录。
容器只运行单个应用。
使用 Docker Compose 运行多个 Docker 容器。
将多个 RUN 指令合并为一个。
Docker 镜像是分层的;
Dockerfile 中的每个指令都会创建一个新的镜像层;
镜像层将被缓存和复用;
当 Dockerfile 的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效;
某一层的镜像缓存失效之后,它之后的镜像层缓存都会失效;
镜像层是不可变的,如果我们再某一层中添加一个文件,然后在下一层中删除它,则镜像中依然会包含该文件(只是这个文件在 Docker 容器中不可见了);
Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层。

全量备份使用 mysqldump 工具

直接上脚本:

!/bin/bash

在使用之前,请提前创建以下各个目录

db_user="root"
db_passwd="123456"
db_host="192.168.1.101"
db_prod="3306"
db_name="test"
backup_dir="/home/leo/backup/bakmysql"
backup_old_dir="/home/leo/backup/bakmysqlold"

echo $backup_old_dir

进入备份目录将之前的移动到 old 目录

cd "$backup_dir"
echo "you are in bakmysql directory now"
mv $db_name* "$backup_old_dir"
echo "Old databases are moved to bakmysqlold folder"

时间格式

time=$(date +"%Y-%m-%d")

mysql 备份的命令,注意有空格和没有空格

mysqldump -h$db_host -P$db_prod -u$db_user -p$db_passwd --single-transaction --flush-logs $db_name | gzip >"$backup_dir/$db_name"-"$time.sql.gz"
echo "your database backup successfully completed"

这里将 7 天之前的备份文件删掉

SevenDays=$(date -d -7day +"%Y-%m-%d")
if [ -f "$backup_old_dir/$db_name-$SevenDays.sql.gz" ]; then
rm -rf "$backup_old_dir/$db_name-$SevenDays.sql.gz"
echo "you have delete 7days ago bak sql file "
else
echo "7days ago bak sql file not exist "
echo "bash complete"
fi
通过下面命令将脚本加入系统的计划任务:

分钟 小时 天 月 星期几

每天01点10分执行备份

crontab -e
10 01 * /usr/bin/bash /home/leo/backup/bakmysql.sh

保存后 crontab 会自动加载配置

增量备份 binlog

增量备份主要用到的是binlog, 需要开启 mysql binlog:

开启 binlog

vim /var/lib/mysql/mysql.conf.d/mysqld.cnf

[mysqld] 下添加:

[mysqld]
log_bin=mysql-bin
log_bin_index=mysql-bin.index
binlog_do_db=test
binlog_ignore_db=mysql

log 3天自动删除

expire_logs_days=3
备份脚本:

!/bin/bash

在使用之前,请提前创建以下各个目录

backupDir="/home/leo/backup/bakmysql"

增量备份时复制mysql-bin.00000*的目标目录,提前手动创建这个目录

mysqlDir="/var/lib/mysql"

mysql的数据目录

logFile="/home/leo/backup/bakmysql/bak.log"

mysql的index文件路径,放在数据目录下的

binFile="/var/lib/mysql/mysql-bin.index"

这个是用于产生新的 mysql-bin.00000* 文件

mysqladmin -uroot -p123456 flush-logs

wc -l 统计行数

awk 简单来说 awk 就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

counter=$(wc -l $binFile | awk '{print $1}')
nextNum=0

这个 for 循环用于比对 $counter , $nextNum 这两个值来确定文件是不是存在或最新的

for file in $(cat $binFile); do

base=$(basename $file)
echo $base
#basename用于截取mysql-bin.00000*文件名,去掉./mysql-bin.000005前面的./
nextNum=$(expr $nextNum + 1)
if [ $nextNum -eq $counter ]; then
    echo $base skip! >>$logFile
else
    dest=$backupDir/$base
    if (test -e $dest); then #test -e用于检测目标文件是否存在,存在就写exist!到$logFile去
        echo $base exist! >>$logFile
    else
        cp $mysqlDir/$base $backupDir
        echo $base copying >>$logFile
    fi
fi

done
echo $(date +"%Y年%m月%d日 %H:%M:%S") $Next Bakup succ! >>$logFile
通过下面命令将脚本加入系统的计划任务:

分钟 小时 天 月 星期几

每两个小时执行备份

crontab -e
0 /2 /home/leo/backup/mysqlIncreBackup.sh

保存后 crontab 会自动加载配置

数据恢复

恢复整个db

gzip < db1.sql.gz | mysql -uroot -p123456
binlog 数据恢复需要用到 mysqlbinlog 工具,由于 binlog 记录的是 sql 的所有操作,请按 mysql-bin.index 顺序恢复

恢复增量备份

mysqlbinlog mysql-bin.0000xx | mysql -u用户名 -p密码 数据库名

清理备份脚本

!/bin/bash

删除备份文件

Started on 2019/11/8 Leo <xinlichao2016@gmail.com>

Last update 2019/11/8 Leo <xinlichao2016@gmail.com>

BAKINCRE_PATH=/home/leo/mysqlbackup/bakincre

删除7天前文件

find ${BAKINCRE_PATH} -mtime +7 -type f -name "." | xargs rm -f

通过下面命令将脚步加入系统的计划任务

crontab -e

分钟 小时 天 月 星期几

每天01点30分执行

crontab -e

30 01 * /usr/bin/bash /home/leo/scripts/clearBakMysql.sh >> /dev/null 2>&1