使用 Jenkins 借助 Docker 实现自动化部署

孙博 技术分享
Docker Jenkins CI/CD DevOps

使用Docker部署站点已经很方便了,但是手敲命令还是会存在一定的风险——有可能因为写错命令导致生产环境挂掉、不方便多人操作等,因此我们可以选择一些常见的CI/CD工具帮我们完成这个工作。

这里向大家推荐的是Jenkins的解决方案。我们可以将Jenkins通过Docker部署,并使用Jenkins管理其他应用的编译与部署,由于Jenkins官方已经提供了Docker镜像,所以我们只需简单的命令就能让其跑起来。(命令中/var/jenkins为宿主机用于存放Jenkins运行所需的文件,请根据自身实际情况替换

Docker部署Jenkins

#/bin/bash
sudo docker run \
  -u root \
  -d \
  -p 8080:8080 \
  -p 50000:50000 \
  -v /var/jenkins:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --name jenkins \
  --restart=always \
  jenkinsci/blueocean

使用Jenkins创建一个自由软件项目(Freestyle project),设置完git的相关配置后,在Build环节添加一个Execute Shell,并填入类似下方的编译脚本用来编译。编译的过程其实就是根据Dockerfile来制作一个镜像,为了省事,我们使用<span class="katex-error" title="ParseError: KaTeX parse error: Expected &#x27;EOF&#x27;, got &#x27;#&#x27; at position 67: …改成不同的tag`规则。

#̲# 编译脚本

…" style="color:#cc0000">{BUILD_NUMBER}`来使每次生成的镜像时打的`tag`都不同。用户也可以根据自己的实际需要更改成不同的`tag`规则。

## 编译脚本
```bash
echo &#x27;&gt;&gt;&gt; DOCKER BUILD START&#x27;

docker build -t</span>{JOB_NAME}:1.0.<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>B</mi><mi>U</mi><mi>I</mi><mi>L</mi><msub><mi>D</mi><mi>N</mi></msub><mi>U</mi><mi>M</mi><mi>B</mi><mi>E</mi><mi>R</mi></mrow><mi mathvariant="normal">.</mi><mi mathvariant="normal">∣</mi><mi>t</mi><mi>e</mi><mi>e</mi></mrow><annotation encoding="application/x-tex">{BUILD_NUMBER} . | tee</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal" style="margin-right:0.10903em;">U</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal">L</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10903em;">N</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.10903em;">U</span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span></span><span class="mord">.∣</span><span class="mord mathnormal">t</span><span class="mord mathnormal">ee</span></span></span></span>{WORKSPACE}/docker_build_result.log
RESULT=<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>c</mi><mi>a</mi><mi>t</mi></mrow><annotation encoding="application/x-tex">(cat</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">c</span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span></span></span></span>{WORKSPACE}/docker_build_result.log | tail -n 1)
#if [["<span class="katex-error" title="ParseError: KaTeX parse error: Expected &#x27;EOF&#x27;, got &#x27;#&#x27; at position 34: …sfully*]];then
#̲  exit -1
#fi

…" style="color:#cc0000">RESULT&quot; != *Successfully*]];then
#  exit -1
#fi

echo &#x27;&gt;&gt;&gt; DOCKER BUILD SUCCESSFULLY&#x27;

编译完成后,我们需要将最新镜像部署起来。由于一个端口只能被一个应用监听,所以我们并不能通过简单的docker run来运行容器,我们需要先将原来运行中的旧版本的容器先关掉,才能部署新版本的镜像。部署脚本如下所示,其中端口号20001为手动指定的项目专用的端口号,如果自己的项目有其他要求,也可以任意按照自己的需求进行更新。

部署脚本

echo &#x27;&gt;&gt;&gt; DOCKER DEPLOY START&#x27;

CID=</span>(docker ps | grep "<span class="katex-error" title="ParseError: KaTeX parse error: Expected &#x27;}&#x27;, got &#x27;EOF&#x27; at end of input: …&quot; | awk &#x27;{print" style="color:#cc0000">{JOB_NAME}&quot; | awk &#x27;{print</span>1}')
if [ "<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi><mi>I</mi><mi>D</mi><mi mathvariant="normal">&quot;</mi><mo stretchy="false">!</mo><mo>=</mo><mi mathvariant="normal">&quot;</mi><mi mathvariant="normal">&quot;</mi><mo stretchy="false">]</mo><mo separator="true">;</mo><mi>t</mi><mi>h</mi><mi>e</mi><mi>n</mi><mi>e</mi><mi>c</mi><mi>h</mi><msup><mi>o</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo>&gt;</mo><mo>&gt;</mo><mo>&gt;</mo><mi>D</mi><mi>O</mi><mi>C</mi><mi>K</mi><mi>E</mi><mi>R</mi><mi>R</mi><mi>E</mi><mi>O</mi><mi>M</mi><mi>V</mi><mi>E</mi><mi>O</mi><mi>L</mi><mi>D</mi><mi>C</mi><mi>O</mi><mi>N</mi><mi>T</mi><mi>A</mi><mi>I</mi><mi>N</mi><mi>E</mi><msup><mi>R</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mi>d</mi><mi>o</mi><mi>c</mi><mi>k</mi><mi>e</mi><mi>r</mi><mi>c</mi><mi>o</mi><mi>n</mi><mi>t</mi><mi>a</mi><mi>i</mi><mi>n</mi><mi>e</mi><mi>r</mi><mi>s</mi><mi>t</mi><mi>o</mi><mi>p</mi></mrow><annotation encoding="application/x-tex">CID&quot; != &quot;&quot; ];then
  echo &#x27;&gt;&gt;&gt; DOCKER REOMVE OLD CONTAINER&#x27;
  docker container stop</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mord">&quot;</span><span class="mclose">!</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.0019em;vertical-align:-0.25em;"></span><span class="mord">&quot;&quot;</span><span class="mclose">]</span><span class="mpunct">;</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">t</span><span class="mord mathnormal">h</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal">ec</span><span class="mord mathnormal">h</span><span class="mord"><span class="mord mathnormal">o</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">&gt;&gt;&gt;</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.9463em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal" style="margin-right:0.22222em;">V</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal">L</span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7519em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mord mathnormal">d</span><span class="mord mathnormal">oc</span><span class="mord mathnormal" style="margin-right:0.03148em;">k</span><span class="mord mathnormal" style="margin-right:0.02778em;">er</span><span class="mord mathnormal">co</span><span class="mord mathnormal">n</span><span class="mord mathnormal">t</span><span class="mord mathnormal">ain</span><span class="mord mathnormal" style="margin-right:0.02778em;">er</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal">o</span><span class="mord mathnormal">p</span></span></span></span>CID
  docker container rm <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi><mi>I</mi><mi>D</mi><mi>f</mi><mi>i</mi><mi>d</mi><mi>o</mi><mi>c</mi><mi>k</mi><mi>e</mi><mi>r</mi><mi>r</mi><mi>u</mi><mi>n</mi><mo>−</mo><mi>p</mi><mn>20001</mn><mo>:</mo><mn>80</mn><mo>−</mo><mi>d</mi><mo>−</mo><mo>−</mo><mi>n</mi><mi>a</mi><mi>m</mi><mi>e</mi></mrow><annotation encoding="application/x-tex">CID
fi
docker run -p 20001:80 -d --name</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mord mathnormal">i</span><span class="mord mathnormal">d</span><span class="mord mathnormal">oc</span><span class="mord mathnormal" style="margin-right:0.03148em;">k</span><span class="mord mathnormal" style="margin-right:0.02778em;">er</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal">u</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8389em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span><span class="mord">20001</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">80</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord">−</span><span class="mord mathnormal">nam</span><span class="mord mathnormal">e</span></span></span></span>{JOB_NAME} <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>J</mi><mi>O</mi><msub><mi>B</mi><mi>N</mi></msub><mi>A</mi><mi>M</mi><mi>E</mi></mrow><mo>:</mo><mn>1.0.</mn></mrow><annotation encoding="application/x-tex">{JOB_NAME}:1.0.</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.09618em;">J</span><span class="mord mathnormal" style="margin-right:0.02778em;">O</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.0502em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10903em;">N</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1.0.</span></span></span></span>{BUILD_NUMBER}
echo '>>> DOCKER DEPLOY SUCCESSFULLY'

根据示例的脚本可以快速的实现项目的自动化部署,但是这些脚本并不完美,它并不能够支持“平滑发布”,在新容器启起来之前,访问站点的用户会有明显的中断,用户体验较为不好。所以对于面向C端的使用者,可以随机指定端口,并通过与Nginx配置upstream协同完成部署工作,此处介于篇幅所限不做过多介绍。