Docker集成 #
一、GitLab Container Registry #
启用Container Registry #
- 进入项目Settings → Packages & Registries
- 启用Container Registry
镜像命名规范 #
text
registry.example.com/group/project:tag
│ │ │ │
│ │ │ └── 标签
│ │ └── 项目名
│ └── 组名
└── Registry地址
常用镜像标签 #
| 标签 | 说明 |
|---|---|
latest |
最新版本 |
main |
主分支构建 |
develop |
开发分支构建 |
v1.0.0 |
版本标签 |
abc123 |
Commit SHA |
二、Docker构建 #
基本构建 #
yaml
stages:
- build
docker_build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
多阶段构建 #
Dockerfile:
dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
yaml
docker_build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
缓存优化 #
yaml
docker_build:
script:
- docker pull $CI_REGISTRY_IMAGE:latest || true
- docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
BuildKit构建 #
yaml
docker_build:
variables:
DOCKER_BUILDKIT: 1
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
三、多架构构建 #
使用docker buildx #
yaml
docker_build:
image: docker:latest
services:
- docker:dind
variables:
DOCKER_CLI_EXPERIMENTAL: enabled
before_script:
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- docker buildx create --use
script:
- docker buildx build --platform linux/amd64,linux/arm64 -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --push .
矩阵并行构建 #
yaml
docker_build:
parallel:
matrix:
- ARCH: [amd64, arm64]
image: docker:latest
services:
- docker:dind
script:
- docker build --platform linux/$ARCH -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-$ARCH .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-$ARCH
manifest:
stage: manifest
image: docker:latest
services:
- docker:dind
needs:
- job: docker_build
artifacts: false
script:
- docker manifest create $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA \
$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-amd64 \
$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA-arm64
- docker manifest push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
四、镜像扫描 #
Trivy扫描 #
yaml
container_scanning:
stage: test
image: docker:latest
services:
- docker:dind
variables:
IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
script:
- docker pull $IMAGE
- |
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image --exit-code 1 --severity HIGH,CRITICAL $IMAGE
allow_failure: true
GitLab Container Scanning #
yaml
include:
- template: Jobs/Container-Scanning.gitlab-ci.yml
variables:
CS_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
Clair扫描 #
yaml
container_scanning:
stage: test
image: docker:latest
services:
- docker:dind
- name: arminc/clair-db:latest
alias: postgres
- name: arminc/clair-local-scan:v2.0.1
alias: clair
script:
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- |
wget -O clair-scanner https://github.com/arminc/clair-scanner/releases/download/v12/clair-scanner_linux_amd64
chmod +x clair-scanner
./clair-scanner -c http://clair:6060 --ip $(hostname -i) -r gl-container-scanning-report.json \
-l clair.log $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA || true
artifacts:
reports:
container_scanning: gl-container-scanning-report.json
五、镜像推送策略 #
分支推送 #
yaml
docker_build:
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- |
if [ "$CI_COMMIT_BRANCH" == "main" ]; then
docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
docker push $CI_REGISTRY_IMAGE:latest
elif [ "$CI_COMMIT_BRANCH" == "develop" ]; then
docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:develop
docker push $CI_REGISTRY_IMAGE:develop
fi
标签推送 #
yaml
docker_build:
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
only:
- tags
版本管理 #
yaml
docker_build:
script:
- |
if [[ $CI_COMMIT_TAG =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
MAJOR="${BASH_REMATCH[1]}"
MINOR="${BASH_REMATCH[2]}"
PATCH="${BASH_REMATCH[3]}"
docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG .
docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG $CI_REGISTRY_IMAGE:$MAJOR.$MINOR
docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG $CI_REGISTRY_IMAGE:$MAJOR
docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
docker push $CI_REGISTRY_IMAGE:$MAJOR.$MINOR
docker push $CI_REGISTRY_IMAGE:$MAJOR
fi
only:
- tags
六、Docker Compose #
构建和测试 #
yaml
test:
stage: test
image: docker:latest
services:
- docker:dind
script:
- docker-compose -f docker-compose.test.yml up --abort-on-container-exit
docker-compose.test.yml:
yaml
version: '3.8'
services:
app:
build: .
depends_on:
- db
- redis
environment:
- DATABASE_URL=postgres://test:test@db:5432/test
- REDIS_URL=redis://redis:6379
command: npm test
db:
image: postgres:14
environment:
- POSTGRES_DB=test
- POSTGRES_USER=test
- POSTGRES_PASSWORD=test
redis:
image: redis:7
部署 #
yaml
deploy:
stage: deploy
image: docker:latest
services:
- docker:dind
script:
- docker-compose -f docker-compose.prod.yml pull
- docker-compose -f docker-compose.prod.yml up -d
七、完整示例 #
yaml
stages:
- lint
- build
- test
- scan
- push
- deploy
variables:
DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
lint_dockerfile:
stage: lint
image: hadolint/hadolint:latest-debian
script:
- hadolint Dockerfile
allow_failure: true
docker_build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $CI_REGISTRY_IMAGE:latest || true
- docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $DOCKER_IMAGE .
- docker push $DOCKER_IMAGE
container_scanning:
stage: scan
image: docker:latest
services:
- docker:dind
script:
- docker pull $DOCKER_IMAGE
- |
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image --exit-code 0 --severity HIGH,CRITICAL -o trivy-report.json $DOCKER_IMAGE
artifacts:
paths:
- trivy-report.json
expire_in: 1 week
allow_failure: true
push_latest:
stage: push
image: docker:latest
services:
- docker:dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $DOCKER_IMAGE
- docker tag $DOCKER_IMAGE $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:latest
only:
- main
deploy_staging:
stage: deploy
image: docker:latest
services:
- docker:dind
environment:
name: staging
url: https://staging.example.com
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker pull $DOCKER_IMAGE
- docker tag $DOCKER_IMAGE $CI_REGISTRY_IMAGE:staging
- docker push $CI_REGISTRY_IMAGE:staging
- |
ssh deploy@staging.example.com << EOF
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
docker pull $CI_REGISTRY_IMAGE:staging
docker stop myapp || true
docker rm myapp || true
docker run -d --name myapp -p 3000:3000 $CI_REGISTRY_IMAGE:staging
EOF
only:
- develop
deploy_production:
stage: deploy
image: bitnami/kubectl:latest
environment:
name: production
url: https://example.com
script:
- kubectl set image deployment/myapp myapp=$DOCKER_IMAGE
- kubectl rollout status deployment/myapp
only:
- main
when: manual
八、最佳实践 #
1. 使用多阶段构建 #
dockerfile
FROM node:18 AS builder
# 构建阶段
FROM nginx:alpine
# 运行阶段
2. 使用alpine镜像 #
dockerfile
FROM node:18-alpine
3. 缓存优化 #
yaml
script:
- docker pull $CI_REGISTRY_IMAGE:latest || true
- docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $IMAGE .
4. 安全扫描 #
yaml
include:
- template: Jobs/Container-Scanning.gitlab-ci.yml
5. 镜像清理 #
yaml
cleanup:
stage: cleanup
image: docker:latest
script:
- docker image prune -af
when: always
下一步 #
现在你已经掌握了Docker集成,接下来让我们学习 Kubernetes部署!
最后更新:2026-03-28