Skip to content

DevOps自动化部署实战V1.0

一、前期准备工作

  1. 一台云服务器 (配置:1核2G,系统CentOS7.9)
  2. Github.com
  3. 远程连接工具:MobaXterm
  4. 代码编辑器:WebStorm

二、自动化构建流程

2.1、绘制自动化流程图

1676296311135

2.2、构建过程讲解

  1. 在 github 仓库创建一个项目,项目拥有 main、dev 两个分支。项目中创建脚本触发 jenkins 进行远程构建,脚本填写分支参数控制 jenkins 需要构建的分支。
  2. jenkins 构建成功后,Version Number的插件以 分支__时间__今日构建版本 格式作为版本号,同时 docker 构建的镜像格式:任务名称:版本 进行构建。
  3. jenkins 构建镜像成功后,删除历史版本并且运行当前最新镜像。

三、安装docker和docker-compose

3.1、首先使用SSH远程连接服务器

1676551671271

3.2、安装docker

详细使用可以参考 Docker官方网址

先查看是否安装过 docker 可以进行先删除

bash
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

执行结果如下图

1676551752902

安装 yum-utils 和设置 yum 源

bash
sudo yum install -y yum-utils
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

开始安装 docker

bash
sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

启动和开机自启 docker

bash
sudo systemctl start docker

测试是否安装成功

bash
docker --version

运行结果如下

1676552187204

3.3、安装docker-compose

以在 GitHub.com 下载文件手动通过SSH连接工具上传至服务器进行安装

docker-compose下载地址

  1. 进入docker的github的下载地址,自由选择版本,这里以 v2.15.0 版本安装

1676552615423

点击某一个版本选择对应系统下载

1676552695029

  1. 上传至云服务器

上传的服务器路径: /usr/local/bin

1676553225718

  1. 上传完成之后, 更改文件名称、添加执行权限、添加软件连接
bash
# 更改名称
mv docker-compose-linux-x86_64 docker-compose
# 添加执行权限
sudo chmod +x /usr/local/bin/docker-compose
# 添加软连接
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

执行如下图

1676553650137

四、docker安装jenkins

  1. 选择LTS版本的docker安装

1676555639562

选择复制推荐命令

1676555737810

查看 docker 下载的 jenkins 镜像

bash
docker module_img

运行如下图

1676555954087

  1. /home 路径下建立 docker_jenkins 目录,该目录下创建 docker-compose.yml 文件

1676556047542

docker-compose.yml 配置如下

yml
version: '3'
services:
  docker_jenkins:
    image: jenkins/jenkins:lts-jdk11 # 镜像
    restart: always
    container_name: docker_jenkins # 容器名称
    ports:
      - 8080:8080 # jenkins开放的端口,可自行设置,端口映射
      - 50000:50000
    volumes:
      - ./jenkins_home:/var/jenkins_home # 容器卷映射

执行 docker-compose up -d 命令, 运行 jenkins

bash
docker-compose up -d

🔔注意:这里会经常遇到的问题是 jenkins 容器一直在启动中, 可以使用 docker ps 查看容器状态

bash
docker ps # 查看jenkins容器状态

1676556732551

可以使用 docker logs 容器id 查看容器内的日志

bash
docker logs 20271d19be72

执行如下图

1676556894830

具体原因是: 从容器映射当前文件夹下的 jenkins_home 没有执行权限, 解决方案很多

bash
chown -R 1000:1000 jenkins_home

再次执行 docker ps 查看, 发现可以运行

1676557451331

在浏览器输入ip地址查看

1676557717117

以上就是 docker 安装 jenkins 的全部过程,详细可以参考 jenkins官网

五、配置jenkins基础插件安装

5.1、jenkins安装过程配置

  1. 查看管理员密码进行登录, 并且重新设置管理员

1676557990331

  1. 选择插件安装

1676558030613

  1. 插件安装我这边选择了 只先安装中文插件

1676558135294

  1. 选择创建管理员用户, 自行设置

1676558285245

5.2、jenkins基础插件配置

  1. 配置中文插件翻译不完全问题

系统管理 → 插件管理 → Available plugins → 搜索locale安装

安装 Locale,重启 jenkins 即可

  1. 修改jenkins插件安装地址

由于 jenkins 安装插件地址在国外源,下载速度慢,所以切换到国内地址

进入插件管理 → 选择高级设置 → 升级站点

1676638844588

将URL的输入的地址替换 https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/dynamic-stable-2.361.4/update-center.json (清华大学站点),点击提交

1676638946226

进入 /home/docker_jenkins/jenkins_home/updates 目录下,修改 default.json

1676639157816

将 www.google.com 修改为 www.baidu.com, 将updates.jenkins.io/download 替换为mirrors.tuna.tsinghua.edu.cn/jenkins,之后进行 重启

1676639574453

😨踩坑记录:

切换国内源可能会导致部分插件不能正常使用,因为可能清华网的插件更新比较慢甚至跟不上jenkins的更新版本。

当前的jenkins版本:2.375.3,如果是清华地址源,此版本安装NodeJS不起作用,无法选择node的版本。

例如:NodeJS

正常情况如下

1676953164310

  1. jenkins启用代理

jenkins 使用时会经常出现以下错误

1676640391506

解决方案

1676640538305

六、安装jenkins所需插件和凭证配置

6.1、安装Git

由于是 jenkins 是 docker 安装运行的镜像,这里不使用服务器安装 git,使用 Git plugin 默认进行拉取代码

1676691941241

配置 Git plugin 默认用户,应用保存即可

1676719152935

6.2、安装Node

1676719220264

配置自动安装 node

1676953164310

🔔注意:第一次打包是比较慢,因为 jenkins 需要安装 Node,版本就是上诉图片选择的版本,这里选择 Node 版本是16.18.1

6.3、安装Generic Webhook Trigger插件实现远程构建

1676723527068

6.4、安装Version Number构建自定编号

1676723709915

6.5、安装Timestamper 控制输出中显示时间

1676724121056

配置 Timestamper 插件的系统设置

1676724593019

6.6、安装SSH Agent代理(后期使用pipeline进行打Tag)

1676723238213

6.7、安装钉钉插件进行通知

  1. jenkins 安装 DingTalk 插件

1676895117734

  1. 配置钉钉通知信息

创建钉钉群聊,这里不做详细阐述,可以参考以下地址:https://blog.51cto.com/yangxingzhen/5980547

进入系统管理,最下方进入钉钉配置

1676895117734

6.8、安装pipeline插件

安装成功,新建任务就会多出 pipeline 的项目类型

1676900489599

七、添加凭证

由于项目代码保存至 GitHub 上,拉取代码使用 https 的形式经常拉取代码失败(外网),所以这里使用 ssh 形式拉取代码

7.1、生成ssh公钥

生成 ssh 不做阐述,可自行参考其他

7.2、GitHub上创建SSH keys

1676894719536

创建成功

1676894792895

7.3、jenkins上添加凭证

1676895031978

7.4、验证凭证是否有效

  1. 创建一个自由风格项目test

1676898045187

进行项目配置

1676953711230

  1. 构建测试任务

1676900138130

  1. 查看git和node的版本

1676953604251

🔔注意:第一次构建可能会出现 Host key verification failed 原因拉取失败,这里推荐现在第一个 Accept first connection 进行第一次构建,构建成功后还原默认设置

错误输出

1676906911163

解决方案

1676900257812

八、jenkins使用宿主机的docker

在构建自动化项目之前,因为流程图中体现采用思路是 jenkins 构建镜像,属于docker来运行该制作的镜像。这里需要jenkins使用宿主机的 docker(容器卷映射 docker 文件至 jenkins 容器内),不推荐在 jenkins 容器里面在安装 docker

8.1、在映射docker文件之前,需要修改docker文件使用权限

使用 cd /var/run 命令进入到 /var/run 目录下

1676954946900

执行以下命令

bash
chown root:root docker.sock
chmod o+rw docker.sock

权限修改成功如下

1676955083990

8.2、将宿主机的docker文件映射到jenkins容器内

修改 /home/docker_jenkins/docke-compose.yml 文件即可

修改后的文件内容

yml
version: '3'
services:
  docker_jenkins:
    image: jenkins/jenkins:lts-jdk11
    restart: always
    container_name: docker_jenkins
    ports:
      - 8080:8080
      - 50000:50000
    volumes:
      - ./jenkins_home:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock #docker映射文件
      - /usr/bin/docker:/usr/bin/docker #docker映射文件
      - /etc/docker/daemon.json:/etc/docker/daemon.json #docker映射文件

执行 docker-compose up -d 进行重启 jenkins

8.3、再次使用test项目执行shell脚本使用docker命令是否成功

1676955784561

构建test项目,查看打印的日志

1676956281834

或者进入容器,验证 docker 是否有效

bash
docker exec -it 容器id /bin/bash # 进入容器
docker --version # 验证docker命令

执行如下图

1676956462554

九、创建jenkins的pipeline任务

pipeline 使用项目 jenkinsfile 进行构建,可以进行灵活修改。

9.1、新建pipeline任务

1676976220550

9.2、配置blog任务

  1. 添加机器人

1676978452356

  1. 配置触发器

选择 Generic Webhook Trigger 远程构建

1676978501482

配置远程构建参数

1676978668039

1676979024896

配置 token

1676978766857

配置打印配置

1676978788249

1676978997839

配置流水线

1676978788249

十、github项目配置

在项目中创建 docker 文件目录,Linux 的 sh 脚本、dockerfile、jenkinsfile 都放在此目录下

10.1、配置jenkinsfile

bash
pipeline {
    agent any
    environment {
    	  # 构建版本
        BUILD_VERSION = VersionNumber([
            versionNumberString: '${branch}_${BUILD_DATE_FORMATTED, "yyyyMMdd"}_${BUILDS_TODAY}',
        ])
    }

    triggers {
        # 远程构建,接收branch、username参数
        GenericTrigger(
            genericVariables: [
              [key: 'branch', value: '$.branch'],
              [key: 'username', value: '$.username']
            ],
            token: 'blog',
            printContributedVariables: true,
            printPostContent: true
        )
    }

    options {
        timestamps()
    }

    tools {
        git 'Default'
    }

    stages {
        # 拉取代码
        stage('pull code') {
            steps {
                git branch: '${branch}', credentialsId: '066f42b8-5d76-4e72-9e0f-0c167d191bfb', url: 'git@github.com:szchason/blog.git'
            }
        }
        # 安装npm包
        stage('install npm packages') {
            steps {
                nodejs('Node16.18.1') {
                    sh "npm i"
                    sh "npm run build"
                }
            }
        }
        # 运行脚本,构建镜像
        stage("build docker image") {
            steps {
                sh '/bin/bash ./docker/docker.sh'
            }
        }
    }

    post {
        success {
           # 构建成功后,jenkins后台输出版本号
            script {
                currentBuild.displayName = env.BUILD_VERSION
            }
            # 构建成功打tag
            git branch: '${branch}', credentialsId: '066f42b8-5d76-4e72-9e0f-0c167d191bfb', url: 'git@github.com:szchason/blog.git'
            sshagent(['066f42b8-5d76-4e72-9e0f-0c167d191bfb']) {
                sh "git tag -a -f ${env.BUILD_VERSION} -m 'jenkins Git plugin tagging with ${env.BUILD_VERSION}'"
                sh "git push origin ${env.BUILD_VERSION}"
            }
        }
    }
}

🔔注意:credentialsId 需要使用 jenkins 生成的凭证 id

10.2、配置docker.sh脚本

bash
#!/bin/bash

# Use jenkins job name as image name
image_name=$JOB_NAME
version="${BUILD_VERSION}"
echo $version

full_name="${image_name}:${version}"

echo $full_name

echo "---------------------"
echo "copy project files to docker folder"
cp -r ./dist ./docker
cd ./docker

echo "---------------------"
echo "stop container"
containerId=`docker ps -a | grep ${image_name} | awk '{print $1}'`
if [ "$containerId" != "" ] ; then
  docker stop $containerId
  docker rm $containerId
fi

echo "---------------------"
echo "start to build images"
docker build . -t $full_name

echo "---------------------"
echo "Delete images of other versions and run the latest one"
for tag in `docker module_img | grep ${image_name} | awk '{print $2}'`
do
  if [ "${tag}" != "${version}" ] ; then
     docker rmi -f "${image_name}:${tag}"
  fi
done

echo "docker run"
docker run --restart=always -dp 80:80 $full_name
echo "部署成功"

10.3、配置Dockerfile

bash
FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf  # docker目录下的nginx.conf映射到制作的容器中
COPY dist/ /usr/share/nginx/html/

十一、配置远程脚本

在根目录下创建bin目录,bin目录下创建index.mjs

11.1、配置index.mjs

js
import fetch from 'node-fetch';
import { execSync } from 'child_process';

let username = 'Anonymous';
let branch = 'dev';
let jobName = 'blog';
let jenkins_url = '';

try {
  username = execSync('git config --get user.name'); // 获取用户名
  branch = execSync('git rev-parse --abbrev-ref HEAD'); // 获取当前分支
  jenkins_url = execSync('npm config get jenkins_url'); // 从npm获取远程构建的地址
} catch (e) {}

if (!jenkins_url) {
  throw Error('缺少远程构建地址');
}

fetch(`${jenkins_url.toString().trim()}/generic-webhook-trigger/invoke?token=${jobName}`, {
  method: 'post',
  body: JSON.stringify({
    username: username.toString().trim(),
    branch: branch.toString().trim(),
  }),
  headers: { 'Content-Type': 'application/json' },
})
  .then((response) => response.json())
  .then((res) => {
    console.log(res);
  })
  .catch((err) => {
    console.log(err, '<---err');
  });

🔔注意:jobName 必须和 jenkinsfile 的 generic-webhook-trigger 插件配置 token 保持一致

10.2、package.json创建scripts脚本

json
  "scripts": {
    "deploy": "node bin/index.mjs"
  },