云计算课程实验
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

18 KiB

基于 ucloud 镜像仓库实现 GitHub 的 CI/CD

GitHub Actions是GitHub的一个持续集成和持续交付(CI/CD)的平台,可以自动化构建、测试和部署Pipelines。

Workflow(工作流)

Workflow其实就是一个可配置的自动化过程,会运行一个或多个Job。Workflow定义在仓库的 .github/workflows文件夹的一个YML或者YAML文件中,并在仓库的Event触发时运行,也可以配置成手动触发运行,或者定时触发。一个Workflow中甚至可以引用另一个Workflow。

可以简单理解,一个YML配置文件就是一个Workflow,仓库可以在.github/workflows文件夹下拥有多个YML文件,即拥有多Workflows。每个Workflow可以执行一组不同的步骤。例如,一个仓库中有两个Workflows,就可以有一个Workflow用来构建和测试PR(Pull Request),另一个Workflow用来每次发布Release版本时自动部署应用。

Event(事件)

Event是仓库中的一个用来触发Workflow运行的特殊活动,有不同类型,如某人创建了一个PR、新建了一个Issue等,这些都是可以用来触发Workflow运行的Event。

Job(工作)

Job是Workflow中的一组步骤,在同一个Runner(运行者)上运行。每个步骤要么是将执行的Shell脚本,要么是将运行的Action。各步骤是按顺序执行的,并且相互依赖。由于各步骤是在同一个Runner上运行,因此可以将数据从一个步骤共享到另一个步骤。可以配置Job与其他Job的依赖关系;默认情况下,Job之间没有依赖关系,并且彼此并行运行。当一个Job依赖于另一个Job时,它将等待从属Job完成,然后才能运行。

Action

Action是GitHub Actions平台的自定义应用程序,用于执行复杂但经常重复的任务。Action可以减少在Workflow的YML文件中编写的重复代码。Action可以从GitHub上拉取仓库代码,为构建环境设置正确的工具链。我们可以编写自己的Action,也可以在GitHub Marketplace中寻找适合使用的Action。

Runner(运行者)

Runner是在Workflow被触发时运行它们的服务器。每个Runner一次可以运行一个Job。GitHub提供了Ubuntu Linux、Windows和macOS Runner来运行Workflow。每个Workflow都在全新的预先配置好的虚拟机中执行。如果我们需要不同的操作系统或者特定的硬件配置,可以用自己托管的Runner来代替GitHub提供的Runner。

实验目的和实验环境

【实验目的】

(1)了解 GitHub Actions。

(2)初步了解 Workflow 语法并自行构建。

(3)实现 Spring Cloud 项目全自动化打包部署。

(4)熟悉整个 CI/CD 的原理。

【实验环境】

(1)CentOS:7.9 及以上

(2)Docker:20.10.7 版。

(3)docker-compose:1.29.2 版,build 5becea4c。

(4)maven 3.9.5

(5)java openjdk-1.8.0

(6)本次实验建议使用 vscode 连接云主机,这样就可以直接在云主机上编辑,而不用总是上传文件。(这个可以自行上网学习,很方便,参考文档 https://blog.csdn.net/m0_49448331/article/details/126030161

实验步骤

1.复制项目代码

https://github.com/OpenEduTech/DaseDevOps/tree/master 复制到自己的账户下后,会生成DaseDevops仓库。注意:下面所有图中显示的devops_demo仓库其实对应的是DaseDevops仓库下的dasedevops_spring_demo项目。

image-20231111152635356

随后,在自己的云主机任意目录下(我这里是 /root )执行 git clone 克隆仓库。使用 ssh 克隆。在克隆之前,可能会报没有 git 命令的错误,需要你手动安装一下 yum install -y git

请重点检查:是 fork 后的仓库,而不是 OpenEduTech 的仓库!!!不然会无法 push

image-20231112145610434

在云主机上,生成本机密钥,用于免密认证。引号内的部分需要更换成你自己 github 绑定的邮箱。

cd .ssh
ssh-keygen -t rsa -C "102155014xx@stu.ecnu.edu.cn"

一路回车,待成功生成密钥后,执行命令 cat id_rsa.pub 将打印出的公钥复制到 github 中。

在 github 上配置云主机的 ssh key,点击头像,

image-20231112145800806

密钥 Title 设置为 action,内容复制进去,这样就可以直接在云主机上免密 git push 了。

2.建立服务器A环境

这里使用的是GitHub托管的Runner,因此服务器A的环境其实已经由GitHub处理好了,不需要我们做任何操作。如果使用自托管的Runner,感兴趣的同学可以参考相关网页。

3.建立服务器B环境

首先,创建一个 centOS 云主机,1 核 2G 配置,20M 带宽流量计费,数据盘设置为 50 G

安装Docker,安装docker-compose。

docker-compose 安装过程:

通过 curl 下载 docker compose

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

添加可执行权限

sudo chmod +x /usr/local/bin/docker-compose

将文件 copy 到 /usr/bin/ 目录下

sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

查看版本

docker-compose --version

显示以下信息说明安装成功。

image-20231110221616117

安装 jdk

请注意,本次实验仅支持手动安装,不支持使用 yum 安装!!

浏览器访问 oracle 官网 https://www.oracle.com/java/technologies/downloads/#license-lightbox 下拉到 Java SE8,下载 x64 版本的压缩包

image-20231112152329365

在云主机的 /usr 目录下创建 java/ 文件夹

cd /usr
mkdir java
cd java

把下载好的文件上传到 /usr/java 下

因为文件有 100M 大小,建议等待一段时间,等上传完成以后进行后续操作。

解压

tar -zxvf jdk-8u391-linux-x64.tar.gz

解压以后,配置环境变量

vi /etc/profile

在文件末尾添加

export JAVA_HOME=/usr/java/jdk-1.8.0_391
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib

更新环境变量

source /etc/profile

输入 java -version 应该可以看到安装成功的消息。

image-20231112155129640

安装 maven

浏览器访问 maven 的下载页面 https://maven.apache.org/download.cgi

点击链接下载

image-20231112145016939

之后上传到 ucloud 云主机的 /usr/local 目录下,进入 /usr/local 目录,解压

tar -xvf apache-maven-3.9.5-bin.tar.gz

执行 vim /etc/profile 配置环境变量

MAVEN_HOME=/usr/local/apache-maven-3.9.5
export PATH=${MAVEN_HOME}/bin:${PATH}

重载环境变量

source /etc/profile

查看是否安装成功,输入 mvn -v 命令,显示相关信息

image-20231112151248101

由于 maven 官方源在国内速度比较慢,我们需要配置阿里 maven 源。cd 到 maven 的安装目录下

修改 conf 文件夹下的 settings.xml

sudo vi conf/settings.xml

修改 mirrors 下没有被注释的那一部分

image-20231112165227354

我这边是已经修改过的,同学们需要根据以下代码修改原有的代码

    <mirror>
      <id>alimaven</id>
      <mirrorOf>central</mirrorOf>  
      <name>aliyun maven</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public/</url>      
    </mirror>

需要把原有的 <block>true</block> 去掉

4.建立 ucloud 阿里云容器镜像服务

本来是想通过 ucloud 使用容器镜像服务的,但是奈何 ucloud 镜像仓库无法通过 github action 的 workflow 进行登录并且操作。无奈之下只能使用阿里云的 aliyun/acr-login 进行 yml 文件登录到 docker 的操作。

为什么不能通过 ucloud 创建容器镜像服务然后再通过登录阿里云镜像仓库然后把镜像推送到 ucloud 中呢?不行。就像 github 中无法直接把自己的代码推送到别人的仓库中一样。

所以为了完成本次实验,需要麻烦大家再在阿里云上创建一个容器镜像服务。

首先,访问 https://www.aliyun.com/ 点击右上角的 “注册/登录” 按钮,完成注册与登录操作

image-20231111104809589

可以直接使用支付宝扫码登录

登录成功后,访问实例列表 https://cr.console.aliyun.com/cn-shanghai/instances 点击创建个人实例。

需要通过 RAM 授权,按照流程点击确认即可。

image-20231111105335421

image-20231111105406205

创建完个人版实例以后,需要设置 registry 登录密码。

然后点击 命名空间 -> 创建命名空间 -> 给自己的命名空间起一个名字吧

推荐使用自己的姓名拼音之间加 "-" 号进行命名。如果出现重名,就再加一些符号。

image-20231111105841358

image-20231112155904281

需要把 默认仓库类型 设置为公开。

作业 1: 创建完成以后,进入个人实例-命名空间页面,截图插入实验报告。

5.接下来,编写本项目的 workflow 文件。在项目根目录下新建 .github/workflows 文件夹将以下代码保存在 docker-publish.yml

name: SpringCloud CI/CD with Docker
on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

env:
  MODULE_1: gateway
  MODULE_2: hello
  MODULE_3: login
  MODULE_4: provider_one
  MODULE_5: provider_two
  MODULE_6: provider_three

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK 8
        uses: actions/setup-java@v2
        with:
          distribution: 'temurin'
          java-version: '8'
          cache: 'maven'
      - name: Build with Maven
        run: |
          whoami
          pwd
          mvn -B package --file pom.xml
          pwd
      - name: Login to Aliyun Container Registry (ACR)
        uses: aliyun/acr-login@v1
        with:
          login-server: https://registry.cn-shanghai.aliyuncs.com
          region-id: cn-shanghai  # 3
          username: "${{ secrets.ACR_USERNAME }}"
          password: "${{ secrets.ACR_PASSWORD }}"
      - name: Build and push image
        run: |
          docker build -t ${{ secrets.ALI_NAMESPACE_URL }}/$MODULE_1:latest ./dasedevops_spring_demo/$MODULE_1
          docker push ${{ secrets.ALI_NAMESPACE_URL }}/$MODULE_1:latest
          docker build -t ${{ secrets.ALI_NAMESPACE_URL }}/$MODULE_2:latest ./dasedevops_spring_demo/$MODULE_2
          docker push ${{ secrets.ALI_NAMESPACE_URL }}/$MODULE_2:latest
          docker build -t ${{ secrets.ALI_NAMESPACE_URL }}/$MODULE_3:latest ./dasedevops_spring_demo/$MODULE_3
          docker push ${{ secrets.ALI_NAMESPACE_URL }}/$MODULE_3:latest
          docker build -t ${{ secrets.ALI_NAMESPACE_URL }}/$MODULE_4:latest ./dasedevops_spring_demo/$MODULE_4
          docker push ${{ secrets.ALI_NAMESPACE_URL }}/$MODULE_4:latest
          docker build -t ${{ secrets.ALI_NAMESPACE_URL }}/$MODULE_5:latest ./dasedevops_spring_demo/$MODULE_5
          docker push ${{ secrets.ALI_NAMESPACE_URL }}/$MODULE_5:latest
          docker build -t ${{ secrets.ALI_NAMESPACE_URL }}/$MODULE_6:latest ./dasedevops_spring_demo/$MODULE_6
          docker push ${{ secrets.ALI_NAMESPACE_URL }}/$MODULE_6:latest
 
      - name: Copy single file to remote
        uses: garygrossgarten/github-action-scp@release
        with:
          local: ./docker-compose.yml
          remote: scp/devops_demo/docker-compose.yml
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USER_NAME }}
          password: ${{ secrets.USER_PASSWORD }}
          port: ${{ secrets.PORT }}
 
  depoly:
    needs: [ build ]
    name: Docker Pull And Docker-compose Run
    runs-on: ubuntu-latest
    steps:
      - name: executing remote ssh commands using password
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USER_NAME }}
          password: ${{ secrets.USER_PASSWORD }}
          port: ${{ secrets.PORT }}
          script: |
            docker-compose -f scp/devops_demo/docker-compose.yml up -d
            docker-compose -f scp/devops_demo/docker-compose.yml stop
            docker-compose -f scp/devops_demo/docker-compose.yml pull
            docker-compose -f scp/devops_demo/docker-compose.yml up -d
            docker image prune -f

相关 secrets 解释:

为什么需要用到 github secrets? 我们都知道,很多情况下,项目有一些隐秘信息,不能直接配置在项目内,包括但不仅限于: github token, 各种账号的用户名密码,私钥信息,各种网站的 api key, app key, secret key 等等。这时候就需要用到 secrets。所以根据 secrets 的特性,一经设置就不可查看!所以设置 secrets 时务必仔细确认!

secrets.ALI_NAMESPACE_URL: 对应阿里云容器镜像服务的 “所在地域 + 命名空间” ,我这里是 “registry.cn-shanghai.aliyuncs.com/easonlin-devops-practice” ,前面的 registry.cn-shanghai.aliyuncs.com 是地域,后面的 easonlin-devops-practice 是命名空间。地域和命名空间很重要,在我们登录阿里云 registry 和拉取、推送镜像时都会用到。

image-20231111163606733

secrets.ACR_USERNAME:阿里云容器服务registry的用户名。

secrets.ACR_PASSWORD:阿里云容器服务registry的用户密码。

secrets.HOST:服务器B的IP地址,就是 ucloud 云主机的公有 ip

secrets.USER_NAME:服务器B的登录用户名,默认为 root

secrets.USER_PASSWORD:服务器B的登录密码。

secrets.PORT:服务器B的SSH开放端口,默认是22。

这些 secrets都可以在代码仓库的“Setting →Secrets → Actions”界面进行设置,使用自己账号的阿里云容器镜像服务中的参数。

image-20231111161358868

新建 secret:点击 New repository secret 按钮

image-20231111161513709

输入 secret name 与 value 即可

image-20231111161537636

随后,进入微服务文件夹 dasedevops_spring_demo 下,进入以下六个文件夹的 Dockerfile 进行编辑。

files.png

注意到了吗,这六个文件夹就和 workflow 中的六个 MODULE 命名相同。

env:
  MODULE_1: gateway
  MODULE_2: hello
  MODULE_3: login
  MODULE_4: provider_one
  MODULE_5: provider_two
  MODULE_6: provider_three

编辑 DockerFile 也是为了分别将这六个 module 打包成镜像,上传到镜像仓库中。这么看,这个 yml 文件是不是也不那么复杂?🐶

gateway微服务的Dockerfile文件内容如下:

FROM java:8
MAINTAINER ningzhicheng
VOLUME /tmp
ADD ./target/*.jar /gateway.jar
ENTRYPOINT ["java","-jar","/gateway.jar"]
EXPOSE 8080

hello微服务的Dockerfile文件内容如下:

FROM java:8
MAINTAINER ningzhicheng
VOLUME /tmp
ADD ./target/*.jar /hello.jar
ENTRYPOINT ["java","-jar","/hello.jar"]
EXPOSE 8001

login微服务的Dockerfile文件内容如下:

FROM java:8
MAINTAINER ningzhicheng
VOLUME /tmp
ADD ./target/*.jar /login.jar
ENTRYPOINT ["java","-jar","/login.jar"]
EXPOSE 8000

provider_one微服务的Dockerfile文件内容如下:

FROM java:8
MAINTAINER ningzhicheng
VOLUME /tmp
ADD ./target/*.jar /provider_one.jar
ENTRYPOINT ["java","-jar","/provider_one.jar"]
EXPOSE 8666

provider_two微服务的Dockerfile文件内容如下:

FROM java:8
MAINTAINER ningzhicheng
VOLUME /tmp
ADD ./target/*.jar /provider_two.jar
ENTRYPOINT ["java","-jar","/provider_two.jar"]
EXPOSE 8667

provider_three微服务的Dockerfile文件内容如下:

FROM java:8
MAINTAINER ningzhicheng
VOLUME /tmp
ADD ./target/*.jar /provider_three.jar
ENTRYPOINT ["java","-jar","/provider_three.jar"]
EXPOSE 8668

6.编写 docker-compose.yml 文件

在 dasedevops_spring_demo 下新建一个 docker-compose.yml 文件,将以下内容复制到文件中

version: "3"

services:
  providerOne:
    image: ${{ secrets.ALI_NAMESPACE_URL }}/provider_one:latest
    ports:
      - "8666:8666"

  gateway:
    image: ${{ secrets.ALI_NAMESPACE_URL }}/gateway:latest
    ports:
      - "8080:8080"

  login:
    image: ${{ secrets.ALI_NAMESPACE_URL }}/login:latest
    ports:
      - "8000:8000"

  hello:
    image: ${{ secrets.ALI_NAMESPACE_URL }}/hello:latest
    ports:
      - "8001:8001"

  providerTwo:
    image: ${{ secrets.ALI_NAMESPACE_URL }}/provider_two:latest
    ports:
      - "8667:8667"

  providerThree:
    image: ${{ secrets.ALI_NAMESPACE_URL }}/provider_three:latest
    ports:
      - "8668:8668"

随后将所有文件提交到暂存区,创建提交信息,推送提交。

git add .
git commit -m "test"
git push

查看自己仓库的 Actions 界面

image-20231112165619307

作业 2: 将成功的截图(示例如下)插入到实验报告中。

image-20231112165720555

作业 3:将阿里云容器镜像服务-个人实例-镜像仓库页面截图,插入实验报告。

示例如下图,必须包括这六个仓库。

image-20231112170627251

本次实验已结束,请同学们立即释放所有 ucloud 云主机资源!