前言

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"]

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,对于每种环境,我们将使用不同的标签,这意味着我们将使用dev,qa 和prod 标签。

我们的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文件

acos介绍\54.png)services:- docker:19.03.7-dind
stages:- build jar- build and push docker image- deploy
build:image: maven:3.6.3-jdk-11-slimstage: build jarbefore_script:- source .${CI_COMMIT_REF_NAME}.envscript:- mvn clean install -Dspring.profiles.active=$SPRING_ACTIVE_PROFILE && mvn package -B -e -Dspring.profiles.active=$SPRING_ACTIVE_PROFILEartifacts:paths:- target/*.jar
docker build:image: docker:stablestage: build and push docker imagebefore_script:- source .${CI_COMMIT_REF_NAME}.envscript:- 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:lateststage: deploybefore_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}.envscript:- 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-slimstage: build jarbefore_script:- source .${CI_COMMIT_REF_NAME}.envscript:- mvn clean install -Dspring.profiles.active=$SPRING_ACTIVE_PROFILE && mvn package -B -e -Dspring.profiles.active=$SPRING_ACTIVE_PROFILEartifacts:paths:- target/*.jar

这是执行第一步骤代码的一部分,构建了一个jar文件,该文件可以下载。这实际上是一个可选步骤,仅用于演示构建jar并从GitLab下载它是多么容易。

第二步骤是在Docker存储库中构建并推送Docker镜像。

docker build:image: docker:stablestage: build and push docker imagebefore_script:- source .${CI_COMMIT_REF_NAME}.envscript:- 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:lateststage: deploybefore_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}.envscript:- 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

还在用Jenkins?试试Gitlab的CI/CD功能吧,贼带劲!相关推荐

  1. GitLab通过CI/CD 实现流水线部署(演示主要是通过shell上传SpringBoot项目)

    GitLab通过CI/CD 实现实现流水线部署(演示主要是通过shell上传SpringBoot项目) 环境准备 1.JDK: 2.maven: 3.Git 4.Docker (本次安装没有使用到,仅 ...

  2. CentOS8.1部署Gitlab+Jenkins持续集成(CI/CD)环境之Jenkins安装(二)

    大家好,我是SuieKa,本博文以学习笔记为主,此时此刻我已按捺不住自己的心情将学习搬运到博客上 上手之前,习惯性的多逼逼知识点,尽管各路大神都已经了如指掌了哈哈哈 目录 什么是Jenkins? 安装 ...

  3. git(gitlab)子模块功能在团队协同开发和生产环境中的应用(git,gitlab,TortoiseGit,CI/CD,Jenkins,docker-compose,分支合并,开发环境,测试环境)

    git(gitlab)子模块功能在团队协同开发和生产环境中的应用 目录 git(gitlab)子模块功能在团队协同开发和生产环境中的应用 一.前言 二.先决条件 三.创建gitlab项目(项目管理员操 ...

  4. GItLab入门级CI/CD环境搭建(适用于小微企业或个人)

    相关 什么是CI/CD CI - Continuous Integrarion - 持续集成 现代应用开发的目的是能够让多个开发人员在同时进行同一应用的不同功能.但是这样需要企业在某一天将不同开发人员 ...

  5. Gitlab的CI/CD初尝试

    初衷:今天公司的前端和测试人员吵起来了.原因是测试埋怨前端人员把Bug的状态更改为已解决,结果代码根本没提交,而前端人员埋怨测试测的太频繁了,需要打几个环境的包不方便.又要改东西又要频繁打包费时间.凡 ...

  6. Jenkins 2.X free-style CI/CD流水线搭建(一)

    前面介绍了Jenkins的安装和插件管理,这篇文章我们介绍下Jenkins free-style CI流水线的搭建.虽然现在不推荐使用这种方式搭建流水线.但是它可以帮助初学者快速了解和体验Jenkin ...

  7. 【GitLab】693- 用 GitLab 做 CI/CD 是什么感觉,太强了!!

    作者:废物大师兄 来源:www.cnblogs.com/cjsblog/p/12256843.html GitLab CI/CD 是一个内置在GitLab中的工具,用于通过持续方法进行软件开发: Co ...

  8. (三)设置Jenkins为MLOps构建CI/CD管道

    目录 Jenkins简介 安装Jenkins插件 配置电子邮件通知 在Jenkins中设置GCP凭据 下一步 在这里,我们配置Jenkins以帮助我们将Docker容器链接到一个实际的管道中,容器将在 ...

  9. 极狐GitLab的CI/CD中 声明和使用变量的三种方式

    更加有关变量的解析可以阅读该文章 极狐GitLab CI/CD关键词(五):变量 variables 使用预设变量 获取当前任务的变量 test_variable:stage: testscript: ...

最新文章

  1. [推荐推荐][提供下载]ORACLE SQL:经典查询练手系列文章收尾(目录篇)
  2. Python时间戳转时间
  3. 前端工程基础知识点--Browserslist (基于官方文档翻译)
  4. 实验4.1 循环控制 一
  5. 图解.Net Telerik 控件教程
  6. Java方法重载与方法重写
  7. 【面试招聘】有哪些好的秋招经验分享?数据、算法岗的几点经验分享
  8. instance在ceph对应pool的位置查询
  9. 天津海运[600751]股票
  10. daz模型导入marvelous_传世工坊自制Daz Studio 4.10 系列入门教程
  11. CCF推荐的计算机顶级期刊和论文参考
  12. 基于SSM的志愿者管理系统
  13. c++11 日期和时间工具(std::chrono::duration)(二)
  14. Eclipse4.6(neno)配置Tomcat插件
  15. 探索 TDengine在《图码联侦》项目中的应用可行性及实践研究(new)
  16. .xin是什么域名?
  17. SRI-Subresource Integrity
  18. Unity官方实例教程 Roll-a-Ball(二)
  19. 软件加密系统Themida应用程序保护指南(十):高级选项
  20. 机器学习 (二) K近邻算法分析与实现

热门文章

  1. c#sort升序还是降序_C#中对数组或集合进行升序或降序排序
  2. python 守护线程 join_Python多线程threading join和守护线程setDeamon原理详解
  3. 获取数组第N个元素的方法
  4. 三种云存储加密的方法
  5. poj3508(高精度模拟减法)
  6. 07-图6 旅游规划 (25分)(以此感谢zyx佬)
  7. python 因果推断_KDD 2018:微软推出用于因果推断的Python库
  8. 解题报告(二)多项式问题(多项式乘法及其各种运算)(ACM/ OI)超高质量题解
  9. 解题报告:luoguP6685 可持久化动态仙人掌的直径问题
  10. 【每日DP】day 10、P1005 矩阵取数游戏【区间DP+高精(python)】难度⭐⭐⭐★