设计思路:
用jenkins持续集成维护docker的自动化部署服务,如果有新人使用,直接图形化界面一键部署环境,节约时间精力,另外每个人都有自己的docker(端口),可以分离git环境,切换git分支不影响别人。
补充: 好像有个k8s的工具可以控制扩展docker集群,后期可以考虑集成进去。
整体架构设计图:
1.下载jenkins 安装包 (https://jenkins.io/) 可以选docker直接启动,我这边用的原生的镜像(需要装java的支持组件)
2.安装java支持组件(centos举例)
yum search java | grep jdk
yum install java-1.8.0-openjdk
3.装docker(centos 7.0参考官方文档,需要梯子)
老版本的安装 yum install docker-io
没有梯子的同学参考https://blog.youkuaiyun.com/ghostyusheng/article/details/80321483 安装
debian同学 apt intall ...
4.找包(拿人家的包当做基础镜像,完善后打出来自己的镜像)
(1)考虑要装哪些服务(nginx ? php ? mysql ? memcache ? redis ? ......) -> 我是用php的 以这个为例
(2) docker search xxx (xxx 为你要搜的关键词)
(3)找到你心仪的镜像 借来用用
docker pull skiychan/nginx-php7
docker pull redis
docker pull bingozhou/mysql5.7
(心里面:谢谢老哥 提供牛逼的镜像)
5.打包 ( 打包就是把nginx / mysql打成你要的镜像,你拉下来的容器nginx是的配置文件都是那个啥 初始化的 没暖用)
(1)打包之前 先启动容器吧
docker run -itd --privileged \
--name zhangyusheng_php_nginx \
-v /home/zhangyusheng/code:/code \
-v /home/zhangyusheng/dev_conf:/root/dev_conf \
-p 8080:8080 \
skiychan/nginx-php7 /usr/sbin/init
docker run --name nn_mysql -itd -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root bingozhou/mysql5.7
docker run -itd --name nn_redis -p 6379:6379 redis
参数解释:
自己看docker run --help , 开个玩笑
-d 后台运行
-i 交互式
--privileged 开启最高权限(加上这个选项 不然docker里面内核修改不了会报错)
--name 容器起别名(如: zhangyusheng_php_nginx)
-v 目录映射 宿主机的 /home/zhangyusheng/code 映射到 虚拟机的 /code
-p 端口映射 宿主机的 8080 端口 映射到 虚拟机的 8080端口
skiychan/nginx-php7 镜像名
/usr/sbin/init 容器初始化加载的脚本?(反正也是开启个什么vip权限来的,不然修改内核权限不够??? 尽量加上吧 我是踩过坑才加的)
启动容器后 记得进入容器啊
docker exec -it zhangyusheng_php_nginx bash
(2) 开始打包 (以nginx为主 其他容器简单到过 逻辑不大一样)(这些操作在docker容器中做 , 别在宿主机瞎搞)
nginx 至少要把 配置文件自动化部署把
先找到nginx vhost目录做个软连接把
准备好你的配置文件
准备初始化shell脚本 保证nginx配置文件可以移动到正确的位置(sleep 10s 关键)
准备start.sh 的 shell脚本在容器启动的触发机制 (你肯定想到 /etc/rc.local 之类的骚操作,这对docker行不通!别问我怎么知道的 试了无数次)
配置supervisor 来达到触发的效果 (supervisor 小教程https://blog.youkuaiyun.com/ghostyusheng/article/details/80223784)
(3)容器做好了 总得试试脚本能不能用吧(重启容器测试效果)
命令行
exit; 回车退出容器 到宿主机
docker kill zhangyusheng_php_nginx
docker start zhangyusheng_php_nginx
然后进到容器检查下 start.sh是不是达到你需要的效果(对这个demo而言是否移动到vhost路径下了)
(4)真正意义上的打包(以php_nginx容器为例子)
在宿主机执行 docker commit skiychan/nginx-php7 nn_php_nginx:1.0 (第一个参数镜像名或者镜像hash?什么你不知道hash。。。 第二个参数你要打包后的镜像名 1.0代表tag 也可以是1.1 1.2 你懂得 镜像迭代)
(5) docker images
查看你自己打的包(以后docker run要用这个镜像启动啊 别搞错)
6. 宿主机的shell脚本+python脚本编写(说好的自动化 总不能让人手动 docker run 巴拉巴拉吧)
别问我shell为什么要配合py写 因为我shell写不好。。。
好吧 py也写的菜 凑合着看吧
run.sh
#!/bin/bash
#sh run.sh zhangyusheng
let port=`netstat -anp|grep tcp|awk -F " " '{print $4}'|awk -F":" '{print $4}'|sort -rn|head -n 1`
let qnn_port=${port}+1
let boss_port=${port}+2
let keep_port1=${port}+3
let keep_port2=${port}+4
let keep_port3=${port}+5
useradd -m -s /bin/bash $1
echo $1 | passwd --stdin $1
cp -r /home/zhangyusheng/code /home/$1/
mkdir /home/$1/dev_conf
python /root/init/run.py ${qnn_port} ${boss_port} /home/$1/dev_conf/
docker run -itd --privileged \
--name ${1}_php_nginx \
-v /home/$1/code:/code \
-v /home/$1/dev_conf:/root/dev_conf \
-p ${qnn_port}:${qnn_port} \
-p ${boss_port}:${boss_port} \
-p ${keep_port1}:${keep_port1} \
-p ${keep_port2}:${keep_port2} \
-p ${keep_port3}:${keep_port3} \
nn_php_nginx:1.2 /usr/sbin/init
echo ${qnn_port}
echo ${boss_port}
#!/usr/bin/env python
#-*- coding:utf8 -*-
#python conf.py 10003 10004
from sys import argv
boss_config_origin = """
server {
listen {2};
root /code/boss/public;
index index.php;
ssl on;
ssl_certificate /code/boss/data/cert/*.test.com.crt;
ssl_certificate_key /code/boss/data/cert/*.test.com.key;
ssl_client_certificate /code/boss/data/cert/ca.crt;
ssl_verify_client on;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers
ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES128-SHA:AES128-SHA:RC4-SHA;
ssl_session_cache shared:SSL:10m;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log off;
error_page 404 /index.php;
sendfile off;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_connect_timeout 30s;
fastcgi_read_timeout 30s;
fastcgi_send_timeout 60s;
fastcgi_ignore_client_abort on;
fastcgi_pass_header "X-Accel-Expires";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTP_REFERER $http_referer;
fastcgi_param VERIFIED $ssl_client_verify;
fastcgi_param SSL_CLIENT_S_DN $ssl_client_s_dn;
fastcgi_param SITE_ENV 'test';
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
"""
qnn_config_origin = """
server {
listen {1};
root "/code/web/public/";
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx_error.log;
sendfile off;
client_max_body_size 100m;
location ^~/mobile {
alias /code/h5/dist;
}
location ^~/que {
alias /code/qnn-vue;
add_header Cache-Control no-cache;
}
location = /mobile/index.html {
alias /code/h5/dist/index.html;
add_header Cache-Control no-cache;
}
location = /mobile/app.html {
alias /code/h5/dist/app.html;
add_header Cache-Control no-cache;
}
location = /mobile/active/enjoy/index.html {
alias /code/h5/dist/active/enjoy/index.html;
add_header Cache-Control no-store;
}
location ^~ /activity2/ {
alias /code/qnn-activity/dist/;
if ($document_uri ~* "index\.html") {
add_header Cache-Control no-cache,no-store;
}
}
location ^~/h5 {
alias /code/qnn-vue/dist;
}
location = /h5/index.html {
alias /code/qnn-vue/dist/index.html;
add_header Cache-Control no-cache;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /$document_root$fastcgi_script_name;
fastcgi_param SITE_ENV test;
fastcgi_intercept_errors off;
fastcgi_buffer_size 16k;
fastcgi_buffers 4 16k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
}
location ~ /\.ht {
deny all;
}
}
"""
qnn_config = qnn_config_origin.replace("{1}", argv[1])
boss_config = boss_config_origin.replace("{2}", argv[2])
def main():
path = argv[3]
fp = open (path + "boos.conf", "w")
fp.write(boss_config);
fp = open (path + "qnn.conf", "w")
fp.write(qnn_config);
if __name__ == '__main__':
main()
脚本解析:
1). 拿到当前最大的端口 port (往上增 映射端口的时候就不会冲突了)
2). 创建 用户 账号密码一样
3).准备好 nginx配置文件(docker 做 目录映射,docker内部就可以拿到了)
4).复制代码目录到每个人自己的根目录下
5).模拟执行docker run 操作
7. sh run.sh zhangyusheng2 (看下效果 docker自动启动了没 环境部署起来没)
8. jenkins 触发shell脚本
还记得第一步下好的jenkins.war吗
java -jar jenkins.war --httpPort=8080 用8080启动下 然后下一步下一步下一步。。。
9.创建一个jenkins job
主要有两个点
第一个 参数化构建 (这里如果选择默认安装是没这个插件的 你需要在“系统管理” “插件管理” 搜索参数化插件并安装)
第二个
参数化插件:
10.开始构建