初創公司利用Docker持續集成部署
來自:http://dockone.io/article/671
Docker技術炙手可熱,但是對于初創企業如何利用Docker這門新技術來解決內網開發或者測試環境的快速部署,解放運維并提高工作效率,尤其在創業 之初人力資源不足的情況下,更為重要。為此我和公司一位開發同學一起研究的關于Docker快速部署應用的解決方案架構,下面是整個方案部署的步驟,由于 資源有限過程中有問題還望大家指正交流,謝謝!
架構圖
部署說明:
注意:
1. 平臺部署以虛擬機為基礎,除DNS服務器系統為Centos6.5之外,所有虛擬機系統為Centos7.0。
2. VM系統需要設置selinux為允許或者關閉,以及關閉默認系統防火墻。
安裝過程:(dns-registry-zk-mesos-marathon-consul-nginx-consul-template)
1)安裝docker軟件,部署說明中需要docker環境的都需要先安裝軟件,命令如下:systemctl stop firewalld;systemctl disable firewalld setenforce 0 sed -i s/^SELINUX=enforcing/SELINUX=permissive/ /etc/selinux/config #設置Selinux為允許或者直接關閉。 yum install docker -y vi /etc/sysconfig/docker OPTIONS='--selinux-enabled --insecure-registry docker.smart.com' #添加docker倉庫信任 systemctl start docker #啟動docker服務
2)配置DNS解析smart.com區域文件
DNS服務器配置過程略。
192.168.10.200 docker.smart.com #解析倉庫域名服務器 echo nameserver 192.168.10.86 >>/etc/resolv.conf #修改所有服務器域名服務器地址
3)配置Docker倉庫
/data/docker/registry #創建docker運行映射目錄 docker pull index.alauda.cn/juqkai/registry #靈雀云拉一個倉庫鏡像 docker tag index.alauda.cn/juqkai/registry docker.smart.com/base/registry #修改標簽 docker run -d --restart=always -p 80:5000 -v /data/docker/registry:/tmp/registry-dev docker.smart.com/juqkai/registry #運行registry服務 docker push docker.smart.com/base/registry #將本地鏡像推送到倉庫 curl http://docker.smart.com/v1/search #查看倉庫中的相關鏡像(可以使用python json模塊轉換| python -m json.tool) (可以按照此方法將Jenkins、nginx、zookeeper等鏡像拉下來并推送到docker.smart.com倉庫)
4)配置zookeeper
mkdir /data/docker/zookeeper/conf -p #創建配置文件映射目錄(統一將docker運行的軟件配置文件放到這個目錄)
5)配置mesos-master和mesos-slave
- cat /data/docker/zookeeper/conf/zoo.cfg
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/tmp/zookeeper clientPort=2181 server.1=0.0.0.0:2888:3888 server.2=zk2.paas.smart.com:2888:3888 server.3=zk3.paas.smart.com:2888:3888- /data/docker/zookeeper/data/myid
echo "1" > /data/docker/zookeeper/data/myid- 如果myid與zoo.cfg配置文件中的server.x相同則后邊只能寫0.0.0.0,2888為zk通訊端口,3888為選舉端口,這里3個zk組成一個集群。
rpm -i http://repos.mesosphere.io/el/7/noarch/RPMS/mesosphere-el-repo-7-1.noarch.rpm yum -y install mesos mesos-master --ip=192.168.10.203 --hostname=master1.paas.smart.com --work_dir=/var/lib/mesos --quorum=1 --log_dir=/var/log/mesos --port=5050 --zk_session_timeout=120secs --zk=zk://zk1.paas.smart.com:2181,zk2.paas.smart.com:2181,zk3.paas.smart.com:2181/mesos #啟動master
- 這里--ip為本機 --hostname也為本機主機名 --quorum做為有效果結點數,值為(N+1) / 2,N是master節點數,配置log_dir主要是為了查看mesos日志。
mesos-slave --ip=192.168.10.136 --hostname=192.168.10.136 --log_dir=/var/log/mesos --containerizers=docker,mesos --master=zk://zk1.paas.smart.com:2181,zk2.paas.smart.com:2181,zk3.paas.smart.com:2181/mesos --executor_registration_timeout=5mins #啟動slave 首次啟動均在前臺,沒有問題可以使用nohup放到后臺。
6)配置marathon平臺
- ip每個主機取值不相同 hostname默認會是主機名,但很多情況不能訪問,所以使用主機IP
如果要在WEB UI上看到日志,需要配置log_dir屬性
executor_registration_timeout容器執行的超時時間,如果docker pull的時候非常耗時,可能會導致這里超時.
7)配置consul集群
- marathon平臺需要依賴mesos相關庫文件和java環境所以需要安裝mesos和java
rpm -i http://repos.mesosphere.io/el/7/noarch/RPMS/mesosphere-el-repo-7-1.noarch.rpm yum -y install mesos marathon java- 需要配置環境變量
echo "export LIBPROCESS_IP=192.168.10.124" >> /etc/profile source /etc/profile #IP為本機的IP地址 bin/start --master zk://zk1.paas.smart.com:2181,zk2.paas.smart.com:2181,zk3.paas.smart.com:2181/mesos --zk zk://zk1.paas.smart.com:2181,zk2.paas.smart.com:2181,zk3.paas.smart.com:2181/marathon --hostname 192.168.10.124 --framework_name smart #啟動服務,hostname為主機IP或本機主機名
8)nginx配置
- 需要部署consul的節點,mesos-master和mesos-slave
#將consul可執行文件放到/usr/bin目錄下 mkdir /usr/local/consul/conf #創建consul配置文件目錄 cat /usr/local/consul/conf/config.conf { "datacenter": "diliPAAS" ,"data_dir": "/usr/local/consul/data" ,"log_level": "INFO" ,"node_name": "master1" ,"server": true ,"retry_join":["192.168.10.210","192.168.10.184","192.168.10.152","192.168.10.136"] ,"rejoin_after_leave":true ,"client_addr":"192.168.10.203" } #retry_join IP為各個consul節點的IP,client_addr為本機IP地址,server為工作模式。 consul agent -node=master1 -server -bootstrap -data-dir=/usr/local/consul/data -dc=diliPAAS #前臺首次啟動命令,需要指定consul相關數據存放目錄,當啟動其他consul之后可以使用如下命令啟動 nohup consul agent -config-file=config.conf >consul.out& consul members -rpc-addr=192.168.10.210:8400 #查看consul集群情況,其中rpc-addr為任意節點consul IP.
9.配置consul-template來動態發現注冊服務。
- 因為我們的nginx和DNS配置是通過consul-template生成配置文件的,我們先把nginx起來然后配置consul-template通過模板生成最新的配置文件。
mkdir /data/docker/nginx/conf/ #創建nginx配置映射目錄,ssl等文件也放在這個目錄 docker run -d --name nginx -p 80:80 -v /data/docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf index.alauda.cn/library/nginx #從靈雀云拉的鏡像運行,如果之前拉過并push到倉庫,可以從我們之前放到docker.smart.com倉庫中拉去。
- 配置nginx的服務發現和注冊
cat /data/docker/nginx/conf/nginx.conf.tmpl #nginx配置模板文件 {{$model:="test"}} worker_processes 1; events { worker_connections 65535; } http { #lua_code_cache off; client_max_body_size 1G; server_names_hash_bucket_size 64; upstream marathon { server 192.168.10.186:8080; server 192.168.10.124:8080; } server { server_name marathon1.paas.smart.com; listen 80; location / { proxy_pass http://marathon; } } upstream registry { server 192.168.10.200:80; } server { server_name docker.smart.com; listen 80; location / { proxy_pass http://registry; } }############################loop
{{range services}} {{$nameArr := .Name | split "-"}} {{if gt (len $nameArr) 1}} {{if eq $model (index $nameArr 1)}} {{$name := (index $nameArr 0)}} {{if service .Name }} upstream {{.Name}} { {{range service .Name}} server {{.Address}}:{{.Port}};#{{range .Tags}}{{.}},{{end}}{{end}} } server { server_name {{$name}}.smart.com; listen 80; location / { proxy_pass http://{{.Name}}; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; } } {{if eq $name "passport"}} upstream {{.Name}}ssl { {{range service .Name}} server {{.Address}}:{{.Port}};{{end}} } server { server_name {{$name}}.smart.com; listen 443; ssl on; ssl_certificate smart_server.pem; ssl_certificate_key smart_server.key; ssl_session_timeout 5m; ssl_protocols SSLv2 SSLv3 TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers RC4:HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { proxy_pass http://{{.Name}}ssl; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; } } {{end}} {{end}} {{end}} {{end}} {{end}} } #nginx配置文件模板文件內容 mkdir -p /usr/local/consul-template/ #創建consul-template 配置文件目錄 cat nginx.tmpl.conf consul="192.168.10.203:8500" template { source="/data/docker/nginx/conf/nginx.conf.tmpl" destination="/data/docker/nginx/conf/nginx.conf" command="docker exec nginx nginx -s reload >> /dev/null" } #其中consul中的IP為mesos-master nohup consul-template -config=./nginx.tmpl.conf & #啟動consul-template更新nginx服務
- 配置DNS的consul-template服務
cat /var/named/smart.com.zone.tmp #DNS區域文件模板 {{$model:="test"}} $TTL 1D @ IN SOA @ rname.invalid. ( 0 ; serial 1D ; refresh 1H ; retry 1W ; expire 3H ) ; minimum NS @ A 127.0.0.1 AAAA ::1 @ IN NS ns.smart.com. {{$ips:=file "/var/named/smart.json" |parseJSON}} {{range services}} {{$nameArr := .Name | split "-"}} {{if gt (len $nameArr) 1}} {{if eq $model (index $nameArr 1)}} {{$name := (index $nameArr 0)}} {{$name}} IN A 192.168.10.177 {{end}} {{end}} {{end}} {{range $k,$v := $ips}}{{$kn := $k|regexReplaceAll "$" "-"|regexReplaceAll "$" $model}}{{$sk := service $kn}}{{$l:=len $sk}}{{if $l}}{{else}} {{$k}} IN A {{$v}}{{end}}{{end}} #由于系統需要調用外部資源所以增加外部固定資源DNS A記錄 smart.json cat /var/named/smart.json { "ns":"192.168.10.86" ,"zk1.paas":"192.168.10.160" ,"zk2.paas":"192.168.10.150" ,"zk3.paas":"192.168.10.209" ,"master1.paas":"192.168.10.203" ,"master2.paas":"192.168.10.210" ,"docker":"192.168.10.200" ,"cms":"192.168.6.54" ,"supplier":"192.168.6.54" ,"user":"192.168.6.54" ,"www":"192.168.6.54" ,"manweb":"192.168.6.54" ,"passport":"192.168.6.54" ,"authcode":"192.168.6.54" ,"shop":"192.168.6.54" ,"manage":"192.168.6.54" ,"upload":"192.168.6.53" ,"chat":"192.168.6.53" ,"csc":"192.168.6.53" ,"titan":"192.168.6.53" ,"orders":"192.168.6.53" ,"static":"192.168.6.53" "smart.json" 51L, 1157C ,"mapi.pay":"192.168.6.53" ,"pay2":"192.168.6.53" ,"sso":"192.168.6.54" ,"group-admin":"192.168.6.54" ,"group":"192.168.6.54" ,"group-orders":"192.168.6.54" ,"img0":"192.168.6.153" ,"img1":"192.168.6.153" ,"img2":"192.168.6.153" ,"img3":"192.168.6.153" ,"img4":"192.168.6.153" ,"img5":"192.168.6.153" ,"img6":"192.168.6.153" ,"img7":"192.168.6.153" ,"img8":"192.168.6.153" ,"img9":"192.168.6.153" ,"cashier.pay":"192.168.6.53" ,"schedule":"192.168.4.14" ,"dp":"192.168.4.211" ,"apd":"192.168.6.54" ,"marathon":"192.168.10.177" ,"jenkins":"192.168.10.161" ,"leader.paas":"192.168.10.177" } #添加consul-template更新DNS的配置文件 cat /usr/local/consul-template/bind.conf consul="192.168.10.184:8500" template { source="/var/named/smart.com.zone.tmp" destination="/var/named/smart.com.zone" command="chown root.named /var/named/smart*;/etc/init.d/named restart" } nohup consul-template -config=./bind.conf >dns.out & #運行DNS的consul-template服務
10)配置Jenkins
- jenkins服務提供拉取代碼并本地編譯然后推送到Docker Build服務器。
docker run -it --rm -p 80:8080 -v /data/docker/jenkins:/var/jenkins_home -v /data/docker/jenkins/maven:/home/anonymous/.m2 docker.smart.com/base/jenkins cat /data/docker/jenkins/upload_file #jenkins 編譯完成之后推送腳本 #!/bin/bash dcpu=${cpu:="0.4"} dmem=${mem:="512"} dins=${ins:="1"} model="test" #sysName="www" #BUILD_NUMBER="1" #sysDir="/data/docker/jenkins/workspace/www/diligrp-website-web/target/diligrp-website-web" sysName=${JOB_NAME} HOST=root@192.168.10.130 sysTmp=$(find ${WORKSPACE} -name ${filename:=*.war}) sysDir=${sysTmp/'.war'/} echo "war path: ${sysDir}" upload_file() { ssh -nq $HOST "[ -d /tmp/${sysName} ] && rm -rf /tmp/${sysName} >>/dev/null ; mkdir -p /tmp/${sysName}" ssh -nq $HOST "mkdir -p /tmp/${sysName} " scp -r ${sysDir}/* $HOST:/tmp/${sysName} ssh -nq $HOST "sh /usr/bin/Docker_Build ${sysName} ${BUILD_NUMBER} ${dcpu} ${dmem} ${dins} ${model}" } upload_file
11)配置Docker Build服務
- Docker Build其實就是將Jenkins服務器推過來的源碼包利用Dockfile生成 docker 鏡像。
cat /usr/bin/Docker_Build #!/bin/bash cpu=$3 mem=$4 ins=$5 sysName=$1 BUILD_NUMBER=$2 model=$6 #sysTmp=$(find / -name ${filename:=*.war}) #sysDir=${sysTmp/'.war'/} sysDir=/tmp/$1 echo "war path: ${sysDir}" if [ ! -f "${sysDir}/Dockerfile" ]; then #дDockerfile echo "FROM docker.smart.com/base/tomcat RUN rm -rf /usr/local/tomcat/webapps/ROOT/* ADD ./ /usr/local/tomcat/webapps/ROOT " > ${sysDir}/Dockerfile fi dockerPath=docker.smart.com/front/$sysName:${BUILD_NUMBER} cd ${sysDir} docker build -t ${dockerPath} . docker push ${dockerPath} curl -X DELETE -H "Content-Type: application/json" http://marathon1.paas.smart.com/v2/apps/${model}/${sysName} sleep 20 if [ ! -f "${sysDir}/app_marathon.json" ]; then cat << EOF >${sysDir}/app_marathon.json {"id": "/${model}/${sysName}","container": {"docker":{"image":"${dockerPath}","network": "BRIDGE","parameters":[{"key":"dns", "value": "192.168.10.86"}],"portMappings": [{"containerPort": 8080}]}},"cpus": ${cpu},"mem": ${mem},"instances": ${ins}} EOF fi curl -X POST -H "Content-Type: application/json" http://marathon1.paas.smart.com/v2/apps -d@${sysDir}/app_marathon.json sleep 5 cd / rm -rf ${sysDir}
平臺部署遇到的一些坑:
- 系統防火墻問題,docker的防火墻和系統的防火墻是獨立管理的,可以關閉系統防火墻。
- 系統selinux問題,如 果selinux設置為強制會影響docker系統權限,需改成允許或者禁用。 3. 平臺VM是基于cloudstack搭建的,這里cloudstack的安全組也是一個坑,需要將相關端口開放。 4. consul第一個節點啟動的時候需要帶參數并指定bootstrap參數,然后在其他節點啟動之后可以正常使用配置文件啟動。
- 在部署平臺之前先規劃好相關主機名和DNS解析。
- 平臺啟動順序為先啟動zk然后mesos然后marathon,不然會導致marathon與mesos通訊異常。
- 在啟動nginx時-v參數后邊接nginx相關配置目錄不要接文件,尤其是需要配置ssl的時候。 8.jenkins由于跑在docker里,所以在推送腳本的時候需要進入docker做下與Docker Build 的ssh信任關系。
- 在使用yum安裝mesos的時候可能會由于linux 7下systemctl服務創建開機自動啟動服務,需要disable掉。
平臺使用
任務從一次Jenkins構建開始,Jenkins從代碼倉庫(svn,git)拉取代碼并編譯(配置mvn服務), 編譯完成之后通過upload_file腳本將*.war包推送到Docker Build服務器,Build服務器使用Docker_Build腳本生成Dockfile文件并building成相應的app鏡像推送到 docker.smart.com倉庫,同時通過RESTful接口通知marathon平臺,marathon平臺從mesos-master請求部署 任務,mesos-master返回具體部署服務器slave信息;marathon通過slave docker Damon進程部署app任務。consul服務更新app相關IP和端口然后consul-template服務分別將IP和服務端口更新到DNS和 nginx配置文件reload服務,最后用戶就可以直接訪問app服務,整個任務完成。- Jenkins構建app任務
- marathon平臺部署
- 服務訪問
- 后記:使用此平臺能快速部署應用,易于擴展,從任務發布到訪問服務不過短短幾分鐘,這在創業公司或者內部測試完全能滿足需求,但是如果要落地到企業生產環境還有很多地方需要改進。
- Jenkins編譯構建流程需要拆分,不能每次發布同一款項目都需要重新編譯拉包等,效率低下且不合理。
- Docker的iptables網絡部分需要重新設計,靠iptables的NAT轉發效率有限,雖然解決了服務發現的問題。
- 沒有比較細致的權限控制,平臺安全性缺少。
- Docker APP應用監控以及平臺相關資源監控報警缺少。(Docker監控目前可以介入監控寶)
- APP應用的彈性伸縮目前是人為控制,不能根據業務需求創建。
- 平臺部署相對流程比較多,易于擴展性不足。 (后臺consul-UI)
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!