一台虚拟机学习CI流程

本次学习虚拟机配置如下

4U8G Rocky-9.6-x86_64-dvd.iso 网络模式 nat

第一阶段:准备工作

1.配置yum仓库,使用阿里云的.,截至目前可用,后续如果更新自行替换。

bash 复制代码
[base]
name=Rocky Linux 9 - BaseOS - AliYun
baseurl=https://mirrors.aliyun.com/rockylinux/9/BaseOS/$basearch/os/
gpgcheck=1
enabled=1
gpgkey=https://mirrors.aliyun.com/rockylinux/RPM-GPG-KEY-Rocky-9


# Rocky Linux 9 - AppStream - AliYun Mirror
[appstream]
name=Rocky Linux 9 - AppStream - AliYun
baseurl=https://mirrors.aliyun.com/rockylinux/9/AppStream/$basearch/os/
gpgcheck=1
enabled=1
gpgkey=https://mirrors.aliyun.com/rockylinux/RPM-GPG-KEY-Rocky-9


# Rocky Linux 9 - Extras - AliYun Mirror
[extras]
name=Rocky Linux 9 - Extras - AliYun
baseurl=https://mirrors.aliyun.com/rockylinux/9/extras/$basearch/os/
gpgcheck=1
enabled=1
gpgkey=https://mirrors.aliyun.com/rockylinux/RPM-GPG-KEY-Rocky-9


[docker]
name=Docker
baseurl=https://mirrors.aliyun.com/docker-ce/linux/rhel/9.6/x86_64/stable/
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/rhel/gpg


[epel]
name=epel
baseurl=https://mirrors.aliyun.com/epel/9/Everything/x86_64/
gpgkey=https://mirrors.aliyun.com/epel/RPM-GPG-KEY-EPEL-9
gpgcheck=1
enabled=1

2.环境参数配置

bash 复制代码
#!/bin/bash
# 最简容器环境准备(防火墙/SELinux/swap关闭 + 内核转发 + 时间同步)

# 1. 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld

# 2. 关闭 SELinux(临时+永久)
setenforce 0
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config

# 3. 关闭 swap(临时+永久)
swapoff -a
sed -i '/\bswap\b/s/^/#/' /etc/fstab

# 4. 加载必要内核模块(忽略 br_netfilter 不存在的情况)
modprobe overlay 2>/dev/null || true
modprobe br_netfilter 2>/dev/null || true
cat > /etc/modules-load.d/container.conf <<'EOF'
overlay
br_netfilter
EOF

# 5. 开启内核转发(必选)
cat > /etc/sysctl.d/99-container.conf <<'EOF'
net.ipv4.ip_forward = 1
EOF

# 如果 br_netfilter 已加载,添加 bridge 相关参数
if [ -d /proc/sys/net/bridge ]; then
    echo "net.bridge.bridge-nf-call-iptables = 1" >> /etc/sysctl.d/99-container.conf
    echo "net.bridge.bridge-nf-call-ip6tables = 1" >> /etc/sysctl.d/99-container.conf
fi

sysctl --system

# 6. 设置时区为北京时间
timedatectl set-timezone Asia/Shanghai

# 7. 启用并启动 chronyd 时间同步
systemctl enable chronyd
systemctl restart chronyd
chronyc -a makestep  # 强制立即同步

3.更新系统 安装docker

bash 复制代码
# 1. 更新系统软件包
sudo yum update -y

# 2. 安装基础依赖(vim编辑器、wget下载工具等)
sudo yum install -y vim wget net-tools

# 3. 安装 Docker 引擎(国内源,速度快)
sudo yum remove -y docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo systemctl start docker
sudo systemctl enable docker

# 4. 验证 Docker 是否安装成功
docker --version

第二阶段:安装部署

1.准备镜像

提前下载镜像并重新tag 方便使用

bash 复制代码
docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/gitlab/gitlab-ce:latest

docker tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/gitlab/gitlab-ce:latest gitlab/gitlab-ce:latest

docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/jenkins/jenkins:latest

docker tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/jenkins/jenkins:latest jenkins/jenkins:latest

2.部署容器

1.部署gitlab容器

1.创建目录 启动容器
bash 复制代码
mkdir -p /data/gitlab/{config,logs,data}
mkdir -p /data/jenkins
bash 复制代码
docker run -d \
--name gitlab \
--hostname 192.168.124.165 \
--restart always \
--shm-size 256m \
-p 80:80 \
-p 2222:22 \
-p 5050:5050 \
-v /data/gitlab/config:/etc/gitlab \
-v /data/gitlab/logs:/var/log/gitlab \
-v /data/gitlab/data:/var/opt/gitlab \
-e GITLAB_OMNIBUS_CONFIG="\
external_url 'http://192.168.124.165';
gitlab_rails['registry_enabled']=true;
registry_external_url 'http://192.168.124.165:5050'" \
gitlab/gitlab-ce:latest

具体的参数含义自行查阅了解,基本就是挂载卷,端口映射,环境变量和参数。

2.检查容器状态

初始化可能需要5-15分钟,可以进入容器查看状态。

bash 复制代码
#进入容器
docker exec -it gitlab bash

#查看状态
gitlab-ctl status

#查看数据库迁移状态
gitlab-rake db:migrate:status

如果组件状态都是run 并且数据库迁移状态up 说明没有问题

可以看到我上一步查看日志有报错,循环报错上述内容。

bash 复制代码
docker logs -f gitlab

不用关注,这个报错是因为gitlab-exporter监控采集失败的报错 大概原因是新版本已经使用PostgreSQL 分区表比如

p_ci_builds

p_ci_build_names

但是exporter 某些指标采集 SQL 可能仍然引用旧的

ci_pipelines

ci_job_artifacts

所以一直报错 relation does not exist

日志里可以看到确实使用了JOIN ci_pipelines之类的sql语句

可以忽略该告警,或者关闭监控,只要浏览器输入ip地址可以正常访问就可以。

当然也可以在容器内执行这个命令

bash 复制代码
gitlab-rake gitlab:check SANITIZE=true

如果这条命令最终结果是finished success pass通过检查 那就说明初始化完成 可以浏览器登录你的虚拟机ip地址访问了。

获取初始密码 默认用户名root 进入容器获取密码

bash 复制代码
docker exec -it gitlab bash

cat /etc/gitlab/initial_root_password

登录后修改密码 点头像-edit 进去之后找到左侧passwd 修改密码即可

3.可选项:关闭监控

容器内修改配置文件

bash 复制代码
#登录容器
docker exec -it gitlab bash
#修改配置文件
vi /etc/gitlab/gitlab.rb

在文件末位添加如下配置

bash 复制代码
### Disable monitoring stack
prometheus_monitoring['enable'] = false

prometheus['enable'] = false

alertmanager['enable'] = false

gitlab_exporter['enable'] = false

redis_exporter['enable'] = false

postgres_exporter['enable'] = false

退出保存然后执行下面重新生成配置

bash 复制代码
gitlab-ctl reconfigure

等待出现 gitlab Reconfigured!

然后重启

bash 复制代码
gitlab-ctl restart

再次检查组件状态

bash 复制代码
gitlab-ctl status

会发现exporter和prometheus之类的都没了,检查日志也不会有相关打印了。

4.创建用户级别token

accesstoken 如下图 头像-preference-accesstokens

添加描述和权限,为了方便可以全选权限,后面可以只用这一个token,虽然标准的做法是项目内部创建独立的。name可以自定义 我截图里是666 后来我换成user了,你可以使用自己喜欢的,和 (步骤 3.创建凭据 accesstoken )保持一致即可。

创建后记得复制保留token 忘了就只能重新创建。

5.修改docker配置测试登录

docke login 测试,在此之前需要修改docker配置添加地址为安全可信的,否则可能会报错。

bash 复制代码
cat >/etc/docker/daemon.json <<EOF
{
  "insecure-registries":[
    "192.168.124.164:5050"
  ]
}
EOF

重启docker

bash 复制代码
systemctl restart docker

登录

bash 复制代码
docker login 192.168.124.165:5050

用户名root 密码是之前创建的token

6.新建项目 demo-app

创建空白项目 blank

项目名字 demo-app 下拉框选择root空间 其他参考图片

7.测试推送镜像

随便下载一个nginx的打标签 然后推送

bash 复制代码
docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:alpine
docker tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:alpine 192.168.124.165:5050/root/demo-app/nginx:test
docker push 192.168.124.165:5050/root/demo-app/nginx:test

成功后可以在web界面上看到。

左侧橘色头像 projiects 找到personal的一个项目点进去

左侧deploy的container registry

可以看到自己的镜像已推送成功

2.部署jenkins容器

1.创建目录启动容器

Jenkins 容器默认用户是:uid=1000 (jenkins) 提前创建目录指定权限,否则会因为权限问题无法启动。

bash 复制代码
mkdir -p /data/jenkins
chown -R 1000:1000 /data/jenkins

然后启动容器

bash 复制代码
docker run -d \
  --name jenkins \
  --restart always \
  -p 8080:8080 \
  -p 50000:50000 \
  -v /data/jenkins:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v $(which docker):/usr/bin/docker \
  --group-add $(stat -c '%g' /var/run/docker.sock) \
  jenkins/jenkins:latest
2.获取初始密码登录
bash 复制代码
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

浏览器访问 http://192.168.124.165:8080(替换为自己的IP地址)

选择:安装推荐插件,等待安装完成,然后右下角继续注册用户,下一步url ,学习使用本地环境不用修改。

3.创建凭据 accesstoken

进入后 系统管理-凭据管理

直接点击global 蓝色小字

add凭据 用户名user 密码 就是目录中 4.创建用户级别token的token

4.安装插件 Generic Webhook Trigger

在插件管理中搜索该插件 确认安装该插件

5.创建任务demo-app

具体配置如下 勾选该选项

配置git地址 这里我分支 /master 修改为 /main 是为了和(6.修改主分支名字并推送代码)保持一致 如果你这里是master 步骤6就不用修改分支名字了使用git push -u origin master即可上图中url不确认的话可以去gitlab项目界面复制 http这个,Credentials就是之前创建的root。

6.配置webhook

在gitlab中配置,用来通知jenkins。

然后在gitlab 的webhook配置

最下方的enablessl关闭 保存

7.修改安全配置

左下角 admin

setting-network

找到outbonding 如下配置

保存退出

8.webhook测试

200即可

3.部署git

1.安装并初始化git
bash 复制代码
#安装git
yum install -y git
# 创建项目目录(绝对路径)
mkdir -p /home/jenkins/my-nginx-demo
cd /home/jenkins/my-nginx-demo

# 初始化 git 仓库
git init

配置git邮箱和用户名(自定义)

bash 复制代码
git config --global user.email "gitlab@test.com"

git config --global user.name "root"

添加远端仓库 url地址不缺人的话可以跳到(步骤2.部署jenkins容器- 步骤5.创建任务demo-app)中最后一步的地址

bash 复制代码
git remote add origin  http://192.168.124.165/root/demo-app.git
2.创建 index.html(自定义 Nginx 首页)
bash 复制代码
cat > /home/jenkins/my-nginx-demo/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Nginx</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>欢迎!</h1>
这是一个来自我的 Jenkins 构建的测试页面。
镜像版本: <!-- 版本号占位符 --></body>
</html>

EOF
3.创建 Dockerfile
bash 复制代码
cat > /home/jenkins/my-nginx-demo/Dockerfile << 'EOF'
# 1. 下载基础镜像
FROM nginx:alpine

# 2. 设置维护者信息(可选)
LABEL maintainer="jenkins"

# 3. 将本地的 html 文件夹复制到容器的默认网页目录
COPY index.html  /usr/share/nginx/html/

# 4. 【关键步骤】使用脚本动态替换版本号
# 这会在构建时把 index.html 里的占位符替换为当前的 Jenkins 构建号
RUN sed -i "s/<!-- 版本号占位符 -->/构建版本: ${BUILD_NUMBER}/g" /usr/share/nginx/html/index.html

# 5. 暴露端口
EXPOSE 80

# 6. 启动命令
CMD ["nginx", "-g", "daemon off;"]
EOF
4.创建 Jenkinsfile
bash 复制代码
cat > /home/jenkins/my-nginx-demo/Jenkinsfile << 'EOF'
pipeline {
    agent any

    // 定义环境变量,方便统一管理
    environment {
        // 你的私有仓库地址和项目路径
        REGISTRY   = '192.168.124.165:5050'
        REPO_PATH  = 'root/demo-app'
        IMAGE_NAME = "${REGISTRY}/${REPO_PATH}/nginx-demo"
        TAG        = "${BUILD_NUMBER}"
    }

    stages {
        stage('1. 清理环境') {
            steps {
                echo "清理旧文件和旧镜像..."
                // 删除本地可能存在的旧镜像,防止冲突
                sh "docker rmi ${IMAGE_NAME}:${TAG} || true"
                sh "rm -rf index.html.bak || true"
            }
        }

        stage('2. 代码准备') {
            steps {
                echo "准备网页文件..."
                // 这里模拟代码修改,直接修改本地文件以便观察变化
                // 将版本号写入文件(实际项目中通常是 Git 检出代码)
                sh '''
                    # 替换占位符为当前构建号
                    sed -i "s/<!-- 版本号占位符 -->/构建版本: ${BUILD_NUMBER}/g" index.html

                    # 打印出来看看对不对
                    echo "=== 当前 index.html 内容 ==="
                    cat index.html
                '''
            }
        }

        stage('3. 构建镜像') {
            steps {
                echo "开始构建 Docker 镜像..."
                sh "docker build -t ${IMAGE_NAME}:${TAG} ."
            }
        }

        stage('4. 登录并推送') {
            steps {
                script {
                    // 使用 withCredentials 绑定之前创建的 Deploy Token
                    withCredentials([usernamePassword(
                        credentialsId: 'token',
                        usernameVariable: 'REG_USER',
                        passwordVariable: 'REG_PASS'
                    )]) {
                        sh '''
                            echo "正在登录私有仓库..."
                            echo "$REG_PASS" | docker login ${REGISTRY} -u "$REG_USER" --password-stdin

                            echo "推送镜像 ${IMAGE_NAME}:${TAG} ..."
                            docker push ${IMAGE_NAME}:${TAG}

                            echo "推送 latest 标签..."
                            docker tag ${IMAGE_NAME}:${TAG} ${IMAGE_NAME}:latest
                            docker push ${IMAGE_NAME}:latest
                        '''
                    }
                }
            }
        }
    }

    post {
        success {
            echo "🎉 成功!镜像已推送到: ${IMAGE_NAME}:${TAG}"
        }
        failure {
            echo "❌ 构建失败,请检查日志。"
        }
        always {
            // 清理登录状态
            sh 'docker logout ${REGISTRY} || true'
        }
    }
}

EOF
5.提交git代码
bash 复制代码
git add .
git commit -m "666"
6.修改主分支名字并推送代码

在git初始化的目录中执行

bash 复制代码
git branch

查看本地分支为master 仓库默认使用main 推荐修改为main再推送

bash 复制代码
git branch -m master main

git push -u origin main

用户名 user 密码就是token 不确认的话跳转 (4.创建用户级别token)

7.jenkins页面检查构建任务

点击任务-流水线步骤 可以查看详情

点击任务-consoleoutput 可以查看日志

8.gitlab仓库查看镜像

可以看到历史的2个版本 16 17 我使用的构建任务编号作为镜像的后缀

9.本地查看镜像
bash 复制代码
docker images

可以看到本地的产物16 17 并且17对于的就是latest 如果再构建一次 latest就是18 自动更新 代码实现的逻辑在jenkinsfile中,具体自己了解。

10.验证镜像命名

在项目界面点击立即构建 可以看到#18开始构建

仓库和本地也有了产物

待续:CD流程

基础的CI流程至此已完成,感兴趣可以考虑增加代码检测等其他插件和流程。

关于CD流程,持续部署,需要搭建K8S集群和CI联动。虽然我有一个三节点的k8s集群,但是PC资源不足,不能同时开启这么多虚拟机,暂时不打算进行后续测试,CD有两种模式。

1.主动部署(Push 模式)------ Jenkins 直接操作目标服务器

主动部署(Push 模式)------ Jenkins 直接操作目标服务器

原理:

Jenkins 在构建并推送镜像后,通过 SSH、Ansible、Kubernetes API 等工具,主动登录到目标服务器(或集群)执行拉取新镜像、重启容器等操作。

优点:

控制权在 Jenkins,部署时机精确。

适合需要复杂编排的场景(如蓝绿部署、金丝雀发布)。

对目标环境要求低(只需 SSH 或 API 可达)。

缺点:

Jenkins 需要持有目标服务器的访问凭证(密钥、Token)。

目标服务器数量增多时管理成本上升。

2.被动部署(Pull 模式)------ 目标服务器主动检测更新

原理:​

Argo CD 作为 Kubernetes 集群内的控制器,持续监听 Git 仓库中声明的期望状态(如 Deployment 的镜像版本)。当 Git 仓库中的配置发生变化(例如 Jenkins 更新了 k8s/deployment.yaml中的镜像标签),Argo CD 会自动检测到差异,并将集群的实际状态拉取(Pull)至与 Git 一致,无需 Jenkins 主动触发部署。

优点:​

声明式、可审计:所有部署配置都存储在 Git 中,天然具备版本控制和回滚能力。

自动化程度高:Argo CD 持续对账,一旦 Git 变更,自动同步到集群,无需人工干预。

安全性好:Jenkins 无需持有 Kubernetes 集群的访问凭证,只需有 Git 仓库的写入权限即可。

适合大规模集群:Argo CD 原生支持多集群、多环境,管理成本较低。

缺点:​

强依赖 Kubernetes:Argo CD 本身是 Kubernetes 原生应用,必须运行在 Kubernetes 集群内。

部署延迟:同步周期默认为 3 分钟(可通过 Webhook 缩短),无法做到毫秒级响应。

学习曲线:需要理解 GitOps 理念、Application CRD 以及 Argo CD 的配置方式。

不适合非容器化应用:仅适用于 Kubernetes 资源管理,对传统虚拟机或物理机部署无能为力。

结束语

内容略多 可能有细节出现错误或者未修改,请指正,看到会及时修改。

相关推荐
IT WorryFree1 小时前
GitHub Actions 流水线注入敏感配置完整方案(Antora + Docker Compose)
docker·容器·github
十月的皮皮2 小时前
C语言学习笔记20260614-数组奇偶数调整3种方法
c语言·笔记·学习
怪我冷i2 小时前
人工智能的数学基础——学习笔记
人工智能·笔记·学习
java_cj2 小时前
从kubectl源码学Cobra:打造专业级Go命令行工具的完整实践
运维·开发语言·后端·云原生·golang·kubernetes·k8s
烁3472 小时前
Oracle学习
数据库·学习·oracle
小的博客2 小时前
Oh-My-Posh安装及使用
学习·数据可视化
186******205312 小时前
新手高效学习知识体系构建指南
学习
俏皮小混子2 小时前
山东大学软件学院项目实训-创新实训-计科智伴(六)——个人博客(后端运行后真实调整)
人工智能·笔记·学习·ui
梦想的颜色2 小时前
Dockerfile 深度实战:从指令底层原理到生产级镜像构建的艺术
docker·容器·镜像·dockerfile·dockerfile解析