在CI/CD流水线中自动化实现镜像扫描和推送到Harbor,是提升容器安全性和部署效率的关键。下面这张流程图直观展示了其核心步骤与决策点,你可以结合后续的详细说明来实践。

下面,我们详细解析每个阶段的关键操作。
🔧 阶段一:代码编译与镜像构建
这个阶段负责将源代码构建成Docker镜像。
- 基础环境配置 :确保你的CI/CD环境(如Jenkins、GitLab Runner)已安装Docker,并配置为可访问你的Harbor私有仓库。通常需要在Docker配置中声明Harbor仓库地址为非安全注册表(
insecure-registries)或配置正确的CA证书。 - 构建与标记镜像 :在流水线脚本中,使用
docker build命令构建镜像,并使用docker tag为镜像打上符合Harbor规范的标签,格式通常为<harbor-server>/<project-name>/<image-name>:<tag>。
🔍 阶段二:镜像安全扫描与质量门禁
这是保障安全的核心环节,通常在构建之后、推送之前进行。
-
集成扫描工具 :在流水线中集成漏洞扫描工具,如开源的Trivy、Clair或商业工具。将这些工具的命令直接添加到流水线脚本中。一个典型的Trivy扫描命令如下:
arduino# 扫描镜像并生成报告,如果发现高危或严重漏洞则使构建失败 trivy image --exit-code 1 --severity HIGH,CRITICAL <your-image-tag> -
设置质量门禁 :通过工具的退出代码(如Trivy的
--exit-code 1)或策略检查,在发现超过预设严重级别的漏洞时,主动让CI/CD流水线失败,从而阻断不安全的镜像流入后续环节。你还可以配置只阻断新引入的高危漏洞,这对于初步建立流程的团队非常有用。
📤 阶段三:推送镜像至Harbor
通过安全扫描后,镜像可以被推送到Harbor。
-
登录Harbor :在流水线脚本中使用
docker login命令认证Harbor。务必使用凭证管理工具(如Jenkins的Credentials Binding插件)安全地处理用户名和密码,避免硬编码。bashdocker login -u $HARBOR_USER -p $HARBOR_PASSWORD $HARBOR_SERVER -
推送镜像 :使用
docker push命令将打好标签的镜像推送到Harbor的指定项目中。
🚀 阶段四:部署到Kubernetes
镜像推送成功后,流水线可自动或手动触发部署步骤。
- 更新部署清单:通常需要更新Kubernetes的YAML文件或Helm Chart中的镜像标签,指向刚刚推送到Harbor的新镜像。
- 执行部署命令 :使用
kubectl apply或Helm命令来更新Kubernetes中的部署。确保CI/CD系统拥有操作K8s集群的必要权限(可通过ServiceAccount等方式配置)。
💡 进阶实践与建议
- 使用Harbor的机器人账户:为CI/CD流程创建专门的Harbor"机器人账户",并赋予最小必要权限(通常仅限指定项目的推送权限),这比使用个人管理员账户更安全。
- 定期扫描与策略管理 :除了推送前扫描,还可以利用Harbor内置的漏洞扫描功能设置镜像标签不可变、自动扫描、阻止运行有严重漏洞的镜像等策略。同时,可设置定时任务(如每晚)重新扫描仓库中的旧镜像,以应对新披露的漏洞。
- 遵循Dockerfile最佳实践 :安全始于构建。在Dockerfile中尽量使用轻量级基础镜像 ,以非root用户运行应用,并进行多阶段构建以减少最终镜像的攻击面。
🧩 示例流水线脚本片段 (Jenkins Pipeline)
以下是一个简化的Jenkins Pipeline脚本示例,它串联了上述主要步骤:
kotlin
pipeline {
agent any
environment {
HARBOR_SERVER = 'your-harbor.com'
PROJECT_NAME = 'your-project'
IMAGE_NAME = 'your-app'
}
stages {
stage('Build') {
steps {
script {
docker.build("${IMAGE_NAME}:${env.BUILD_ID}")
}
}
}
stage('Security Scan') {
steps {
script {
// 使用Trivy扫描,如果发现HIGH/CRITICAL漏洞则失败
sh "trivy image --exit-code 1 --severity HIGH,CRITICAL ${IMAGE_NAME}:${env.BUILD_ID}"
}
}
}
stage('Push to Harbor') {
steps {
script {
withCredentials([usernamePassword(credentialsId: 'harbor-cred', usernameVariable: 'HARBOR_USER', passwordVariable: 'HARBOR_PASSWORD')]) {
sh "docker tag ${IMAGE_NAME}:${env.BUILD_ID} ${HARBOR_SERVER}/${PROJECT_NAME}/${IMAGE_NAME}:${env.BUILD_ID}"
sh "docker login -u $HARBOR_USER -p $HARBOR_PASSWORD $HARBOR_SERVER"
sh "docker push ${HARBOR_SERVER}/${PROJECT_NAME}/${IMAGE_NAME}:${env.BUILD_ID}"
}
}
}
}
stage('Deploy to K8s') {
steps {
sh "sed -i 's|IMAGE_TAG|${env.BUILD_ID}|g' k8s-deployment.yaml"
sh "kubectl apply -f k8s-deployment.yaml"
}
}
}
}