docker ci cd docker-compose jenkins sonar

使用Docker一鍵部署CI、CD環境

曾克維 2018/12/26 11:52:51
8327

使用Docker一鍵部署CI、CD環境


簡介

利用 Docker 來建立持續性整合與發佈的環境,並達到「一鍵部署」的目標。

作者

曾克維


使用Docker一鍵部署CI、CD環境

 

前言

在軟體開發的過程中,我們常常會需要導入 CI(Continuous Integration)、CD(Continuous Delivery) 流程來增加軟體開發的品質、效率。

但每次開始新的專案都需要重新部署設定 CI、CD 環境十分耗時與費力。

因此接下來我們將利用 Docker 來建立持續性整合與發佈的環境,並達到「一鍵部署」的目標。

CI、CD 架構(範例)

以下將以此架構來建立 CI、CD 的環境:

Jenkins 由 Bitbucket 取得原始碼後,交由 Sonaqube 進行安全性掃描,接者進行打包並部署至 JBoss 上。

NOTE: 此架構為簡單的範例,可依實際需求做調整

開始前準備

  1. Docker

開始建置

Step 1:啟動 Docker

執行 Docker,查詢版本確認已啟動

$ docker version

Client:
 Version:      17.09.0-ce
 API version:  1.32
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:40:09 2017
 OS/Arch:      darwin/amd64

Server:
 Version:      17.09.0-ce
 API version:  1.32 (minimum version 1.12)
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:45:38 2017
 OS/Arch:      linux/amd64
 Experimental: true

 

Step 2:從 Docker Hub 上尋找適合的 image

兩種方式搜尋 Docker Hub 上的 image:

  1. 下指令搜尋
$ docker search jenkins
  1. 至 Docker Hub 網站搜尋

Jenkins

下圖為搜尋「Jenkins」的結果,通常若有官方提供的 image,會優先選擇。

但 Jenkins 官方提供的 image,已經被棄用不再維護,官方建議使用由 Jenkins 社群維護的 image「jenkins/jenkins:lts」。

因此我們選擇「jenkins/jenkins:lts」作為 Jenkins 的 image。

Image Tags

jenkins/jenkins:lts」冒號左邊為 image name,右邊即是 image tag,image tag 代表此 image 的某個特定版本,若不特別指定預設為 latest 也就是最新的版本。

此處選擇的 lts 為長期維護的版本(Long Term Support)。

可點選「Tags」查看此 image 提供哪些版本:

Sonaqube

選擇 Sonaqube 官方提供的 image「sonarqube:lts」。

Postgres

選擇 Postgres 官方提供的 image「postgres」,因為沒有特別提供 lts 的版本,所以使用預設的最新版本 latest

JBoss

因為 JBoss 官方並沒有提供公開的 image,所以接下來將示範如何自製 JBoss image,當然您也可以選擇 JBoss 的開源版本 Wildfly 來取代。

Step 3:Docker Hub 上沒有合適的 image 怎麼辦?

DIY 一個適合自己的 image 吧,以下將自製架構中的 JBoss image。

需要準備三樣東西:

  1. JBoss 主程式
  2. Dockerfile
  3. Docker Repository

JBoss 主程式

可至官方網站註冊開發者帳號下載取得 7.1.0 版的 zip 檔。

Dockerfile

Dockerfile 就像是 image 的設計圖,裡面定義了 image 該如何被建置,通常包含了:

  • 基底映像檔資訊
  • 維護者資訊
  • 映像檔操作指令
  • 容器啟動時執行指令

新增一個檔案名稱為 Dockerfile,內容如下:(相關語法參考

# Use latest jboss/base-jdk:8 image as the base
FROM jboss/base-jdk:8

# Sets the Author field of the generated images
LABEL maintainer="cody.tseng@tpinformation.com.tw"

# Set the JBOSS_VERSION env variable
ENV JBOSS_VERSION 7.1.0
ENV JBOSS_HOME /opt/jboss/jboss-eap-$JBOSS_VERSION

# Checkout user to root
USER root

# Copy jboss zip file from local to container 
COPY jboss-eap-$JBOSS_VERSION.zip /opt/jboss

# Add the JBoss distribution to /opt, and make jboss the owner of the extracted tar content
# Make sure the distribution is available from a well-known place
RUN cd /opt/jboss \
    && unzip jboss-eap-$JBOSS_VERSION.zip \
    && rm jboss-eap-$JBOSS_VERSION.zip \
    && chown -R jboss:0 ${JBOSS_HOME} \
    && chmod -R g+rw ${JBOSS_HOME}

# Ensure signals are forwarded to the JVM process correctly for graceful shutdown
ENV LAUNCH_JBOSS_IN_BACKGROUND true

# Checkout user to jboss
USER jboss

# Add a user in administration realm
RUN ${JBOSS_HOME}/bin/add-user.sh admin Admin#007 --silent

# Expose the ports we're interested in
EXPOSE 8080 9990

# Set the default command to run on boot
# This will boot JBoss EAP in the standalone mode and bind to all interface
CMD ${JBOSS_HOME}/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0

Docker Repository

在 Docker Hub 上新增管理 JBoss image 的 repository:

  1. 登入 Docker Hub,然後點選「Create Repository

  1. 輸入 image 名稱「jboss」,然後點選「Create

  1. 完成後即可看到頁面如下:

Build image

將寫好的 Dockerfile、JBoss 的 zip 檔放在同目錄下,然後在目錄下輸入指令「docker build -t $NAME:$TAG $DIR_PATH」建立 image,最後輸入「docker push $NAME:$TAG」將建好的 image 推送到我們建好的 Repository

$ ls

Dockerfile		jboss-eap-7.1.0.zip

# 根據當前目錄下的 Dockerfile 建立 image
$ docker build -t cody81314/jboss:7.1.0 .

# 將 image 推送至 repository
$ docker push cody81314/jboss:7.1.0

完成後至 Repository 的「Tags」頁籤,即可看到剛剛建立好的 image 已經推送上去了。

Step 4:編輯 docker-compose.yml 檔

Docker Compose 是一個可以定義如何啟動多個容器的工具。
可以藉由定義一個 YAML 檔來配置應用程式服務。
定義完成後即可使用一行指令來創建、啟動這些服務。

主要包含三個部分:

  • services
  • networks
  • volumes

以下就新增一個名為「docker-compose.yml」的 YAML 檔(預設路徑為 ./docker-compose.yml)來配置我們的 CI、CD 架構:

version: "3.3"

services:
  jenkins:
    image: jenkins/jenkins:lts
    container_name: 'DevOps_jenkins'
    ports:
      - "18080:8080"
      - "50000:50000"
    networks:
      - jenkinsnet
    volumes:
      - ./jenkins_home:/var/jenkins_home

  sonarqube:
    image: sonarqube:lts
    container_name: 'DevOps_sonarqube'
    ports:
      - "9000:9000"
    networks:
      - sonarnet
      - jenkinsnet
    environment:
      - SONARQUBE_JDBC_URL=jdbc:postgresql://db:5432/sonar
    volumes:
      - sonarqube_conf:/opt/sonarqube/conf
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_bundled-plugins:/opt/sonarqube/lib/bundled-plugins

  db:
    image: postgres
    container_name: 'DevOps_postgres'
    networks:
      - sonarnet
    environment:
      - POSTGRES_USER=sonar
      - POSTGRES_PASSWORD=sonar
    volumes:
      - postgresql:/var/lib/postgresql
      # This needs explicit mapping due to https://github.com/docker-library/postgres/blob/4e48e3228a30763913ece952c611e5e9b95c8759/Dockerfile.template#L52
      - postgresql_data:/var/lib/postgresql/data

  jboss:
    image: cody81314/jboss:7.1.0
    container_name: 'DevOps_jboss'
    ports:
      - "28080:8080"
      - "9990:9990"
    networks:
      - jenkinsnet

networks:
  sonarnet:
    driver: bridge
  jenkinsnet:
    driver: bridge

volumes:
  sonarqube_conf:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_bundled-plugins:
  postgresql:
  postgresql_data:

NOTE: 副檔名使用 .yml 或 .yaml 都可以

version

定義 compose 檔的格式版本,詳細「格式版本」與「Docker Engine 版本」的對應如下:

Compose file format Docker Engine release
3.7 18.06.0+
3.6 18.02.0+
3.5 17.12.0+
3.4 17.09.0+
3.3 17.06.0+
3.2 17.04.0+
3.1 1.13.1+
3.0 1.13.0+

1. services

定義各個「服務」的配置區塊,在上面範例中我們定義了四個服務分別為:

  1. jenkins
  2. sonarqube
  3. db
  4. jboss
1-1. image

指定建立 Container 的來源映像檔、Tag(版本)

1-2. container_name

指定自定義的容器名稱,而不是系統自動生成的預設名稱

1-3. ports

設定對外的端口與容器端口的對應,以格式HOST:CONTAINER做設定:

  • HOST:公開釋出的端口
  • CONTAINER:容器內的端口
1-4. networks

指定要加入的網路,此處指定的網路需被定義在與services同層的networks區塊

1-5. environment

針對各個服務指定環境變數

1-6. volumes

可指定一個「本機位置」或「參考名稱」對單一服務掛載 volumes,但若是要多個服務共用同一個 volumes,則需要在最上層的 volumes 宣告名稱。

範例中,jenkins 服務有指定「本機位置」來掛載容器內的「/var/jenkins_home」,來保存配置設定,確保之後無論將服務搬移至哪台主機都能將原有的 jenkins 配置資料再掛載上去。

2. networks

最上層 networks 的可指定要創建的網路,在上面範例中我們定義了兩個網路分別為:

  1. sonarnet
  2. jenkinsnet
2-1. driver

指定應該為此網絡使用哪個驅動程序,若在單一主機上通常使用 bridge

3. volumes

最上層的 volumes,定義可跨多個服務使用的 volumes 名稱

一鍵部署

Step 1:建立 Workspace

在一個空目錄下(此處為 Docker)準備以下內容:

  1. 編輯完成的 docker-compose.yml
  2. 目錄 jenkins_home(Jenkins 配置的內容都會同步到此資料夾中)

因此若是想要在一台新主機上部署,但又不想重新設定 Jenkins,只需要將舊主機上的 jenkins_home 目錄複製到新主機並且掛載上去即可。

反之若要重新設定,則新增一個空的 jenkins_home 目錄即可。

Step 2:執行 docker-compose up

在 Workspace 目錄下執行:

$ docker-compose up

就會開始依照 docker-compose.yml 裡的配置的內容進行配置

Step 3:完成部署

  1. Jenkins

  1. SonarQube

  1. JBoss

 

曾克維