Docker 入門(三):持續集成、持續部署

在軟件開發過程當中,若是咱們每一次提交的代碼都可以進行一次完整的編譯、測試、打包、發佈,就能及早發現問題、及早修復,在保證代碼質量的同時讓產品快速迭代。這就是持續集成(CI)、持續部署(CD)的好處。java

目前 CI/CD 的方案有不少,本文將展現一個用 Docker + Jenkins 實現的完整過程。node

本文的 CI/CD 流程

開發人員提交代碼到本身的分支並 push 到遠程倉庫 ==> 觸發遠程倉庫(GitHub/GitLab)的 Webhooks ==> Jenkins 接到通知自動執行以前準備好的一個流程(克隆代碼,對代碼進行編譯、測試、打包,沒有問題後會執行 docker 命令進行鏡像構建)==> 最終發佈到測試服務器中。react

環境說明

  • 本文選用的測試環境是阿里雲的服務器,因此全程也是在服務器上操做的,無需本地安裝 docker,固然在本地操做也是能夠的。
  • 本文選用的遠程代碼庫是 GitHub 公有倉庫,若是是私有倉庫或 GitLab,步驟會略有不一樣。
  • 本文中所用的 Jenkins 也是用的 docker 版,並非直接安裝在宿主機上的。

開始一個 docker 應用

要演示整個過程,就得有一個應用,這裏咱們用一個 create-react-app 爲例,無需 IDE,一個 terminal 便可搞定。linux

  • 首先建立 react-app 和 Dockerfile
四、5 行是增長了一個設置,是關掉 webpack 的 host 檢查,若是不加此項,訪問綁定域名的服務器就會被 webpack-dev-server 攔截。
$ npm install -g create-react-app
$ create-react-app my-app
$ cd my-app
$ touch .env
$ echo DANGEROUSLY_DISABLE_HOST_CHECK=true > .env
$ touch Dockerfile
  • 將如下內容寫入 Dockerfile:
爲了簡單,咱們這裏直接採用 npm start 的方式啓動它,就不 build 了,安裝 cnpm 是爲了提升依賴的下載速度
FROM node:8.11.1-slim

WORKDIR /home/app

COPY . ${WORKDIR}

RUN npm install -g cnpm --registry=https://registry.npm.taobao.org \
    && cnpm install

EXPOSE 3000

ENTRYPOINT [ "npm", "start" ]
  • 到這裏就徹底好了,單元測試什麼的就暫且忽略。

爲何要使用 Jenkins

若是沒有 Jenkins,就上面那個例子,咱們想要將本身的代碼集成而且部署到服務器,可能要經歷如下步驟:webpack

  • 一、將代碼 push 到倉庫
  • 二、ssh 登陸服務器,克隆代碼到宿主機(宿主機還要安裝 git)
  • 三、執行如下命令完成鏡像構建和部署
$ cd repository
$ docker build -t test .
$ docker run -d -p 80:3000 --name my-react test

能夠看到上面那個過程須要人工操做,很是繁瑣,這還沒算上對代碼進行測試,若是每次提交了代碼都要來一個這樣的過程,那是真的無法專心搞開發了。git

若是用了 Jenkins,上面的整個過程均可以自動化完成。web

初始化 Jenkins

Jenkins 的官網是 jenkins.io,它有不少種安裝方式,例以下載 war 包到宿主機上,而後用 java -jar jenkins.war 命令啓動。可是這種安裝方式很是不利於管理和服務器的遷移,徹底是在給 docker 託後腿。因此我選擇用 docker 版的 jenkins。docker

使用 docker 版的 jenkins 是須要注意不少細節的shell

  • 首先咱們要重寫官方 jenkins 鏡像
$ vi Dockerfile
FROM jenkins/jenkins:lts

USER root

RUN echo deb http://mirrors.aliyun.com/debian wheezy main contrib non-free \
    deb-src http://mirrors.aliyun.com/debian wheezy main contrib non-free \
    deb http://mirrors.aliyun.com/debian wheezy-updates main contrib non-free \
    deb-src http://mirrors.aliyun.com/debian wheezy-updates main contrib non-free \
    deb http://mirrors.aliyun.com/debian-security wheezy/updates main contrib non-free \
    deb-src http://mirrors.aliyun.com/debian-security wheezy/updates main contrib non-free \
    > /etc/apt/sources.list \
    && apt-get update \
    && apt-get install -y libltdl-dev
這裏用了 jenkins 最新穩定版最爲基礎鏡像,主要乾了兩件事:1、將帳戶改成 root,避免後面沒必要要的權限問題;2、安裝 libltdl-dev ,它是爲了解決用 jenkins 調用容器外部 docker 命令時發生 如下錯誤的問題。(第 4~10 行是爲了換阿里源提升速度)
docker: error while loading shared libraries: libltdl.so.7: cannot open shared object file: No such file or directory
  • 在啓動剛剛重寫好的 jenkins 鏡像的時候還須要掛載三個宿主機的目錄到容器內,第一個 jenkins_home 是爲了對容器內 jenkins 的全部改動作數據持久化。最後兩個目錄是爲了能讓容器內的 jenkins 調用並操做容器外的 docker
$ vi docker-compose.yml
version: "3"
services:
 jenkins:
  build: .
  image: my_jenkins
  ports:
    - "8090:8080"
    - "50000:50000"
  container_name: my_jenkins
  volumes:
    - "/home/jenkins_home:/var/jenkins_home"
    - "/var/run/docker.sock:/var/run/docker.sock"
    - "/usr/bin/docker:/usr/bin/docker"
爲了看起來清晰,我寫了一個 docker-compose.yml 文件,將這個文件和以前的 Dockerfile 放在同一個目錄中,能夠用如下命令快速啓動 jenkins,啓動以後新構建的鏡像和容器都名爲 my_jenkins。
$ docker-compose up -d
  • 啓動 jenkins 後瀏覽器訪問 ip:8090 可看到初始化頁面

這裏要輸入密碼,它給出了密碼在容器內的位置,咱們要將路徑改爲宿主機上的,而後 cat 一下就能看到密碼。
$ cat /home/jenkins_home/secrets/initialAdminPassword
  • 將密碼粘貼進去而後點繼續,下一個頁面選擇插件,點默認推薦的就行了

  • 接着按提示建立一個帳戶

  • 以後就可以使用 jenkins 了

配置 Webhooks

要讓 jenkins 操做本機上的 docker 的前提是它收到了咱們 push 代碼的通知,而這個通知就是由 GitHub 上的 Webhooks 來完成的,因此要將這二者關聯起來。npm

  • 配置 Webhooks 以前首先要更改一下安全設置
打開全局安全配置,軟後進行以下操做,不然 Webhooks 鏈接不成功,設置好了別忘了點保存。

  • 開始建立任務
點擊首頁的「開始建立一個新任務」,起個名字,選擇流水線。

  • 生成身份令牌
點擊「構建觸發器」,選擇「觸發遠程構建」,而後隨便填寫一段字符,而後把 URL 複製下來,記得把「JENKINS_URL」和「TOKEN_NAME」替換爲相應的值,例以下圖最終獲得的 URL 就是 111.11.1.1:8090/job/test/build?token=123456,記下 URL 後點保存。

  • 去 GitHub 建立 Webhooks
打開咱們要 push 代碼的倉庫,點擊「Add webhook」

而後將剛纔記下的回調 URL 填寫到這裏便可

此時,能夠嘗試一下 push 代碼到倉庫,正常狀況下,jenkins 就會自動進行構建,雖然沒有配置要構建什麼,可是它也會進行這個任務,若是構建歷史中自動出現了一個顏色是藍色的任務則表明整個自動觸發的過程是配置成功的。

編寫自動任務腳本進行 CI/CD

  • 點擊上面那個任務的「配置」,切換到流水線這裏。本文不介紹流水線語法,就用 shell 命令來編寫整個過程。但咱們首先仍是要點擊「流水線語法」

  • 將示例步驟切換到「sh: Shell Script」,編寫好 shell 腳本,熟悉 linux 命令的話,這個過程也應該很容易。寫好以後點擊「生成流水線腳本」,以後把生成好的流水線腳本複製下來

  • 將生成好的 流水線腳本複製到這裏就行了,不過要把它複製到一個 node{} 裏面才行。

如下是我寫的生成好的流水線腳本,記得把定義的四個變量替換一下。
node {
    sh '''#!/bin/sh

    REPOSITORY_NAME="你的倉庫名"
    REPOSITORY_URL="你的倉庫地址"
    IMAGE_NAME="給你要構建的鏡像起個名字"
    CONTAINER_NAME="給你要構建的容器起個名字"
       
    echo "清除倉庫目錄"
    rm ${REPOSITORY_NAME} -r
       
    echo "克隆遠程倉庫"
    git clone ${REPOSITORY_URL}

    echo "刪除以前的鏡像和容器"
    docker stop ${CONTAINER_NAME}
    docker rm ${CONTAINER_NAME}
    docker rmi ${IMAGE_NAME}
    
    echo "構建鏡像"
    cd ${REPOSITORY_NAME}
    docker build -t ${IMAGE_NAME} .
    
    echo "發佈應用"
    docker run -d -p 80:3000 --name ${CONTAINER_NAME} ${IMAGE_NAME}'''

}
  • 最後能夠提交一次代碼或者點擊「當即構建」,就會自動完成整個過程,在「控制檯輸出」那裏能夠看到構建過程。

此時,瀏覽器訪問 ip 就能看到更新過的應用了,這就是一個 CI/CD 過程,整個過程省略的測試環節,可自行加上。

後記

用一個測試服務器來作 CI/CD,可以更及時的發現問題、解決問題,提升代碼質量。

可是本文所展現的過程缺陷也很明顯,在更新應用時,是會先停掉容器,再啓動新容器的,不能作到無宕機更新。並且整個過程也沒有服務監控什麼的,不能很好地瞭解無服務的運行狀態。

總之,到目前爲止,咱們已經可以很好地將 docker 用在平常的開發中了。

點擊查看博客原文

相關文章
相關標籤/搜索