使用 jenkins+docker 實(shí)現(xiàn) git+springboot+gradle 及前端項(xiàng)目的持續(xù)集成和部署

0 前言

記錄 jenkins 基于 docker 的前后端項(xiàng)目的構(gòu)建及部署全流程塌鸯。后端項(xiàng)目案例使用 SpringBoot+Gradle,前端項(xiàng)目案例框架不限

1 部署 jenkins

1.1 獲取鏡像

前往 https://hub.docker.com/r/jenkins/jenkins/tags 獲取鏡像:jenkins/jenkins:2.232-slim。也可以直接獲取支持 jdk11 的鏡像:jenkins/jenkins:2.232-jdk11鼠锈,但該鏡像體積較大岭粤,不選擇。三種官方鏡像信息如下:

[root@54s9uer src]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
jenkins/jenkins     2.232-centos        a355678ccb95        41 hours ago        782MB
jenkins/jenkins     2.232-jdk11         3ea7fe8adf57        41 hours ago        766MB
jenkins/jenkins     2.232-slim          803c6c58592b        41 hours ago        470MB

注: jenkins 有關(guān) jdk11 兼容性的文檔詳見(jiàn):jenkins-on-java-11

1.2 創(chuàng)建宿主機(jī)掛載目錄

/usr/src/jenkins_home

1.2.1 掛載目錄權(quán)限問(wèn)題

若直接掛載上述目錄派昧,會(huì)因權(quán)限問(wèn)題而無(wú)法啟動(dòng)容器黔姜。失敗信息可使用 docker logs <容器ID> 命令查看容器日志:

touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?

此時(shí),先不進(jìn)行掛載蒂萎,使用 docker run -it --rm jenkins/jenkins:jdk11 /bin/bash 建立一個(gè)測(cè)試容器秆吵,執(zhí)行 whoami && id 命令獲取當(dāng)前用戶信息

jenkins@8dced799c01c:/$ whoami && id
jenkins
uid=1000(jenkins) gid=1000(jenkins) groups=1000(jenkins)

默認(rèn)情況下,容器用戶是 jenkins五慈。進(jìn)一步查看容器的 jenkins_home 目錄權(quán)限纳寂,發(fā)現(xiàn)所有者也是 jenkins,如下所示:

jenkins@8dced799c01c:/$ ls -la /var/jenkins_home
total 20
drwxr-xr-x 2 jenkins jenkins 4096 Apr 12 00:54 .
drwxr-xr-x 1 root    root    4096 Apr  6 09:01 ..
-rw-r--r-- 1 jenkins jenkins   50 Apr 12 00:54 copy_reference_file.log
-rw-rw-r-- 1 root    root    7152 Apr  6 08:55 tini_pub.gpg

注:即使添加 -u root 參數(shù)進(jìn)入容器泻拦,jenkins_home 的所有者依然是 jenkins

回到宿主機(jī)毙芜,查看 /usr/src/jenkins_home 權(quán)限,所有者是 root争拐。因此當(dāng)容器的 jenkins 用戶進(jìn)程訪問(wèn)宿主機(jī)的 /usr/src/jenkins_home 目錄時(shí)腋粥,就出現(xiàn) Permission denied 的問(wèn)題。

1.2.2 解決方案

根據(jù)測(cè)試容器用戶 uid 的結(jié)果架曹,修改宿主機(jī) /usr/src/jenkins_home 的所有者隘冲,執(zhí)行 chown -R 1000 /usr/src/jenkins_home

注:該解決方案參考了 https://yq.aliyun.com/articles/53990

1.3 啟動(dòng)容器

docker run --name jenkins \
-p 8080:8080 \
--mount type=bind,src=/usr/src/jenkins_home,dst=/var/jenkins_home \
-d \
jenkins/jenkins:jdk11

1.4 添加項(xiàng)目構(gòu)建依賴

用 root 身份進(jìn)入容器

docker exec -it -u root <容器ID> /bin/bash

1.4.1 安裝 git

(1)由于 jenkins/jenkins:2.232-slim 基礎(chǔ)鏡像為 Debian,因此使用 apt 工具安裝

apt-get update
apt-get install git

注:通過(guò)該方法安裝的版本不是最新

(2)查看執(zhí)行路徑

root@832c29984d24:/usr/bin# git --exec-path
/usr/lib/git-core

因此在 jenkins 的 全局工具配置 中需要的 Path to Git executable 就是 /usr/lib/git-core/git

附加內(nèi)容:查看容器的系統(tǒng)版本绑雄。以 jenkins/jenkins:2.232-slim 鏡像為例展辞,進(jìn)入容器后可執(zhí)行如下命令查看

root@832c29984d24:/# cat /etc/issue
Debian GNU/Linux 10 \n \l

注:不可用 cat /proc/versionuname -a,得到的結(jié)果是是宿主機(jī)的系統(tǒng)信息万牺。

附加內(nèi)容:Debian 應(yīng)用的安裝路徑通常在 /usr/share罗珍,可執(zhí)行文件路徑通常在 /usr/bin,配置文件路徑通常在 /etc

1.4.2 安裝 Amazon Corretto 11

后端項(xiàng)目案例使用 Amazon Corretto 11杏愤。jenkins 構(gòu)建項(xiàng)目時(shí)也需要使用靡砌,與容器的自帶 openJDK 不沖突,可以不在 /etc/profile 中設(shè)置 JAVA_HOME珊楼,只在 jenkins 的 全局工具配置 中指定即可通殃。

注:若使用 jenkins/jenkins:2.232-jdk11 鏡像,并且使用自帶 openJDK,可使用 echo $JAVA_HOME 查看路徑画舌,直接復(fù)制到 jenkins 的 全局工具配置 中對(duì)應(yīng)位置堕担。

(1)在 下載頁(yè)面 獲取壓縮包地址,下載到 /usr/src/ 目錄下

wget -c https://d3pxv6yz143wms.cloudfront.net/11.0.3.7.1/amazon-corretto-11.0.3.7.1-linux-x64.tar.gz

注:若需要安裝 wget 命令曲聂,執(zhí)行 apt-get install wget 即可

(2)解壓到 /usr/src/jdk11 目錄

tar zxvf amazon-corretto-11.0.3.7.1-linux-x64.tar.gz -C /usr/src/jdk11/

因此在 jenkins 的 全局工具配置 中需要的 JAVA_HOME 就是 /usr/src/jdk11/amazon-corretto-11.0.3.7.1-linux-x64/

1.4.3 安裝 NodeJs 插件

為構(gòu)建前端項(xiàng)目霹购,需安裝 NodeJs 插件。

(1)前往 jenkins 的插件管理界面搜索安裝

(2)進(jìn)入 全局工具配置 中配置 nodejs 的版本和別名

附加內(nèi)容:jenkins 插件及應(yīng)用路徑

  • 插件路徑:$JENKINS_HOME/plugins朋腋,其中 $JENKINS_HOME 默認(rèn)值為 /var/jenkins_home
  • nodejs 路徑:$JENKINS_HOME/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation

1.4.4 安裝 Gradle

需要安裝 Gradle Plugin 插件齐疙。進(jìn)入 全局工具配置 選擇自動(dòng)安裝,版本按需選擇旭咽。

3 手動(dòng)構(gòu)建后端項(xiàng)目

新建 Freestyle project贞奋,輸入任務(wù)名稱后進(jìn)入詳細(xì)配置。

(1)General

填寫項(xiàng)目地址穷绵,不帶 tree/master 或 tree/branch 部分轿塔,如 https://github.com/username/repositoryname.git

(2)源碼管理

選擇 Git,在 Repository URL 欄填寫 GitHub 倉(cāng)庫(kù)的 https 鏈接(如 https://github.com/username/repositoryname.git)仲墨,Branchs to build 填寫要被構(gòu)建的分支勾缭,如 */master,源碼庫(kù)瀏覽器選擇自動(dòng)目养。

(3)構(gòu)建

新增 Invoke Gradle 構(gòu)建步驟俩由,選擇對(duì)應(yīng)別名;點(diǎn)擊高級(jí)癌蚁,設(shè)置要執(zhí)行的 Tasks 為 bootJar采驻,其余欄位保持默認(rèn)或空白。

4 手動(dòng)構(gòu)建前端項(xiàng)目

新建 Freestyle project匈勋,輸入任務(wù)名稱后進(jìn)入詳細(xì)配置。

(1)General

填寫項(xiàng)目地址膳叨,不帶 tree/master 或 tree/branch 部分洽洁,如 https://github.com/username/repositoryname.git

(2)源碼管理

選擇 Git,在 Repository URL 欄填寫 GitHub 倉(cāng)庫(kù)的 https 鏈接(如 https://github.com/username/repositoryname.git)菲嘴,Branchs to build 填寫要被構(gòu)建的分支饿自,如 */master,源碼庫(kù)瀏覽器選擇自動(dòng)龄坪。

(3)構(gòu)建

新增 Executes a NodeJS script 構(gòu)建步驟昭雌,選擇 NodeJs 插件對(duì)應(yīng)的別名;再新增 執(zhí)行 shell 構(gòu)建步驟健田,添加命令 node -v && npm -v && npm install --registry=http://registry.npm.taobao.org && npm run build

5 其他配置案例

5.1 GitHub 倉(cāng)庫(kù)分支有變動(dòng)時(shí)(提交或合并到該分支)自動(dòng)構(gòu)建

5.1.1 配置 GitHub

(1)進(jìn)入倉(cāng)庫(kù)的 Settings烛卧,側(cè)邊欄找到 Webhooks 并新建。輸入 Payload URL妓局,該地址默認(rèn)為 http://<宿主機(jī)IP>:8080/github-webhook/总放,其余選項(xiàng)保持默認(rèn)即可生成

注:webhook 是通知 Jenkins 的請(qǐng)求地址呈宇,GitHub 通過(guò)該地址通知 Jenkins 發(fā)生的事件

(2)配置 Personal access tokens,開放 admin:repo_hook(包含 write:repo_hook 和 read:repo_hook)即可

5.1.2 配置 jenkins

(1)主界面進(jìn)入 Manager Jenkins局雄,找到 Github 服務(wù)器 項(xiàng)

注:該配置項(xiàng)需安裝 GitHub Plugin 插件

(2)名稱 可任意輸入甥啄,能辨識(shí)即可

(3)API URL 保持默認(rèn) https://api.github.com 即可

(4)添加憑據(jù),類型選擇 Secret text炬搭,在 Secret 欄填入在 GitHub 生成的 Personal access tokens蜈漓;描述 欄可任意輸入,能辨識(shí)即可

(5)憑據(jù) 下拉菜單選擇新添加的憑據(jù)名稱后宫盔,點(diǎn)擊 連接測(cè)試融虽,若成功則配置完成

注:憑據(jù)不能使用 Username with password 類型

附加內(nèi)容:修改 jenkins 默認(rèn)的 Webhooks 地址可在 Github 服務(wù)器 項(xiàng)右下角點(diǎn)擊 高級(jí),出現(xiàn)的 覆蓋 Hook URL 即可重新指定飘言。

5.1.3 任務(wù)詳細(xì)配置

手動(dòng)構(gòu)建 基礎(chǔ)上增加如下配置:

(1)在 構(gòu)建觸發(fā)器 項(xiàng)中勾選 GitHub hook trigger for GiTScm polling

(2)在 構(gòu)建環(huán)境 項(xiàng)中勾選 Use secret text(s) or file(s)衣形,彈出菜單選擇 指定憑據(jù),選擇之前步驟設(shè)定的憑據(jù)別名姿鸿,變量欄 可空

完成上述設(shè)置后即可實(shí)現(xiàn)當(dāng) GitHub 庫(kù)分支有變動(dòng)時(shí)谆吴,如直接提交或從其他分支合并到該分支,就觸發(fā)構(gòu)建苛预。

5.2 前端及后端項(xiàng)目構(gòu)建成功后自動(dòng)部署到遠(yuǎn)端容器

5.2.1 公共配置部分

5.2.1.1 開啟 ssh 服務(wù)

(1)基礎(chǔ)鏡像 debian 默認(rèn)不帶 ssh句狼,執(zhí)行 apt-get install openssh-server 安裝

(2)service ssh start 啟動(dòng)服務(wù)

(3)ps -e | grep ssh 驗(yàn)證安裝

root@aa751ea246b2:/# ps -e | grep ssh
 2777 ?        00:00:00 sshd

注:若需要安裝 ps 命令,執(zhí)行 apt-get install procps 即可

5.2.1.2 root 賬號(hào)密碼設(shè)置

(1)開啟允許 root 登陸热某,執(zhí)行 vim /etc/ssh/sshd_config 修改配置文件腻菇,將 PermitRootLogin 項(xiàng)改為 yes(默認(rèn)值 prohibit-password 阻止密碼登陸;另有值 without-password 可不需密碼登陸)

(2)執(zhí)行 /etc/init.d/ssh restart 更新設(shè)置

(3)執(zhí)行 passwd root 修改 root 密碼

附加內(nèi)容:安裝 ssh 后添加普通權(quán)限用戶并設(shè)置密碼

useradd user
passwd user

5.2.1.3 root 免密登陸設(shè)置

(1)暫缺

備用:將 PasswordAuthentication 項(xiàng)改為 no(默認(rèn) yes 開啟密碼身份驗(yàn)證)

5.2.1.4 Publish over SSH 插件賬號(hào)+密碼連接設(shè)置

(1)進(jìn)入 系統(tǒng)配置 找到 Publish over SSH 的配置項(xiàng)昔馋,前幾項(xiàng)配置留空筹吐,直接展開高級(jí)設(shè)置,勾選Use password authentication, or use a different key秘遏,讓每個(gè)連接使用獨(dú)立設(shè)置的賬戶和密碼丘薛。

(2)填寫以下主要配置項(xiàng),其余可留空或保持默認(rèn)值

  • Name邦危,隨意填寫
  • Hostname洋侨,遠(yuǎn)端容器的 IP 地址
  • Username,填入 root
  • Remote Directoty倦蚪,遠(yuǎn)端容器接收傳輸文件的目錄路徑
  • Passphrase / Password希坚,填入賬戶對(duì)應(yīng)密碼

(2)測(cè)試設(shè)置,提示 Success 說(shuō)明連接正常

附加內(nèi)容:查看容器 IP 地址

  • 方式一:在宿主機(jī)執(zhí)行 docker inspect <容器ID>陵且,找到 IPAddress 即可
  • 方式二:進(jìn)入容器裁僧,執(zhí)行 ifconfig 即可

附加內(nèi)容:debian 安裝網(wǎng)絡(luò)命令

  • 安裝 ifconfig:apt-get install net-tools
  • 安裝 ping:apt-get install iputils-ping
  • 安裝 ip:apt-get install iproute2

5.2.1.5 Publish over SSH 插件免密連接設(shè)置

(1)暫缺

5.2.3 前端項(xiàng)目自動(dòng)部署詳細(xì)配置

當(dāng) master 分支有變動(dòng)時(shí),jenkins 容器負(fù)責(zé)從 github 獲取最新源代碼并執(zhí)行 npm build 構(gòu)建,將構(gòu)建結(jié)果锅知,即 build 目錄下內(nèi)容發(fā)送到遠(yuǎn)端容器接收目錄播急,發(fā)送之前清空接收目錄。主要路徑定義如下:

  • 遠(yuǎn)端容器接收目錄為 /usr/src/static
  • jenkins 容器從 github 獲得的源碼目錄為 /var/jenkins_home/workspace/testfrontend
  • jenkins 容器構(gòu)建后售睹,需要傳輸?shù)哪夸洖?/var/jenkins_home/workspace/testfrontend/build

(1)進(jìn)入項(xiàng)目配置桩警,在 構(gòu)建 環(huán)節(jié)增加 Send files or execute commands over SSH

(2)填寫以下主要配置項(xiàng),其余可留空或保持默認(rèn)值

  • Name昌妹,選擇在 系統(tǒng)配置 中定義的名稱
  • Source files捶枢,留空
  • Remove prefix,留空
  • Remote Directoty飞崖,留空
  • Exec command烂叔,填入以下命令:
cd /usr/src/
rm -rf static
mkdir static

(3)在 構(gòu)建后操作 環(huán)節(jié)增加 Send build artifacts over SSH,并填寫以下主要配置項(xiàng)固歪,其余可留空或保持默認(rèn)值

  • Name蒜鸡,選擇在 系統(tǒng)配置 中定義的名稱
  • Source files,填入 build/**
  • Remove prefix牢裳,填入 build
  • Remote Directoty逢防,留空
  • Exec command,留空

附加內(nèi)容:勾選 Send files or execute commands over SSH after the build runs 與在 構(gòu)建后操作 中添加 Send build artifacts over SSH 的區(qū)別:前者無(wú)論構(gòu)建是否成功都執(zhí)行蒲讯,后者需要構(gòu)建成功才執(zhí)行忘朝。

5.2.4 后端項(xiàng)目自動(dòng)部署詳細(xì)配置

5.2.4.1 建立應(yīng)用容器

后端項(xiàng)目案例使用 Amazon Corretto 11,但官方鏡像選擇的基礎(chǔ)鏡像使用上多有不便判帮,因此選用 debian 自行創(chuàng)建局嘁。

(1)基礎(chǔ)鏡像選擇 debian:stable-20200414

(2)按照 官方文檔 的安裝方式

(3)安裝 JDK 之前,請(qǐng)安裝 java-common 軟件包

apt-get update
apt-get install java-common

(4)從 下載 頁(yè)面下載 Linux .deb 文件晦墙。

注:可能需要安裝 wget 命令悦昵,執(zhí)行 apt-get install wget 即可

(5)安裝 .deb 文件。

dpkg --install java-11-amazon-corretto-jdk_11.0.3.7-1_amd64.deb

注:stable-slim 鏡像無(wú)法用該方法安裝 jdk11晌畅,原因暫時(shí)未知

5.2.4.2 配置

當(dāng) master 分支有變動(dòng)時(shí)旱捧,jenkins 容器負(fù)責(zé)從 github 獲取最新源代碼,并使用 gradle 構(gòu)建踩麦,將構(gòu)建結(jié)果,即 build/libs 目錄下 jar 包發(fā)送到遠(yuǎn)端容器接收目錄氓癌,發(fā)送之前清空接收目錄谓谦。主要路徑定義如下:

  • 遠(yuǎn)端容器接收目錄為 /usr/src/jdkapp
  • jenkins 容器從 github 獲得的源碼目錄為 /var/jenkins_home/workspace/testbackend
  • jenkins 容器構(gòu)建后,需要傳輸?shù)奈募?/var/jenkins_home/workspace/testbackend/build/libs/demo.jar

(1)進(jìn)入項(xiàng)目配置贪婉,在 構(gòu)建 環(huán)節(jié)增加 Send files or execute commands over SSH

(2)填寫以下主要配置項(xiàng)反粥,其余可留空或保持默認(rèn)值

  • Name,選擇在 系統(tǒng)配置 中定義的名稱
  • Source files,留空
  • Remove prefix才顿,留空
  • Remote Directoty莫湘,留空
  • Exec command,填入以下命令:
cd /usr/src/
rm -rf jdkapp
mkdir jdkapp

(3)在 構(gòu)建后操作 環(huán)節(jié)增加 Send build artifacts over SSH郑气,并填寫以下主要配置項(xiàng)幅垮,其余可留空或保持默認(rèn)值

  • Name,選擇在 系統(tǒng)配置 中定義的名稱
  • Source files尾组,填入 build/libs/*.jar
  • Remove prefix忙芒,填入 build/libs
  • Remote Directoty,留空
  • Exec in pty讳侨,勾選該項(xiàng)復(fù)選框呵萨,開啟偽終端
  • Exec command,填入以下命令:
cd /usr/src/
cat /dev/null > nohup.out
nohup sh runjdkapp.sh

對(duì)應(yīng)的 runjdkapp.sh 文件參考內(nèi)容如下:

#!/bin/bash
port=3006
filter=$(netstat -ntlp | grep $port | awk '{print $7}' | awk -F '/' '{print $1}')
for var in $filter
do
  kill -9 $var
done
nohup java -jar /usr/src/jdkapp/demo.jar &

注:可能需要安裝 netstat 命令跨跨,執(zhí)行 apt-get install net-tools 即可

5.2.5 主要配置項(xiàng)釋義

以前端項(xiàng)目為例:

  • Flatten files潮峦,扁平化文件。只上傳文件勇婴,不上傳文件所屬文件夾忱嘹。

  • Source files,需要傳輸?shù)奈募毓ⅰH粢獋鬏斈夸浀铝拢聪喈?dāng)于傳輸其下所有文件,例如:build/**萨螺,可參看 規(guī)則窄做。注意,構(gòu)建后所在路徑位置默認(rèn)指向工作空間慰技,即 /var/jenkins_home/workspace/testfrontend椭盏,因此該配置項(xiàng)直接用目錄名 build 即可,不用寫長(zhǎng)串內(nèi)容吻商。

  • Remove prefix掏颊,移除傳輸文件路徑前綴。該配置項(xiàng)可結(jié)合以上 Source files 的例子來(lái)看艾帐。若留空乌叶,則遠(yuǎn)端最終結(jié)果是 /usr/src/static 目錄下還有一層 build 目錄,不符合需求柒爸,因此需要把「前綴」移除准浴,則所需文件路徑不帶 build/ 前綴,就直接放到 /usr/src/static 目錄下捎稚。

  • Remote directoty乐横,在目標(biāo)目錄下創(chuàng)建一個(gè)新目錄求橄。該項(xiàng)若留空,則直接將文件放到本案例中的 /usr/src/static 下葡公,假設(shè)填寫 var罐农,將文件放到本案例中的 /usr/src/static/var 下。

以 index.html 路徑為例催什,上述配置效果可見(jiàn)下表:

Remote Directoty(系統(tǒng)配置) Source files Remove prefix Remote Directoty(項(xiàng)目配置) 結(jié)果
1 /usr/src/static build/** build /usr/src/static/index.html
2 /usr/src/static build/** /usr/src/static/build/index.html
3 /usr/src/static build/** var /usr/src/static/var/build/index.html
4 /usr/src/static build/** build var /usr/src/static/var/index.html

6 其他問(wèn)題

6.1 提示內(nèi)存不足涵亏,構(gòu)建失敗

進(jìn)入 jenkins 查看失敗的控制臺(tái)輸出,其中有如下信息:

OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000e0000000, 89456640, 0) failed; error='Not enough space' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 89456640 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /var/jenkins_home/.gradle/daemon/5.6.2/hs_err_pid2363.log

進(jìn)一步查看上述 gradle 的日志文件蛆楞,其中有如下內(nèi)容:

root@832c29984d24:/var/jenkins_home/.gradle/daemon/5.6.2# cat hs_err_pid2363.log
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 89456640 bytes for committing reserved memory.
# Possible reasons:
# The system is out of physical RAM or swap space
# The process is running with CompressedOops enabled, and the Java Heap may be blocking the growth of the native heap
# Possible solutions:
# Reduce memory load on the system
# Increase physical memory or swap space
# Check if swap backing store is full
# Decrease Java heap size (-Xmx/-Xms)
# Decrease number of Java threads
# Decrease Java thread stack sizes (-Xss)
# Set larger code cache with -XX:ReservedCodeCacheSize=
# This output file may be truncated or incomplete.
#
# Out of Memory Error (os_linux.cpp:2718), pid=2363, tid=2364
#
# JRE version: (11.0.3+7) (build )
# Java VM: OpenJDK 64-Bit Server VM (11.0.3+7-LTS, mixed mode, aot, sharing, tiered, compressed oops, serial gc, linux-amd64)
# Core dump will be written. Default location: /var/jenkins_home/.gradle/daemon/5.6.2/core.2363

根據(jù)可能的原因進(jìn)行排查溯乒,首先執(zhí)行 free,發(fā)現(xiàn) swap 大小為 0

total        used        free      shared  buff/cache   available
Mem: 1014728 570788 216884 6372 227056 297800
swap: 0 0 0

6.1.1 Linux swap 交換分區(qū)的配置

6.1.1.1 swap 交換分區(qū)的作用

Linux swap 交換分區(qū)豹爹,即為虛擬內(nèi)存裆悄。當(dāng) Linux 系統(tǒng)的物理內(nèi)存不夠用的時(shí)候,就需要將物理內(nèi)存中的一部分空間釋放出來(lái)臂聋,以供當(dāng)前運(yùn)行的程序使用光稼。那些被釋放的空間可能來(lái)自一些很長(zhǎng)時(shí)間沒(méi)有什么操作的程序,這些被釋放的空間被臨時(shí)保存到 swap 空間中孩等,等到那些程序要運(yùn)行時(shí)艾君,再?gòu)?swap 中恢復(fù)保存的數(shù)據(jù)到內(nèi)存中。這樣肄方,系統(tǒng)總是在物理內(nèi)存不夠時(shí)冰垄,才進(jìn)行 swap 交換。避免應(yīng)用程序內(nèi)存不足錯(cuò)誤的最簡(jiǎn)單方法之一是為服務(wù)器添加一些 swap 空間权她。

注:雖然建議對(duì)使用傳統(tǒng)機(jī)械硬盤驅(qū)動(dòng)器的系統(tǒng)進(jìn)行交換虹茶,但對(duì)于 SSD 來(lái)說(shuō),使用 swap 可能會(huì)導(dǎo)致硬件隨著時(shí)間的推移而出現(xiàn)問(wèn)題隅要。出于這種考慮蝴罪,不建議在任何其他使用 SSD 存儲(chǔ)上啟用 swap。這樣做會(huì)影響底層硬件的可靠性步清。

6.1.1.2 查看信息

可執(zhí)行 swapon --show要门,若沒(méi)有任何信息輸出,說(shuō)明沒(méi)有可用的 swap 空間廓啊。也可以使用 free 查看活動(dòng)的 swap

6.1.1.3 大小

一般來(lái)說(shuō)可以按照如下規(guī)則設(shè)置大谢端选:

  • 4G 以內(nèi)的物理內(nèi)存,swap 設(shè)置為內(nèi)存的 2 倍谴轮。
  • 4-8G 的物理內(nèi)存狂巢,swap 等于內(nèi)存大小。
  • 8-64G 的物理內(nèi)存书聚,swap 設(shè)置為 8G唧领。
  • 64-256G 物理內(nèi)存,swap 設(shè)置為 16G雌续。

實(shí)際上斩个,系統(tǒng)中交換分區(qū)的大小并不取決于物理內(nèi)存的量,而是取決于系統(tǒng)中內(nèi)存的負(fù)荷驯杜,所以在安裝系統(tǒng)時(shí)要根據(jù)具體的業(yè)務(wù)來(lái)設(shè)置 swap 的值受啥。

6.1.1.4 設(shè)置

系統(tǒng)并不是等所有的物理內(nèi)存都消耗完畢之后,才去使用 swap 的空間鸽心,什么時(shí)候使用是由 swappiness 參數(shù)值控制滚局。

cat /proc/sys/vm/swappiness
60

該值默認(rèn)值是 60

  • swappiness=0 的時(shí)候表示最大限度使用物理內(nèi)存,然后才是 swap 空間顽频,

  • swappiness = 100 的時(shí)候表示積極的使用 swap 分區(qū)藤肢,并且把內(nèi)存上的數(shù)據(jù)及時(shí)的搬運(yùn)到 swap 空間里面。

注:可以把這個(gè)參數(shù)值設(shè)置的低一些糯景,讓操作系統(tǒng)盡可能的使用物理內(nèi)存嘁圈,降低系統(tǒng)對(duì) swap 的使用,從而提高系統(tǒng)的性能蟀淮。與 swap 文件的交互是費(fèi)時(shí)的最住,因?yàn)樗鼈儽扰c RAM 的交互花費(fèi)更長(zhǎng)的時(shí)間,并且它們可能導(dǎo)致性能的顯著降低怠惶。

  • 臨時(shí)性修改:
sysctl vm.swappiness=10
vm.swappiness = 10

cat /proc/sys/vm/swappiness
10

這里我們的修改已經(jīng)生效涨缚,但是如果我們重啟了系統(tǒng),又會(huì)變成 60.

  • 永久修改:

在 /etc/sysctl.conf 文件里添加如下參數(shù):

vm.swappiness=10

然后重啟系統(tǒng)

6.1.1.5 配置

(1)查看目前磁盤使用情況策治,執(zhí)行 df -h

[root@54s9uer src]# df -h
文件系統(tǒng) 容量 已用 可用 已用% 掛載點(diǎn)
devtmpfs 486M 0 486M 0% /dev
tmpfs 496M 0 496M 0% /dev/shm
tmpfs 496M 57M 440M 12% /run
tmpfs 496M 0 496M 0% /sys/fs/cgroup
/dev/vda1 32G 7.8G 23G 26% /
tmpfs 100M 0 100M 0% /run/user/0
overlay 32G 7.8G 23G 26% /var/lib/docker/overlay2/c2b2dedef134be83b420347470f5bc0cf9ff0f/merged
overlay 32G 7.8G 23G 26% /var/lib/docker/overlay2/3bbd16437dc11ff7ed36ca4c6e60642ef8dbfa/merged

/dev/vda1 是實(shí)際使用的磁盤脓魏,swap 即可從這里設(shè)置容量

注:設(shè)置 swap 分區(qū)應(yīng)在宿主機(jī)進(jìn)行

注:通常,等于或雙倍于系統(tǒng)內(nèi)存的量是一個(gè)很好的選擇览妖。如果只是將其用作 RAM 后備轧拄,那么 swap 分區(qū)盡可能不要超過(guò) 4G。

(2)在根目錄創(chuàng)建 swap 文件

fallocate -l 1G /swapfile

(3)查看是否分配了正確的大小

[root@54s9uer src]# ls -lh /swapfile
-rw------- 1 root root 1.0G 4 月 11 23:32 /swapfile

(4)設(shè)置權(quán)限讽膏。執(zhí)行 chmod 600 /swapfile

(4)標(biāo)記 swap 分區(qū)檩电。執(zhí)行 mkswap /swapfile

(5)啟動(dòng) swap 分區(qū)。執(zhí)行 swapon /swapfile

注:執(zhí)行上述命令后可能出現(xiàn)以下提示府树,但是使用 swapon --showfree -m 命令俐末,可見(jiàn) swap 分區(qū)已經(jīng)配置成功:

swapon: /swapfile:swapon 失敗: 設(shè)備或資源忙

附加內(nèi)容:關(guān)閉 swap

swapoff /swapfile

6.1.1.6 保持配置

上述配置在服務(wù)器重新啟動(dòng)后,將不會(huì)自動(dòng)保留奄侠∽矿铮可將交換文件添加到 /etc/fstab 來(lái)進(jìn)行保留

(1)為了避免出現(xiàn)任何問(wèn)題,先備份 /etc/fstab 文件

cp /etc/fstab /etc/fstab.bak

(2)將下列 swap 文件信息添加到 /etc/fstab 文件末尾

echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

6.2 自動(dòng)部署后端項(xiàng)目時(shí)的問(wèn)題

若將 runjdkapp.sh 代碼直接填入 Exec command垄潮,會(huì)產(chǎn)生構(gòu)建成功后能夠運(yùn)行但無(wú)法自行退出烹卒,最終超時(shí)的問(wèn)題闷盔,jenkins 會(huì)判斷構(gòu)建失敗。部分相關(guān)日志如下:

ERROR: Exception when publishing, exception message [Exec timed out or was interrupted after 120,000 ms]
Build step 'Send build artifacts over SSH' changed build result to UNSTABLE
Finished: UNSTABLE

必須勾選 Exec in pty 復(fù)選框旅急,并將代碼形成 sh 文件后再添加一個(gè) nohup 才能夠正常構(gòu)建(參見(jiàn)前文步驟)逢勾。

有關(guān)討論可詳見(jiàn):

進(jìn)行上述設(shè)置后,項(xiàng)目可正常構(gòu)建和部署藐吮,會(huì)出現(xiàn)以下信息:

nohup: ignoring input and appending output to 'nohup.out'
SSH: EXEC: completed after 200 ms

因此可在運(yùn)行項(xiàng)目之前使用 cat /dev/null > nohup.out 清空該文件

附加內(nèi)容:清空文件

  • 方式一:cat /dev/null > nohup.out
  • 方式二:echo "" > nohup.out
  • 方式三:> nohup.out
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末溺拱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子谣辞,更是在濱河造成了極大的恐慌迫摔,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泥从,死亡現(xiàn)場(chǎng)離奇詭異句占,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)歉闰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門辖众,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人和敬,你說(shuō)我怎么就攤上這事凹炸。” “怎么了昼弟?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵啤它,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我舱痘,道長(zhǎng)变骡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任芭逝,我火速辦了婚禮塌碌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旬盯。我一直安慰自己台妆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布胖翰。 她就那樣靜靜地躺著接剩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪萨咳。 梳的紋絲不亂的頭發(fā)上懊缺,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音培他,去河邊找鬼鹃两。 笑死遗座,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的俊扳。 我是一名探鬼主播员萍,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拣度!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起螃壤,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤抗果,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后奸晴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冤馏,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年寄啼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了逮光。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡墩划,死狀恐怖涕刚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情乙帮,我是刑警寧澤杜漠,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站察净,受9級(jí)特大地震影響驾茴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜氢卡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一锈至、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧译秦,春花似錦峡捡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至雷猪,卻和暖如春睛竣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背求摇。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工射沟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留殊者,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓验夯,卻偏偏與公主長(zhǎng)得像猖吴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挥转,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容