如何在GitLab CI中将Docker Compose所需多镜像推送到GitLab Registry
解决GitLab CI中Docker Compose服务镜像构建与推送的问题
别急,我来一步步帮你搞定这个需求——把Docker Compose里的各个自定义服务(比如php-fpm、nginx)构建成可推送的镜像,完美适配GitLab CI的流水线流程,同时保留开发环境用Docker Compose本地构建的便利性。
核心思路
简单来说就是:给每个自定义服务单独构建镜像,推送到GitLab Registry(和GitLab集成最省心,不用额外折腾Docker Hub),然后在CI流水线或生产环境的Docker Compose配置里直接拉取这些预构建的镜像,而非每次重新构建。
具体步骤
1. 规范镜像命名与版本控制
为了避免镜像混乱,建议用GitLab内置的变量来自动生成镜像名,比如:
- 镜像前缀:
registry.gitlab.com/你的用户名/你的项目名(GitLab Registry的默认地址) - 标签:用
$CI_COMMIT_SHA(当前提交的哈希值)作为唯一标签,方便回滚;同时加latest标签指向主分支的最新稳定版
示例镜像名:
- php-fpm:
registry.gitlab.com/your-username/your-project/php-fpm:abc123(abc123是提交哈希) - nginx:
registry.gitlab.com/your-username/your-project/nginx:latest
2. 拆分Docker Compose配置(区分开发/CI/生产)
为了同时满足开发环境本地构建和CI/生产环境拉取镜像的需求,我们可以用多文件配置:
主配置文件 docker-compose.yml
这个文件只定义通用配置(端口、挂载、依赖等),镜像名用环境变量占位:
services: php-fpm: image: ${PHP_IMAGE:-local-php-fpm} volumes: - ./src:/app # 其他通用配置(比如环境变量、depends_on等) nginx: image: ${NGINX_IMAGE:-local-nginx} ports: - "80:80" volumes: - ./src:/app depends_on: - php-fpm # mysql这类用官方镜像的服务,直接写死镜像名就行 mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
开发环境配置文件 docker-compose.dev.yml
这个文件专门用来定义本地构建规则,开发时和主配置一起使用:
services: php-fpm: build: ./docker/php-fpm nginx: build: ./docker/nginx
开发时启动命令:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d
3. 编写GitLab CI流水线(构建并推送镜像)
在.gitlab-ci.yml里添加构建推送的阶段,利用GitLab的Docker-in-Docker(dind)服务来完成镜像构建:
stages: - build-images - test # 可选,用构建好的镜像跑测试 - deploy # 可选,部署到生产 # 定义全局变量,自动填充镜像名 variables: CI_REGISTRY_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH PHP_IMAGE: $CI_REGISTRY_IMAGE/php-fpm:$CI_COMMIT_SHA PHP_IMAGE_LATEST: $CI_REGISTRY_IMAGE/php-fpm:latest NGINX_IMAGE: $CI_REGISTRY_IMAGE/nginx:$CI_COMMIT_SHA NGINX_IMAGE_LATEST: $CI_REGISTRY_IMAGE/nginx:latest build-images: stage: build-images image: docker:latest services: - docker:dind before_script: # 自动登录GitLab Registry,用GitLab内置的CI变量,无需手动配置密码 - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY script: # 构建php-fpm镜像并推送两个标签(唯一哈希+latest) - docker build -t $PHP_IMAGE -t $PHP_IMAGE_LATEST ./docker/php-fpm - docker push $PHP_IMAGE - docker push $PHP_IMAGE_LATEST # 构建并推送nginx镜像 - docker build -t $NGINX_IMAGE -t $NGINX_IMAGE_LATEST ./docker/nginx - docker push $NGINX_IMAGE - docker push $NGINX_IMAGE_LATEST # 其他自定义服务(比如redis如果有自定义镜像)同理操作 only: - main # 主分支推送latest标签,其他分支可以只推哈希标签(去掉only规则即可) # 可选:用构建好的php-fpm镜像跑单元测试 test-php: stage: test image: $PHP_IMAGE script: - cd /app - php vendor/bin/phpunit # 替换成你的测试命令 only: - main - merge_requests # 可选:部署到生产环境(示例用Docker Compose拉取镜像启动) deploy-production: stage: deploy image: docker:latest services: - docker:dind before_script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY # 如果需要部署到远程服务器,这里可以添加SSH连接配置(比如用GitLab的SSH变量) script: # 设置环境变量指向latest镜像,启动服务 - export PHP_IMAGE=$PHP_IMAGE_LATEST - export NGINX_IMAGE=$NGINX_IMAGE_LATEST - docker-compose up -d only: - main
4. 关键注意事项
- 跳过无需自定义的服务:比如mysql、redis这类官方镜像足够用的,直接在Docker Compose里用官方镜像就行,不用自己构建推送,节省时间和仓库空间。
- GitLab Registry权限:确保你的项目CI/CD权限是开启的,GitLab会自动提供
CI_REGISTRY_USER和CI_REGISTRY_PASSWORD这两个变量,无需手动配置。 - Runner配置:如果用Docker-in-Docker(dind),要确保Runner的配置里开启了
privileged模式;如果觉得dind资源消耗大,可以直接挂载Runner主机的/var/run/docker.sock到Runner容器里(需要Docker版本兼容)。 - 标签策略:用
$CI_COMMIT_SHA做标签可以精准定位到每一次提交的镜像,方便回滚;latest标签适合生产环境快速部署最新稳定版。
这样一套流程下来,你就能在GitLab CI里自动构建推送所有自定义服务的镜像,不管是CI流程里用这些镜像跑测试,还是生产环境用Docker Compose拉取部署,都能完美衔接。如果还有某个服务的细节搞不定,随时说!
内容的提问来源于stack exchange,提问作者user9874638
相关产品推荐
相关产品推荐

