使用GitLab CI和Docker自動部署SpringBoot應用

原文發表於kubernetes中文社區,爲作者原創翻譯 ,原文地址

更多kubernetes文章,請多關注kubernetes中文社區

Docker和Spring Boot是非常流行的組合,我們將利用GitLab CI的優勢,並在應用程序服務器上自動構建,推送和運行Docker鏡像。

GitLab CI

Gitlab CI/CD服務是GitLab的一部分,每當開發人員將代碼推送到GitLab存儲庫時,它都會在所需的環境中構建,測試和存儲最新的更改。

選擇GitLab CI的一些主要原因:

  1. 易於學習,使用和可擴展

  2. 維護容易

  3. 整合容易

  4. CI完全屬於GitLab存儲庫的一部分

  5. 良好的Docker集成

  6. 鏡像託管(Container registry)-基本上是你自己的私有Docker Hub

  7. 從成本上來說,GitLab CI是一個很好的解決方案。每個月你有2000分鐘的免費構建時間,對於某些項目來說,這是綽綽有餘的

爲什麼GitLab CI超越Jenkins

這無疑是一個廣泛討論的話題,但是在本文中,我們將不深入探討該話題。GitLab CI和Jenkins都有優點和缺點,它們都是功能非常強大的工具。

那爲什麼選擇GitLab?

如前所述,CI完全是GitLab存儲庫的一部分,這意味着不需要安裝它,並且維護最少。yml腳本完成後,你便或多或少地完成了所有工作。

對於小型項目使用Jenkins,你就必須自己設置和配置所有內容。通常,你還需要一臺專用的Jenkins服務器,這也需要額外的成本和維護。

使用GitLab CI 前提條件

如果需要與這些前提條件有關的任何幫助,我已提供相應指南的鏈接。

  1. 你已經在GitLab上推送了Spring Boot項目

  2. 你已在應用程序服務器上安裝了Docker(指南

  3. 你具有Docker鏡像的鏡像託管(在本指南中將使用Docker Hub

  4. 你已經在服務器上生成了SSH RSA密鑰(指南

你要創建什麼

你將創建Dockerfile.gitlab-ci.yml, 它們將自動用於:

  1. 構建應用程序Jar文件

  2. 構建Docker鏡像

  3. 將鏡像推送到Docker存儲庫

  4. 在應用程序服務器上運行鏡像

基本項目信息

本文的Spring Boot應用程序是通過Spring Initializr生成的。這是一個基於Java 8或Java11構建的Maven項目。後面,我們將介紹Java 8和Java 11對Docker鏡像有什麼影響。

Docker文件

讓我們從Dockerfile開始。

FROM maven:3.6.3-jdk-11-slim AS MAVEN_BUILD
#FROM maven:3.5.2-jdk-8-alpine AS MAVEN_BUILD FOR JAVA 8
ARG SPRING_ACTIVE_PROFILE
MAINTAINER Jasmin
COPY pom.xml /build/
COPY src /build/src/
WORKDIR /build/
​
RUN mvn clean install -Dspring.profiles.active=$SPRING_ACTIVE_PROFILE && mvn package -B -e -Dspring.profiles.active=$SPRING_ACTIVE_PROFILE
FROM openjdk:11-slim
#FROM openjdk:8-alpine FOR JAVA 8
WORKDIR /app
COPY --from=MAVEN_BUILD /build/target/appdemo-*.jar /app/appdemo.jar
ENTRYPOINT ["java", "-jar", "appdemo.jar"]

與該Dockerfile相關的知識很少。

Java版本

讓我們從Docker的角度看一下Java 8和11之間的區別。長話短說:這是Docker鏡像的大小和部署時間。

基於Java 8構建的Docker鏡像將明顯小於基於Java 11的鏡像。這也意味着Java 8項目的構建和部署時間將更快。

  • Java 8-構建時間:約4分鐘,鏡像大小爲 約180 MB

  • Java 11-構建時間: 約14分鐘,鏡像大小約爲480 MB

注意: 在實際應用中,這些數字可能會有所不同。

Docker鏡像

正如在前面示例中已經看到的那樣,由於Java版本的緣故,我們在應用程序鏡像大小和構建時間方面存在巨大差異。其背後的實際原因是在Dockerfile中使用了Docker鏡像。

如果我們再看一下Dockerfile,那麼Java 11鏡像很大的真正原因是因爲它包含了沒有經過驗證/測試的open-jdk:11鏡像的Alpine版本

如果你不熟悉OpenJDK鏡像版本,建議你閱讀OpenJDK Docker官方文檔。在這裏,你可以找到有關每個OpenJDK版本的鏡像的說明。

備註:動態的變量

ENTRYPOINT 中,與環境相關的屬性,我們只能寫死,如下:

ENTRYPOINT [ “ java”,“ -Dspring.profiles.active = development”,“ -jar”,“ appdemo.jar” ]

爲了使它動態,你希望將其簡單地轉換爲:

ENTRYPOINT [ “ java”,“ -Dspring.profiles.active = $ SPRINT_ACTIVE_PROFILE”,“ -jar”,“ appdemo.jar” ]

以前,這是不可能的,但是幸運的是,這將在.gitlab-ci.yml中通過 ARG SPRING_ACTIVE_PROFILE修復

gitlab-ci.yml

在編寫此文件之前,要準備的東西很少。基本上,我們想要實現的是,只要推送代碼,就會在相應的環境上自動部署。

創建.env文件和分支

我們首先需要創建包含與環境相關的分支和.env文件。每個分支實際上代表我們的應用程序將運行的環境。

我們將在三個不同的環境中部署我們的應用程序:開發,測試和生產( development, QA, and production )。這意味着我們需要創建三個分支。

我們的dev,QA和prod應用程序將在不同的服務器上運行,並且將具有不同的Docker容器標籤,端口和SSH密鑰。這就要求我們的gitlab-ci.yml文件將要是動態的,通過爲我們擁有的每個環境創建.env文件來解決該問題。

.develop.env .qa.env .master.env

重要說明: 命名這些文件時,有一個簡單的規則:使用GitLab分支來命名,因此文件名應如下所示:。$ BRANCH_NAME.env

例如,這是.develop.env文件。

export SPRING_ACTIVE_PROFILE='development'
export DOCKER_REPO='username/demo_app:dev'
export APP_NAME='demo_app_dev'
export PORT='8080'
export SERVER_IP='000.11.222.33'
export SERVER_SSH_KEY="$DEV_SSH_PRIVATE_KEY"

與.env文件有關的重要說明:

SPRING_ACTIVE_PROFILE:不言自明,我們要使用哪些Spring應用程序屬性。 DOCKER_REPO:這是Docker鏡像的存儲庫;在這裏,我們唯一需要注意的是Docker image TAG,對於每種環境,我們將使用不同的標籤,這意味着我們將使用devqaprod 標籤。

我們的Docker中心看起來像這樣。

 

如你所見,存在一個帶有三個不同標籤的存儲庫,每當將代碼推送到GitLab分支上時,每個標籤(應用程序版本)都會被更新。

  • APP_NAME: 此屬性非常重要,它是對容器的命名。 如果你未設置此屬性,則Docker將爲你的容器隨機命名。這可能是一個問題,因爲你將無法以乾淨的方式停止運行容器。

  • 端口:這是我們希望運行Docker容器的端口。

  • SERVER_IP:應用程序使用的服務器IP。通常,每個環境都將位於不同的服務器上。

  • SERVER_SSH_KEY:這是我們已經在每臺服務器上生成的SSH密鑰。 $DEV_SSH_PRIVATE_KEY 實際上是來自GitLab存儲庫的變量。

創建GitLab變量

最後需要做的是創建GitLab變量。

打開你的GitLab存儲庫,然後轉到:Settings -> CI/CD。在 Variables部分中, 添加新變量:

  • DOCKER_USER:用於訪問Docker Hub或其他鏡像託管的用戶名

  • DOCKER_PASSWORD: 用於訪問鏡像託管的密碼

  • $ ENV_SSH_PRIVATE_KEY: 先前在服務器上生成的SSH私鑰。

SSH KEY的重要說明:

  • 你需要複製完整的密鑰值,包括: ----- BEGIN RSA PRIVATE KEY -----和----- END RSA PRIVATE KEY -----

最後,你的GitLab變量應如下所示。

 

創建gitlab-ci.yml文件

最後,讓我們創建將所有內容放在一起的文件。

services:
  - docker:19.03.7-dind
stages:
  - build jar
  - build and push docker image
  - deploy
build:
  image: maven:3.6.3-jdk-11-slim
  stage: build jar
  before_script:
    - source .${CI_COMMIT_REF_NAME}.env
  script:
    - mvn clean install -Dspring.profiles.active=$SPRING_ACTIVE_PROFILE && mvn package -B -e -Dspring.profiles.active=$SPRING_ACTIVE_PROFILE
  artifacts:
    paths:
      - target/*.jar
docker build:
  image: docker:stable
  stage: build and push docker image
  before_script:
    - source .${CI_COMMIT_REF_NAME}.env
  script:
    - docker build --build-arg SPRING_ACTIVE_PROFILE=$SPRING_ACTIVE_PROFILE -t $DOCKER_REPO .
    - docker login -u $DOCKER_USER -p $DOCKER_PASSWORD docker.io
    - docker push $DOCKER_REPO
deploy:
  image: ubuntu:latest
  stage: deploy
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
    - source .${CI_COMMIT_REF_NAME}.env
  script:
    - ssh root@$SERVER "docker login -u $DOCKER_USER -p $DOCKER_PASSWORD docker.io; docker stop $APP_NAME; docker system prune -a -f; docker pull $DOCKER_REPO; docker container run -d --name $APP_NAME -p $PORT:8080 -e SPRING_PROFILES_ACTIVE=$SPRING_ACTIVE_PROFILE $DOCKER_REPO; docker logout"

讓我們解釋一下這裏發生了什麼:

services: 
  - docker:19.03.7-dind

這是一項服務,使我們可以在Docker中使用Docker。在Docker中運行Docker通常不是一個好主意,但是對於此用例來說,這是完全可以的,因爲我們將構建鏡像並將其推送到存儲庫中。

stages:
  - build jar
  - build and push docker image
  - deploy

對於每個gitlab-ci.yml文件,必須首先定義執行步驟。腳本將按照步驟定義的順序執行。

在每個步驟,我們都必須添加以下部分: before_script: - source .${CI_COMMIT_REF_NAME}.env

這只是預先加載之前創建的 env. files, 文件。根據正在運行的分支來自動注入變量。(這就是爲什麼我們必須使用分支名稱來命名.env文件的原因)

這些是我們部署過程中的執行步驟。

 

如你所見,,有三個帶有綠色複選標記的圓圈,這表示所有步驟均已成功執行。

build:
  image: maven:3.6.3-jdk-11-slim
  stage: build jar
  before_script:
    - source .${CI_COMMIT_REF_NAME}.env
  script:
    - mvn clean install -Dspring.profiles.active=$SPRING_ACTIVE_PROFILE && mvn package -B -e -Dspring.profiles.active=$SPRING_ACTIVE_PROFILE
  artifacts:
    paths:
      - target/*.jar

這是執行第一步驟代碼的一部分,構建了一個jar文件,該文件可以下載。這實際上是一個可選步驟,僅用於演示構建jar並從GitLab下載它是多麼容易。

第二步驟是在Docker存儲庫中構建並推送Docker鏡像。

docker build:
  image: docker:stable
  stage: build and push docker image
  before_script:
    - source .${CI_COMMIT_REF_NAME}.env
  script:
    - docker build --build-arg SPRING_ACTIVE_PROFILE=$SPRING_ACTIVE_PROFILE -t $DOCKER_REPO .
    - docker login -u $DOCKER_USER -p $DOCKER_PASSWORD docker.io
    - docker push $DOCKER_REPO

這一步驟,我們不得不使用docker:19.03.7-dind服務。如你所見,我們使用的是最新的穩定版本的Docker,我們只是在爲適當的環境構建鏡像,然後對Dockerhub進行身份驗證並推送鏡像。

我們腳本的最後一部分是:

deploy:
  image: ubuntu:latest
  stage: deploy
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
    - source .${CI_COMMIT_REF_NAME}.env
  script:
    - ssh root@$SERVER "docker stop $APP_NAME; docker system prune -a -f; docker pull $DOCKER_REPO; docker container run -d --name $APP_NAME -p $PORT:8080 -e SPRING_PROFILES_ACTIVE=$SPRING_ACTIVE_PROFILE $DOCKER_REPO"

在此步驟中,我們使用Ubuntu Docker鏡像,因此我們可以SSH到我們的應用程序服務器並運行一些Docker命令。其中的部分代碼 before_script大部分來自官方文檔,但是,當然,我們可以對其進行一些調整以滿足我們的需求。爲不對私鑰進行驗證,添加了以下代碼行:

- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config

你也可以參考指南驗證私鑰。 如你在最後階段的腳本部分中所見,我們正在執行一些Docker命令。

  1. 停止正在運行的Docker容器:docker stop $APP_NAME。(這就是我們要在.env文件中定義APP_NAME的原因 )

  2. 刪除所有未運行的Docker鏡像 docker system prune -a -f。這實際上不是強制性的,但我想刪除服務器上所有未使用的鏡像。

  3. 拉取最新版本的Docker鏡像(該鏡像是在上一個階段中構建並推送的)。

  4. 最後,使用以下命令運行Docker鏡像:

    docker container run -d --name $APP_NAME -p $PORT:8080 -e SPRING_PROFILES_ACTIVE=$SPRING_ACTIVE_PROFILE $DOCKER_REPO

     

譯文鏈接: https://dzone.com/articles/automate-spring-boot-app-deployment-with-gitlab-ci

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章