初創公司利用Docker持續集成部署

jopen 9年前發布 | 41K 次閱讀 Docker

來自:http://dockone.io/article/671

Docker技術炙手可熱,但是對于初創企業如何利用Docker這門新技術來解決內網開發或者測試環境的快速部署,解放運維并提高工作效率,尤其在創業 之初人力資源不足的情況下,更為重要。為此我和公司一位開發同學一起研究的關于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運行的軟件配置文件放到這個目錄)


  • 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組成一個集群。
5)配置mesos-master和mesos-slave
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放到后臺。

  • ip每個主機取值不相同 hostname默認會是主機名,但很多情況不能訪問,所以使用主機IP
    如果要在WEB UI上看到日志,需要配置log_dir屬性
    executor_registration_timeout容器執行的超時時間,如果docker pull的時候非常耗時,可能會導致這里超時.
6)配置marathon平臺

  • 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或本機主機名
      
7)配置consul集群

  • 需要部署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. 
      
8)nginx配置

  • 因為我們的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倉庫中拉去。
      
9.配置consul-template來動態發現注冊服務。

  • 配置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}  

平臺部署遇到的一些坑:
  1. 系統防火墻問題,docker的防火墻和系統的防火墻是獨立管理的,可以關閉系統防火墻。
  2. 系統selinux問題,如 果selinux設置為強制會影響docker系統權限,需改成允許或者禁用。 3. 平臺VM是基于cloudstack搭建的,這里cloudstack的安全組也是一個坑,需要將相關端口開放。 4. consul第一個節點啟動的時候需要帶參數并指定bootstrap參數,然后在其他節點啟動之后可以正常使用配置文件啟動。
  3. 在部署平臺之前先規劃好相關主機名和DNS解析。
  4. 平臺啟動順序為先啟動zk然后mesos然后marathon,不然會導致marathon與mesos通訊異常。
  5. 在啟動nginx時-v參數后邊接nginx相關配置目錄不要接文件,尤其是需要配置ssl的時候。 8.jenkins由于跑在docker里,所以在推送腳本的時候需要進入docker做下與Docker Build 的ssh信任關系。
  6. 在使用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服務,整個任務完成。
  1. Jenkins構建app任務
     初創公司利用Docker持續集成部署
  2. marathon平臺部署
     初創公司利用Docker持續集成部署
  3. 服務訪問
     初創公司利用Docker持續集成部署
  • 后記:使用此平臺能快速部署應用,易于擴展,從任務發布到訪問服務不過短短幾分鐘,這在創業公司或者內部測試完全能滿足需求,但是如果要落地到企業生產環境還有很多地方需要改進。
  1. Jenkins編譯構建流程需要拆分,不能每次發布同一款項目都需要重新編譯拉包等,效率低下且不合理。
  2. Docker的iptables網絡部分需要重新設計,靠iptables的NAT轉發效率有限,雖然解決了服務發現的問題。
  3. 沒有比較細致的權限控制,平臺安全性缺少。
  4. Docker APP應用監控以及平臺相關資源監控報警缺少。(Docker監控目前可以介入監控寶)
  5. APP應用的彈性伸縮目前是人為控制,不能根據業務需求創建。
  6. 平臺部署相對流程比較多,易于擴展性不足。 (后臺consul-UI)
     初創公司利用Docker持續集成部署
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!