<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 7918字,需瀏覽 16分鐘

           ·

          2021-01-06 12:07

          譯者:王延飛

          來源:https://dzone.com/articles/automate-spring-boot-app-deployment-with-gitlab-ci


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

          GitLab CI

          Gitlab CI/CD服務是GitLab的一部分。開發(fā)人員將代碼推送到GitLab存儲庫時,GitLab CI就會在用戶指定的環(huán)境中自動構建,測試和存儲最新的代碼更改。

          選擇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都有優(yōu)點和缺點,它們都是功能非常強大的工具。

          那為什么選擇GitLab?

          如前所述,Gitlab CI是GitLab存儲庫的一部分,這就意味著當我們有了GitLab后,就不需要再安裝Gitlab CI,也不需要額外維護。并且只需要編寫一個.gitlab-ci.yml文件(下文會詳細說明),你便完成了所有CI工作。

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

          使用GitLab CI 前提條件

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

          1. 你已經(jīng)在GitLab上推送了Spring Boot項目

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

          3. 你具有Docker鏡像的鏡像托管(本文中將使用Docker Hub)

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

          你要創(chuàng)建什么

          你將創(chuàng)建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"]


          Java版本

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

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

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

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

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

          Docker鏡像

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

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

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

          備注:動態(tài)的變量

          在ENTRYPOINT 中,與環(huán)境相關的屬性,我們只能寫死,如下:

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

          為了使它動態(tài),你希望將其簡單地轉換為:

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


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

          gitlab-ci.yml

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

          創(chuàng)建.env文件和分支

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

          我們將在三個不同的環(huán)境中部署我們的應用程序:開發(fā),測試和生產(chǎn)( development, QA, and production )。這意味著我們需要創(chuàng)建三個分支。我們的dev,QA和prod應用程序將在不同的服務器上運行,并且將具有不同的Docker容器標簽,端口和SSH密鑰。這就要求我們的gitlab-ci.yml文件將要是動態(tài)的。我們可以為每個環(huán)境創(chuàng)建單獨的.env文件來解決該問題。

          .develop.env

          .qa.env

          .master.env

          重要說明:命名這些文件時,有一個簡單的規(guī)則:使用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,對于每種環(huán)境,我們將使用不同的標簽,這意味著我們將使用dev,qa 和prod 標簽。

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

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

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

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

          • SERVER_IP:應用程序使用的服務器IP。通常,每個環(huán)境都將位于不同的服務器上。

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

          創(chuàng)建GitLab變量

          最后需要做的是創(chuàng)建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變量應如下所示。

          創(chuàng)建gitlab-ci.yml文件

          最后,讓我們創(chuàng)建將所有內(nèi)容放在一起的文件。

          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"


          讓我們解釋一下這里發(fā)生了什么:


          services:
          - docker:19.03.7-dind


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


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


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

          在每個步驟,我們都必須添加以下部分:


          before_script:
          ?- source?.${CI_COMMIT_REF_NAME}.env


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

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

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

          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


          這是執(zhí)行第一步驟代碼的一部分,構建了一個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服務。如你所見,我們使用的是最新的穩(wěn)定版本的Docker,我們只是在為適當?shù)沫h(huán)境構建鏡像,然后對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


          你也可以參考指南驗證私鑰。如你在最后階段的腳本部分中所見,我們正在執(zhí)行一些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


          - END -


          ?推薦閱讀?

          記一次 Linux服務器被入侵后的排查思路
          Nginx為什么快到根本停不下來?
          用了3年Kubernetes,我們得到的5個教訓
          Linux 運維必備的 40 個命令總結,收好了~
          大白話理解Session和Cookie是什么?
          系統(tǒng)架構性能優(yōu)化思路
          運維工程師必備技能:網(wǎng)絡排錯思路大講解~



          點亮,服務器三年不宕機

          瀏覽 60
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产白丝在线观看 | 九九九爱免费视频在线观看 | 狠狠操狠狠 | 日皮网站在线观看 | 日韩高清无码三级 |