乐趣区

关于gitlab:使用-GitLab-CI-和-Docker-自动部署-Spring-Boot-应用

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 分钟的收费构建工夫,对于某些我的项目来说,这是入不敷出的

我把 Docker 的教程和文章整顿成了 PDF,关注微信关注号 Java 后端,回复 666 就能下载了。

为什么 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 *ntStrictHostKeyChecking nonn" > ~/.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 *ntStrictHostKeyChecking nonn" > ~/.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 *ntStrictHostKeyChecking nonn" > ~/.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/au…

翻译:https://blog.csdn.net/weixin_…

退出移动版