前一陣子用上了docker。然后架設了一個簡單的分布式微服務系統。公司沒有運維。一開始手動打包發布。隨著服務的增多真的累死人。于是這2天有點時間。于是去研究了一下自動化部署。
jenkins
關于jenkins網上資料很多。我主要使用它來構建我的項目包。
首先是安裝jenkins。去官網下載既然用到了docker。去用docker來部署是不錯的選擇可以參考官網的這個https://jenkins.io/index.html 。 我并沒有使用docker來啟動。我是在官網下了war包。然后直接運行了這個war包。(其實是一開始沒想到用docker來啟動。后面也就懶得改了。)
下載下來war包。直接運行 java -jar jenkins.war --httpPort=8188 & 這里我修改了一下端口號。
這里順便說下一些關于jenkins的東西。
Jenkins 有自己的工作空間。默認是 ~/.jenkins/ 這個目錄下面。我又一次忘了密碼。可以在 ~/.jenkins/ 下面看到以用戶名為名的文件夾。這里面就配置了密碼。修改里面的config.xml把<passwordHash>節點的內容(圖中黑色的那一串)換成#jbcrypt:$2a$10$DdaWzN64JgUtLdvxWIflcuQu2fgrrMSAMabF5TSrGK5nXitqK9ZMS 保存后重啟。這樣密碼就變成了111111.
然后瀏覽器輸入http://localhost:8188/ 就可以訪問到 jenkins頁面了。
下面設置一下自動打包的內容。首先我是一個一個maven管理的java項目。這里需要下載一下maven的插件。并且設置一下maven的目錄。
在 系統設置-》插件管理 搜索并且安裝 [Maven Integration plugin] 插件。
在 系統設置-》 Global Tool Configuration 里面設置各種環境變量。 包括maven 目錄。jdk git等(這里取決于你想干什么)
因為我的jdk配置過環境變量。這里就沒配置。因為我配置過maven私庫。這里就用了我自己的settings.xml
準備工作都差不多了。接下來開始構建一個任務了。
回到首頁。點擊新建。選擇一個maven項目(如果沒有maven項目。那就是上面的maven插件沒有安裝。去安裝插件即可)。輸入名稱。保存。
- 源碼管理。選擇一個你的版本管理。git或者svn。輸入地址。在下面的Credentials輸入賬號。如果連接不上會有紅色的報錯。地址用戶名密碼都正確的話是不會有紅色報錯的。
- 構建觸發器這里選擇你希望的構建觸發。我測試階段沒有選。就直接在首頁點擊構建。構建的。比較主要的有幾種。一個是遠程觸發。這樣可以通過一個url來觸發。比較受控制。我以后可能會選擇這個比較多。 另外就是Poll SCM 這樣的定時觸發。如果公司有每天提交測試版本。可以弄在晚上12點定時打包。這樣第二天測試人員直接來測試。 還有就是hook來觸發。我沒有使用。我的代碼在git上面hook 是post的。貌似這里需要get的。需要些個請求
- 在Post Steps 下面點擊 Add post-build step 這里可以添加構建后的操作。我選擇了Run only if build succeeds 下面 我選擇了shell 腳本
這里寫腳本即可。
這里可以用到一些變量。可以點擊下面的[the list of available environment variables]。查看變量。
上面基本就可以了。可以測試一下。打包之后觀察一下首頁的工作控件內容。可以查看一下是不是打包成功了。
點擊構建之后左下角會出現一個任務。完成后變成藍色。而工作控件里面會出現構建之后的目錄。比如上圖。target里面會有構建的jar包。
這里附上一開始的簡單腳本:
#!/bin/bash
BUILD_ID=dontKillMe
mv /root/.jenkins/workspace/xzjmaventest/target/mytest-0.0.1-SNAPSHOT.jar /usr/local/javatest
cd /usr/local/javatest
ps -ef|grep xzjmaventest|grep -v grep|cut -c 9-15|xargs kill -s 9
java -jar mytest-0.0.1-SNAPSHOT.jar &
這是個簡單的例子。就是將target里面的jar 移動到我的目錄里面去。然后kill 掉之前的java(這里判斷一下是不是存在比較好)。再啟動一下。這里說下。jenkins的新版本會殺死所有創建的線程。
加上BUILD_ID=dontKillMe 就說明這個是不殺死的。
docker
上面jenkins的任務基本就完事了。接下來就是在shell里面寫shell腳本。來實現各種自動化了。
關于docker就不多說了。本來懂的也不是很多。只是使用而已。處理這個的時候。其實就是改變shell而已
#!/bin/bash
BUILD_ID=dontKillMe
ymDir=$(date +%Y%m)
dHMSDir=$(date +%d%H%M%S)
mkdir /usr/local/javatest/${ymDir}
mkdir /usr/local/javatest/${ymDir}/${dHMSDir}
mv /root/.jenkins/workspace/xzjmaventest/target/mytest-0.0.1-SNAPSHOT.jar /usr/local/javatest/${ymDir}/${dHMSDir}
mv /root/.jenkins/workspace/xzjmaventest/target/Dockerfile /usr/local/javatest/${ymDir}/${dHMSDir}
cd /usr/local/javatest/${ymDir}/${dHMSDir}
#docker stop $(docker ps | grep mytest-8777 |awk '{print $1}')
content=$(docker ps | grep mytest-8777 |awk '{print $1}')
docker stop $content
docker rm $content
docker rmi mytest-8777
docker build -t mytest-8777 .
docker run -p 8777:8777 -t --net=host mytest-8777 --name mytest-8777 &
#ps -ef|grep mytest|grep -v grep|cut -c 9-15|xargs kill -s 9
#java -jar mytest-0.0.1-SNAPSHOT.jar &
這里一個簡單的創建docker鏡像。然后運行的腳本。這里我把Dockerfile放到了我的java項目里面。然后在maven打包的配置里面復制到了jar的同層目錄。便于管理。
上面那種在單機的環境下是沒有什么問題的。在多個服務微服務的架構下。就比較麻煩了。當然可以通過文件傳輸。遠程命令。等在多個服務器上面執行同樣的腳本。上傳同樣的命令。然后來實現。可視并不便于管理。
這里就需要2個東西來幫忙了。docker-registry docker -swarm
docker-registry
docker-registry 是docker的私有倉庫。使用上很簡單。
sudo docker pull registry 就可以從docker的官方倉庫下面拉下來registry鏡像。這里可能會遇到一個天朝特殊網絡環境的問題。所以我pull 的是 daocloud.io/registry 這個image。
然后 docker run 起來就ok了。 這里最好將docker 鏡像的存放目錄掛在到宿主機上面來。
docker run -d -v /opt/registry:/var/lib/registry -p 5000:5000 --restart=always --name registry registry
之后將 鏡像 改成 <host>:port/image:tag 這樣的格式。在執行push命令。就會上傳到registry上面去。
docker tag mytest-8777:${BUILD_NUMBER} <host>:5000/mytest-8777:${BUILD_NUMBER}
docker push <host>:5000/mytest-8777:${BUILD_NUMBER}
這里需要注意的是。如果你的服務器不是https 的。需要修改一下配置。registry 默認是https的。
在/etc/docker/ 下面創建 daemon.json(如果沒有的話)
vim /etc/docker/daemon.json
#添加一行 { "insecure-registries":["<host>:5000"] } host是你對應的服務器地址。然后重啟docker即可
systemctl restart docker.service
經過上面的構成。其他服務器就可以直接run 這個倉庫里面的包了。會自動去倉庫下載。
docker-swarm
關于swarm 我暫時了解的并不多。他是一個docker的分布式管理工具。很好用。同樣的直接pull鏡像
docker pull daocloud.io/swarm 依然不是用的官方的。誰讓我的網 。。哎。。。
然后docker swarm init 即可
我的電腦有2個ip 。他會讓你選擇 ip
docker swarm init --advertise-addr <ip>
這個 swarm 的管理端就好了。執行完這個命令。系統會打印出一段文字 類似這樣
docker swarm join \
--token 111111111dfsfsdfsdfsdfdsf \
192.168.1.1:2377
這個其實就告訴你其他電腦如果加入這個swarm。
在其他電腦上執行上面的命令加入后。這幾個電腦就會被一起管理。
然后在服務端創建一個任務
docker service create --name ${serviceName} --replicas 2 -p 8777:8777/tcp ${imageName}:${BUILD_NUMBER}
這樣被管理的電腦就會根據replicas 設定的值 啟動多個docker 服務。我這里的鏡像都是放在倉庫里面的。所以機器里面如果沒有這個鏡像。也會自己pull去。這樣就實現了我的需求。
在這里。我遇到一個問題。我的服務用的微服務架構。會去zookeeper注冊自己的ip提供該客戶端。而docker里面有自己的ip環境。會導致注冊進去的是docker的虛擬ip。別的宿主機訪問不到。--net=host可以解決。但并不合理。這時候利用swarm的overlay網絡可以輕松解決
docker network create --driver overlay --subnet 10.0.9.0/24 my-multi-host-network
docker service create --name sonar_service1 --replicas 2 --network my-multi-host-network -p 8777:8777/tcp mytest-8777
可以想上面一樣指定一下。當然不寫默認的也能直接訪問。
這里需要注意的是 這個文章整個解決方案是我自己瞎搗鼓的。我并不知道別人是怎么搞的。可能并不是很完美。主要docker的知識也很缺乏。以后需要去了解一下
docker Machine, Docker Swarm, 和Docker Compose. 這三個。可能比上面的方案簡單的多。