前言
分享一些關(guān)于部署網(wǎng)站的簡單技巧,和jenkins刑桑、docker等CICD和容器的技術(shù)失息。
一系列操作涉及到的技術(shù)工具和平臺有:阿里云服務(wù)器, CentOS系統(tǒng), 寶塔
(服務(wù)器圖形界面工具), jenkins
, docker
, docker-compose
, docker swarm
內(nèi)容簡介如下:
- Jenkins登場,用Jenkins簡單配置流水線档址,在服務(wù)器上部署網(wǎng)站盹兢。
- 使用docker,docker-compose等配置文件和相應(yīng)使用守伸。
- docker容器與容器網(wǎng)絡(luò)連接绎秒,以及容器與宿主機(jī)的連接。
- docker swarm的集群部署和滾動升級的簡單使用尼摹。
Jenkins登場
Jenkins是一個開源的见芹、提供友好操作界面的持續(xù)集成(CI)和持續(xù)部署(CD)的工具。在CI/CD這一塊蠢涝,Jenkins是一張王牌玄呛。持續(xù)集成和持續(xù)部署的目的很簡單,如下圖所示和二,可以利用hook或手動徘铝,對開發(fā)項目的新提交進(jìn)行構(gòu)建、測試和部署到生產(chǎn)環(huán)境上惯吕。以及附帶日志收集和狀態(tài)監(jiān)控等等功能惕它。
<center>
<img src="https://s1.ax1x.com/2022/11/28/zUxq2R.jpg" alt="" width="40%" />
</center>
既然是自用的一些工具和云服務(wù)器,會希望簡介易用一些废登,所以我自己給云服務(wù)器安裝了寶塔系統(tǒng)淹魄。寶塔系統(tǒng)是一款不錯的服務(wù)器圖形界面工具,更容易操作云服務(wù)器和部署業(yè)務(wù)堡距。大體界面甲锡,如下圖所示。
<center>
<img src="https://s1.ax1x.com/2022/11/28/zapvq0.png" alt="" width="70%" />
</center>
如果不用圖形化工具的話吏颖,可在終端中輸入命令搔体,選定一個適合的絕對路徑(我用的/root/env),下載好jenkins的war包(官網(wǎng)下載很方便)半醉。使用命令nohup java -jar /root/env/jenkins.war &
疚俱,這里 nohup XXXXX &
是Linux系統(tǒng)的掛起命令,即使關(guān)閉終端缩多,這個掛起的命令也不會退出呆奕,除了錯誤退出和重啟云服務(wù)器之外养晋,都會一直在進(jìn)程中。使用了nohup命令后梁钾,會在終端的路徑之中生產(chǎn)nohup.out日志文件绳泉。當(dāng)然我們也可以在命令之中指定,生成的日志文件的名字和路徑姆泻,如nohup java -jar /root/env/jenkins.war > /root/env/jenkins.out 2>&1 &
則指定jenkins.out日志文件生成在/root/env目錄之下零酪。
jenkins默認(rèn)端口為8080,如果自己的云服務(wù)器的安全組和對應(yīng)的服務(wù)器工具沒有放開8080端口拇勃,那么利用公網(wǎng)ip也訪問不到四苇。
如果是新接觸jenkins的朋友,可以搜一搜網(wǎng)上相關(guān)資料方咆,需要進(jìn)行一些簡單的配置月腋,一些相關(guān)的插件的下載。
這里我簡單地使用jenkins(本文是漢化插件加持)瓣赂。Dashboard -> 新建任務(wù) -> 流水線(pipline) -> 選擇github項目榆骚,輸入github庫的URL -> 下滑到流水線定義那,選擇Pipline script from SCM -> SCM 選擇Git 煌集,配置好git庫URL和憑證(私庫才需要配置) -> 其他配置默認(rèn)即可妓肢,點(diǎn)擊保存
jenkins的pipline相應(yīng)差不多了,另外的需要的是自己Git項目里的根目錄中的Jenkinsfile
文件牙勘。我的Jenkinsfile文件配置得比較簡單:
pipeline
{
agent any
stages {
stage('Build')
{
steps {
sh" gradle clean build -x test "
}
}
stage('Deploy')
{
steps {
sh" kill -9 \$(lsof -i:8034) "
sh" JENKINS_NODE_COOKIE=dontKillMe nohup java -jar /root/project/myservice.jar & "
}
}
}
}
分別在build階段职恳,用gradle構(gòu)建工具重新打包和跳過測試。在deploy階段方面,也就是jenkins在構(gòu)建出jar包之后的部署階段放钦。因為我直接部署在云服務(wù)器之中,端口占用為8034
恭金,我需要先殺死8034端口的進(jìn)程操禀,然后在jenkins里用JENKINS_NODE_COOKIE=dontKillMe
加上部署命令,這里也是用的jenkins生成jar包的絕對路徑的命令横腿。當(dāng)jenkins構(gòu)建和部署成功后我們最希望看到的綠色流水線階段試圖出現(xiàn)了:
<center>
<img src="https://s1.ax1x.com/2022/11/30/zwY5wR.png" alt="" width="50%" />
</center>
這樣一趟操作下來颓屑,構(gòu)建和部署都有了。但相對的缺點(diǎn)也很明顯耿焊,如果之前的服務(wù)沒問題揪惦,新部署的服務(wù)出問題,豈不是網(wǎng)站就崩了罗侯,也沒法回滾原版本器腋;并且服務(wù)在更新之時,也會出現(xiàn)網(wǎng)站服務(wù)停掉后更新的情況;以及項目依賴多了對一個云服務(wù)器環(huán)境依賴也是麻煩事纫塌。而這則是真正項目會用到docker诊县,k8s等容器技術(shù)的原因。
使用 docker
docker容器技術(shù)措左,我就不多贅述了依痊,隔離、切換環(huán)境等等操作很好用怎披。簡單講一下自己的理解胸嘁,dockerhub類似于github;image類似于git項目凉逛,可以推上hub也可以本地放置缴渊;container是image的實例,docker都是跑的container鱼炒,每一個container跑起來都是一個殘血版的Linux系統(tǒng),有獨(dú)立的進(jìn)程和端口蝌借,可以通過映射端口到宿主機(jī)昔瞧。
我在項目中,加入簡單的docker運(yùn)用菩佑。先在項目文件夾的根目錄中加入Dockerfile
文件自晰。這里為的是創(chuàng)造一個需要的容器,file內(nèi)FROM
是拉取遠(yuǎn)程鏡像或本地鏡像稍坯,Dockerfile
本質(zhì)就是為了創(chuàng)建一個自己定義的鏡像酬荞。
比如這里淘菩,我就是拉取合適的jdk版本的遠(yuǎn)端鏡像助琐,WORKDIR
定義鏡像的終端一開始的目錄外里,COPY
為把項目中的構(gòu)建工具的目錄里的文件復(fù)制進(jìn)鏡像定義的路徑和指定的文件名字鹤树。ENV
定義鏡像的環(huán)境變量亩鬼,比如時區(qū)彼硫,甚至一些ip和端口之類的溜徙。EXPOSE
是鏡像生成容器后市怎,服務(wù)在容器內(nèi)的端口陨亡“猓可以在項目根目錄再創(chuàng)建一個.dockerignore
文件,類似于.gitignore
文件负蠕,當(dāng)鏡像要打包文件進(jìn)入的時候蛙埂,會自動排除。
FROM adoptopenjdk/openjdk11:latest
WORKDIR /app
COPY ./build/libs/myservice-1.0.6.jar /app/myservice.jar
ENV LANG=en_US.UTF8
ENV TZ=Asia/Shanghai
EXPOSE 8034
有了上述的文件遮糖,在對應(yīng)目錄下绣的,打開終端,輸入命令docker image build -t myservice .
則可創(chuàng)建名為myservice的鏡像,命令中的-t是指定名字和tag被辑,末尾的點(diǎn)是指定鏡像上下文為當(dāng)前目錄燎悍。
有了鏡像文件,要run起來成為容器盼理,需要命令docker run
谈山, 如docker run --name myapp -p 8034:8034 -d myservice
--name參數(shù)為容器命名;-p參數(shù)為端口映射宏怔,比如這里就是容器內(nèi)的8034端口映射到宿主機(jī)的8034奏路;-d參數(shù)為指定非后臺運(yùn)行。run起來的容器在mac的docker desktop上能看日志和使用命令行臊诊,在Liunx服務(wù)器終端上可以用命令docker logs <你的容器名或容器ID>
容器名如果沒有自己在配置中制定名字鸽粉,可以用docker ps
查看各個容器的信息。要進(jìn)入容器的終端用命令docker exec -it <你的容器名或容器ID> /bin/sh
一些復(fù)雜的docker run
命令抓艳,大量參數(shù)涉及到多行触机,在終端上每一行末尾加上空格和\
,如下所示:
docker run --name mydb \
--network app-network \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=myapp \
-d mysql:8.0
使用 docker-compose
docker-compose是在docker之中涉及到容器編排的技術(shù)玷或。使用也很廣泛儡首。它的使用,是為了集中管理多個容器偏友,試想一下蔬胯,如果一個微服務(wù)項目,有多個模塊和鏡像需要docker啟動位他,能快速部署氛濒、彼此獨(dú)立、分工合作是不是很不錯的一件事鹅髓。
使用compose舞竿,首先在項目根目錄下,建立docker-compose.yml
文件窿冯。如下只是一個簡單的demo:
version: "3.9" # 此處compose的版本影響部分參數(shù)是否有效炬灭,具體參數(shù)可以查詢本文參考里的docker官網(wǎng)
services:
myapp: # 單獨(dú)的服務(wù)名
build: ./ # dockerfile文件在當(dāng)前上下文目錄
image: myservice # image名字
volumes: # 掛載在docker宿主機(jī)上的目錄,指定的好處是可以刪除鏡像和容器后靡菇,目錄不丟失內(nèi)容重归。比如mysql的表內(nèi)容可以一直存在直到卷被刪除。冒號前為宿主機(jī)卷位置厦凤,冒號后為容器內(nèi)位置鼻吮。macos里是找不到實際掛載位置的,因為是虛擬raw文件较鼓。
- app-data:/app
ports:
- "8034:8034" # 映射端口椎木,冒號前為宿主機(jī)违柏,冒號后為容器
environment: # 環(huán)境變量
DOCKER_HOST: 172.20.0.3
depends_on: # 依賴項,依賴項會更早啟動香椎,保證啟動正常
- myredis
restart: always # docker重啟漱竖,會同時重啟容器
entrypoint: java -jar XXX.jar # 啟動容器后運(yùn)行的命令
myredis:
image: redis:latest
volumes:
- redis-data:/var/lib/redis
ports:
- "6380:6379"
volumes: # 書寫格式,用到了掛載卷畜伐,就要加
app-data:
用命令docker-compose up -d
啟動相關(guān)的多個容器馍惹。如果代碼更新后需要的鏡像也要更新,可使用docker-compose up --build -d
玛界,不會走緩存的鏡像万矾,會強(qiáng)制更新鏡像,然后run容器慎框。
dockerc重新生成鏡像會走一些緩存之內(nèi)的良狈,比如你只更新鏡像中的jar包或前端打的包,剩余FROM
拉取的遠(yuǎn)端鏡像不會再從頭拉取笨枯,而是走的緩存薪丁。終端輸出如下圖所示,可以看到例如FROM
拉取鏡像是在瞬間完成的馅精,這就是走的緩存窥突。而之前說的參數(shù)--build
只是重新更新這個完整鏡像,必要走緩存的步驟依舊會走硫嘶,以此節(jié)省性能。
<center>
<img src="https://s1.ax1x.com/2022/11/30/zw8tWF.png" alt="" width="50%" />
</center>
并且可以使用docker-compose up --no-deps --build -d myapp
命令來更新具體想要更新的那個鏡像梧税,而不用把整個服務(wù)的所有鏡像都重塑一遍沦疾。在jenkins里,就可以在deploy
階段第队,加入這個命令去更新你想更新的服務(wù)哮塞。
當(dāng)代碼更新之后,更新docker-compose文件更改tag參數(shù)凳谦,這樣可以做到舊版本的image仍舊存在忆畅,如果新的image的容器出一些不可預(yù)測的問題,可以及時手動回滾調(diào)整尸执。
springboot中的application配置可以跟docker的環(huán)境變量配合家凯,比如
url: jdbc:mysql://${DOCKER_HOST:localhost}:3306/myapp?useSSL=false&serverTimezone=Asia/Shanghai
${DOCKER_HOST:localhost}
的意思就是,如果有DOCKER_HOST
環(huán)境變量則用它如失,如果沒有绊诲,則使用localhost這個數(shù)據(jù)。
jenkins的pipline和docker容器之間最好進(jìn)行恰當(dāng)?shù)穆氊?zé)分離褪贵,如測試掂之、構(gòu)建抗俄、打包環(huán)節(jié)可以交給jenkins,而docker部署的鏡像環(huán)境盡可能純粹世舰。比如前端的依賴包留在服務(wù)器目錄中动雹,只把打好的包裝入docker鏡像。鏡像里盡可能只有一些必要的代碼產(chǎn)物和運(yùn)行插件跟压。值得注意的是胰蝠,如果前端項目在jenkins已經(jīng)打好靜態(tài)包了,則docker里配置的環(huán)境變量則無法在前端的靜態(tài)文件包里生效了裆馒。
docker內(nèi)容器之間的連接
docker內(nèi)各個容器之間姊氓,和docker容器跟宿主機(jī)之間的連接的細(xì)節(jié)和知識點(diǎn)可以看看網(wǎng)上資料的docker網(wǎng)絡(luò)模式。
<center>
<img src="https://s1.ax1x.com/2022/11/29/zdT279.png" alt="" width="20%" />
</center>
docker各個容器之間的連接很常見喷好,比如我有一個后端項目翔横,需要連接數(shù)據(jù)庫,兩個服務(wù)分別在兩個鏡像之中梗搅,分別開啟兩個容器禾唁,則之間需要連接。這里我舉例一個后端容器與一個mysql容器的連接命令无切。
docker run --name mydb \
--network app-network \
--network-alias mydb \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=myservice \
-d mysql:8.0
這里的--network是在容器中創(chuàng)建一個網(wǎng)絡(luò)荡短,這個網(wǎng)絡(luò)可以供其他容器去連接,--network-alias是網(wǎng)絡(luò)別名哆键,這個參數(shù)很重要掘托,如果你需要你的后端項目連接容器的數(shù)據(jù)庫,則不可以使用localhost作為host籍嘹,而是這個網(wǎng)絡(luò)別名闪盔。比如在springboot的application配置中,
url: jdbc:mysql://mydb:3306/myservice?useSSL=false&serverTimezone=Asia/Shanghai
辱士,這里的mydb就是mysql容器網(wǎng)絡(luò)別名泪掀,myservice則是docker run 環(huán)境變量會自動生成的空的有效的數(shù)據(jù)庫。對應(yīng)的后端項目命令docker run --name myapp --link mydb -p 8034:8034 -d myservice
這個命令中 --link后的參數(shù)就是上述的容器網(wǎng)絡(luò)別名颂碘。這樣就可以完成兩個容器之間的連接异赫。
那么在docker-compose里如何完成多個容器的互相連接呢,這里我給出我的方案头岔,配置compose文件:
version: "3.9"
services:
myapp:
build: ./
image: myservice:1.0.6 # image的tag
ports:
- "8034:8034"
environment:
DOCKER_HOST: database # 可以給到application配置文件的環(huán)境變量
links:
- "mydb:database" # 將服務(wù)名別名為database塔拳,然后通過環(huán)境變量傳遞給jar包
depends_on:
- mydb
restart: always
entrypoint: java -jar /app/hok-myservice.jar
mydb:
image: mysql:8.0
volumes:
- mysql-data:/var/lib/mysql
ports:
- "3305:3306"
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: myapp
TZ: Asia/Shanghai
restart: always
volumes:
mysql-data:
當(dāng)然也可以顯式地創(chuàng)建和制定容器連接的網(wǎng)絡(luò)。external字段
和 docker create network
命令峡竣,這個如果有需要可以去了解下蝙斜。
docker容器與宿主機(jī)連接
那么還有個問題是,容器能跟宿主機(jī)進(jìn)行連接嗎澎胡?
當(dāng)然是可以的孕荠,這里面分兩種情況娩鹉。
第一種Linux系統(tǒng)上,使用
ifconfig
稚伍,就能查詢到docker0的inet 網(wǎng)絡(luò)ip是什么弯予,一般為172.18.0.1,在后端鏡像中个曙,用這個ip代替localhost的host即可锈嫩,當(dāng)然這也涉及到宿主機(jī)的db的權(quán)限是否對外開放的問題,可以查一查如何修改和刷新數(shù)據(jù)庫訪問權(quán)限垦搬。第二種就是在MacOS上呼寸,MacOS上跟Linux上不一樣,不能通過ifconfig查詢ip猴贰,但是可以通過其他途徑对雪。比如通過docker desktop -> setting界面 -> resources選項 -> Network 界面 -> Docker subnet ; 默認(rèn)都是192.168.65.0/ 米绕,在后端項目中的url配置host要用192.168.65.2瑟捣,因為最后的子網(wǎng)掩碼0和1都被占用了,1作為docker的網(wǎng)關(guān)栅干。docker desktop上的subnet ip界面如下圖所示:
<center>
<img src="https://s1.ax1x.com/2022/11/29/zdTHne.png" alt="" width="70%" />
</center>
如果是本地開發(fā)調(diào)試迈套,可以使用容器里裝代碼產(chǎn)物,連接宿主機(jī)的數(shù)據(jù)庫碱鳞,但在生產(chǎn)環(huán)境桑李,不建議這樣使用,這樣破壞了最初使用容器環(huán)境之間的隔離思想窿给,對于整個docker的使用流程和思想背道而馳贵白。
使用 docker swarm
上述一堆docker的使用,但貌似還是沒解決最關(guān)鍵的問題填大,構(gòu)建部署之后,如果現(xiàn)版本出問題俏橘,沒有特別方便的辦法回滾和及時恢復(fù)之前服務(wù)的版本允华,會影響業(yè)務(wù)使用。這就需要docker swarm滾動升級了(k8s也可寥掐,這里我用的是swarm)Docker Swarm比起k8s要更簡單靴寂,并且與docker-compose兼容。對于沒有接觸過集群部署的小伙伴召耘,swarm是上佳的選擇百炬。
關(guān)于Docker Swarm,是一個容器編排技術(shù)污它。Docker Swarm 和 Docker Compose 的區(qū)別在于 Compose 用于在同一主機(jī)上配置多個容器剖踊。Docker Swarm可以在多個主機(jī)配置多個容器庶弃。節(jié)點(diǎn)、集群管理德澈、滾動升級歇攻、均衡負(fù)載等都是Docker Swarm的優(yōu)勢。
<center>
<img src="https://s1.ax1x.com/2022/11/30/zwRzY8.png" alt="" width="40%" />
</center>
我對于Swarm和集群相關(guān)的使用比較淺梆造,如果未來有機(jī)會深入理解和使用缴守,再給大家分享更好的經(jīng)驗和文章。這里分享一些命令吧镇辉。
Swarm單詞本身就是群的意思屡穗,docker swarm <option>
命令可以創(chuàng)建、加入忽肛、離開一個集群村砂。在使用swarm之前,要使用命令docker swarm init
麻裁,以及之后docker操作不需要swarm需要關(guān)閉箍镜,應(yīng)該使用命令docker swarm leave
,如果只需要使用compose功能而不關(guān)閉swarm煎源,則終端會一直報warning提醒色迂。
service是一類容器,service是和swarm非常緊密的內(nèi)容手销,使用命令docker service create --replicas 3 -p 80:80 --name nginx nginx:latest
即創(chuàng)建了一個swarm的service歇僧,replicas參數(shù)指定實例數(shù)量,其他參數(shù)跟docker run
的意思大差不差锋拖。docker service update --image nginx:3.0.7 nginx
和docker service rollback nginx
分別是滾動升級鏡像和回滾鏡像的命令诈悍,有了滾動升級的命令,則不用擔(dān)心在更新服務(wù)的時候兽埃,網(wǎng)站無法使用影響體驗了侥钳,回滾命令也給予了極大的容錯空間。
因為swarm和compose是兼容的柄错,所以可以在docker-compose文件中也可以加入一些獨(dú)屬于swarm的配置參數(shù)舷夺,如deploy
等等。
services:
myapp:
省略內(nèi)容
deploy:
mode: replicated
replicas: 3
如果不想compose和swarm配置文件在一起售貌,可以另外重命名自己的swarm配置文件给猾,比如docker-deploy.yml
,這里使用命令docker stack deploy -c <docker-deploy.yml> <你的service名字>
可以指定docker swarm的配置文件啟動service颂跨,之后可以使用命令docker service logs <你的容器名>
查詢?nèi)萜魅罩尽?code>docker service ps <你的容器名>來查詢具體容器的狀態(tài)以及docker service ls
查詢所有service的容器狀態(tài)敢伸,關(guān)閉service可以用docker stack down <你的service名字>
。
參考
本文到此就全部結(jié)束了恒削,大家關(guān)于本文在實踐和內(nèi)容上有想交流的地方池颈,都可以找我交流和提出寶貴的意見哈尾序。
這是自己在使用docker之時參考的一些資料,其中不乏官方資料和優(yōu)秀資料饶辙。