Github Actions中Docker镜像重复构建的流水线优化求助
问题描述
我刚用Github Actions搭建了一条流水线,步骤为:构建Docker应用 → 运行测试 → 发布至Docker镜像仓库。但测试与发布是两个独立Job,导致Docker镜像被重复构建两次。该镜像是Ruby-On-Rails应用,bundle install每次耗时2-3分钟,严重拖慢流水线速度。
我曾尝试在docker/build-push-action@v3中添加cache-from: type=gha和cache-to: type=gha,mode=max来加速构建,但出现报错:
Error: buildx failed with: ERROR: cache export feature is currently not supported for docker driver. Please switch to a different driver (eg. "docker buildx create --use")
请问如何修改流水线以缩短耗时?
原工作流代码:
name: Test & Publish Docker Image on: push: branches: [ master ] pull_request: branches: [ master ] jobs: run_application_tests: name: Run test suite runs-on: ubuntu-latest env: COMPOSE_FILE: docker-compose.yml DOCKER_USER: ${{ secrets.DOCKER_USER }} DOCKER_PASS: ${{ secrets.DOCKER_PASS }} steps: - name: Checkout code uses: actions/checkout@v3 - name: Login To Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and run docker image run: docker-compose up -d --build - name: Run migrations run: make migrate - name: Run tests run: make test build_and_publish_docker_image: needs: run_application_tests name: Build & Publish Docker Images runs-on: ubuntu-latest steps: - name: Checkout The Repo uses: actions/checkout@v3 - name: Login To Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build & Push Docker Image uses: docker/build-push-action@v3 with: push: true tags: | me/image:latest me/image:${{ github.sha }}
解决方案
1. 解决Buildx缓存报错:切换支持缓存的驱动
Github Actions默认Docker驱动不支持Buildx缓存导出功能,需先初始化Buildx专用驱动:
在使用docker/build-push-action前添加以下步骤:
- name: Set up Docker Buildx uses: docker/setup-buildx-action@v2
该步骤会自动创建并启用支持缓存的Buildx驱动,解决之前的报错。
2. 跨Job复用镜像,避免重复构建
将构建逻辑与测试合并为一个Job,同时利用GHA缓存让发布Job直接复用构建层,无需重新执行bundle install:
- 测试Job中先构建带缓存的镜像,再用该镜像运行测试
- 发布Job从GHA缓存拉取镜像层,仅执行推送操作
3. 优化Dockerfile的分层缓存
在Dockerfile中调整bundle install的位置,利用Docker分层缓存减少依赖安装次数:
# 先复制Gemfile相关文件,仅当Gemfile变更时才重新执行bundle install COPY Gemfile Gemfile.lock ./ RUN bundle install --jobs 4 --retry 3 # 再复制项目其他代码 COPY . .
修改后的完整工作流代码
name: Test & Publish Docker Image on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build_and_test: name: Build image & run tests runs-on: ubuntu-latest env: COMPOSE_FILE: docker-compose.yml steps: - name: Checkout code uses: actions/checkout@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Login To Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build Docker image with cache uses: docker/build-push-action@v3 with: context: . load: true # 将构建好的镜像加载到本地Docker,用于测试 tags: me/image:test-${{ github.sha }} cache-from: type=gha cache-to: type=gha,mode=max - name: Update docker-compose to use test image run: | sed -i 's/image: me\/image:latest/image: me\/image:test-${{ github.sha }}/' docker-compose.yml - name: Start application & run migrations run: | docker-compose up -d make migrate - name: Run tests run: make test publish_image: needs: build_and_test name: Publish Docker Images runs-on: ubuntu-latest steps: - name: Checkout The Repo uses: actions/checkout@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Login To Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Push Docker Image (use cache) uses: docker/build-push-action@v3 with: push: true tags: | me/image:latest me/image:${{ github.sha }} cache-from: type=gha
关键改动说明
- 合并构建与测试Job,避免第一次构建资源浪费
- 两个Job均添加
docker/setup-buildx-action,解决Buildx缓存驱动问题 - 发布Job直接从GHA缓存拉取镜像层,跳过耗时的
bundle install步骤 - Dockerfile分层优化,进一步减少依赖重复安装次数
内容的提问来源于stack exchange,提问作者A. Vreeswijk
相关产品推荐
相关产品推荐

