简体   繁体   English

使用 docker/build-push-action 在 GitHub Actions 中本地构建 docker 镜像

[英]Build docker image locally in GitHub Actions using docker/build-push-action

I have several Dockerfiles in my project.我的项目中有几个 Dockerfile。 One is for building basic image, which contains some business-level abstractions.一种是用于构建basic图像,其中包含一些业务级别的抽象。 Others are building services, based on the basic image.其他人正在构建服务,基于basic形象。

So in my services' Dockerfiles I have something like所以在我的服务的 Dockerfiles 中,我有类似的东西

FROM my-project/base
# Adding some custom logic around basic stuff

I am using GitHub Actions as my CI/CD tool.我使用 GitHub Actions 作为我的 CI/CD 工具。 At first I had a step to install docker into my workers, and then ran something like:起初我有一个步骤将 docker 安装到我的工人中,然后运行如下:

- name: Build base image
  working-directory: business
  run: docker build -t my-project/base .

- name: Build and push service
  working-directory: service
  run: |
    docker build -t my-ecr-repo/service .
    docker push my-ecr-repo/service

But then I've found docker/build-push-action and decided to use it in my pipeline:但是后来我找到了 docker/build-push-action 并决定在我的管道中使用它:

- name: Build business-layer container
  uses: docker/build-push-action@v2
  with:
    load: true
    tags: my-project/base
    context: business
    file: business/Dockerfile

- name: Build service
  uses: docker/build-push-action@v2
  with:
    push: true
    tags: my-ecr-repo/service
    context: service
    file: service/Dockerfile

As for now, the second step tries to download docker.io /my-project/base, and obviously cannot do it, because I never push base image:至于现在,第二步尝试下载docker.io /my-project/base,显然做不到,因为我从来没有推送过base image:

ERROR: pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed

The question is: What is the correct way to build an image, so it is accessible by the following building steps locally?问题是:构建镜像的正确方法什么,因此可以通过以下构建步骤在本地访问它?

PS: I don't want to push my naked basic image anywhere. PS:我不想将我的裸体basic图像推到任何地方。

I believe you'll need to set load: true in both your base image and the final image.我相信您需要在基本图像和最终图像中设置load: true This changes the behavior to use the local docker engine for images.这改变了使用本地 docker 引擎处理图像的行为。 I believe you'll need to run a separate push if you do this, eg:我相信如果你这样做,你需要运行一个单独的推送,例如:

- name: Build business-layer container
  uses: docker/build-push-action@v2
  with:
    load: true
    tags: my-project/base
    context: business
    file: business/Dockerfile

- name: Build service
  uses: docker/build-push-action@v2
  with:
    load: true
    tags: my-ecr-repo/service
    context: service
    file: service/Dockerfile

- name: push service
  run: |
    docker push my-ecr-repo/service

The other option is to use a local registry.另一种选择是使用本地注册表。 This has the advantage of supporting multi-platform builds.这具有支持多平台构建的优势。 But you'll want to switch from load to push with your base image, and I'd pass the base image as a build arg to make it easier for use cases outside of Github actions, eg:但是你会想要从load切换到使用你的基本图像push ,我会将基本图像作为构建参数传递,以使其更容易用于 Github 操作之外的用例,例如:

jobs:
  local-registry:
    runs-on: ubuntu-latest
    services:
      registry:
        image: registry:2
        ports:
          - 5000:5000
    steps:
      - name: Login to DockerHub
        uses: docker/login-action@v1 
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      # qemu should only be needed for multi-platform images
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
        with:
          driver-opts: network=host
      - name: Build business-layer container
        uses: docker/build-push-action@v2
        with:
          push: true
          tags: localhost:5000/my-project/base
          context: business
          file: business/Dockerfile
      - name: Build service
        uses: docker/build-push-action@v2
        with:
          push: true
          tags: my-ecr-repo/service
          context: service
          file: service/Dockerfile
          build-args: |
            BASE_IMAGE=localhost:5000/my-project/base

And then your Dockerfile would allow the base image to be specified as a build arg:然后您的 Dockerfile 将允许将基本映像指定为构建参数:

ARG BASE_IMAGE=my-project/base
FROM ${BASE_IMAGE}
# ...

The github action docker/setup-buildx-action@v1 defaults to driver docker-container as documented . GitHub的动作docker/setup-buildx-action@v1默认为驾驶员docker-container如记录
This means builds will run, by default, in a container and thus images won't be available outside of the action.这意味着构建将默认在容器中运行,因此图像在操作之外将不可用。
The solution is to set the driver to docker :解决方案是将驱动程序设置为docker

     ...

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
        with:
          driver: docker # defaults to "docker-containerized"

      - name: Build business-layer container
        uses: docker/build-push-action@v2
        with:
          # using "load: true" forces the docker driver
          # not necessary here, because we set it before
          #load: true
          tags: my-project/base:latest
          context: business
          file: business/Dockerfile

      - name: Build service
        uses: docker/build-push-action@v2
        with:
          # using "push: true" will lead to error:
          # Error: buildx call failed with: auto-push is currently not implemented for docker driver
          # so you will have to follow the solution outlined here:
          # https://github.com/docker/build-push-action/issues/100#issuecomment-715352826
          # and push the image manually following the build
          #push: true
          tags: my-ecr-repo/service:latest
          context: service
          file: service/Dockerfile

      # list all images, you will see my-ecr-repo/service and my-project/base
      - name: Look up images
        run: docker image ls

      # push the image manually, see above comment
      - name: Push image
        run: docker push my-ecr-repo/service:latest

     ...

There is no special steps involved to use local image during build.在构建期间使用本地映像没有涉及特殊步骤。 Docker always checks what you have locally before going into registry. Docker 总是在进入注册表之前检查您在本地拥有的内容。 If you do both steps in one session and didn't make a typo somewhere - it simply works.如果您在一个会话中完成了两个步骤并且没有在某处打错字 - 它就可以正常工作。

Now if it doesn't there are only two possible sources of problem left: it is either the environment on which you build those images or the action you use.现在,如果没有,则只剩下两个可能的问题来源:要么是您构建这些图像的环境,要么是您使用的操作。 Try running on ubuntu-latest and see if anything changes to eliminate the first.尝试在ubuntu-latest上运行,看看是否有任何更改以消除第一个。

I can also offer you two options to solve this but you probably won't like them both:我还可以为您提供两种解决方案,但您可能不会同时喜欢它们:

1. Use temporary local registry. 1. 使用临时本地注册表。 I found this guide on the readme page of the action that you use and slightly changed it for your code:我在您使用的操作的自述页面上找到了本指南,并为您的代码稍微更改了它:

jobs:
  local-registry:
    runs-on: ubuntu-latest
    services:
      registry:
        image: registry:2
        ports:
          - 5000:5000
    steps:
      -
        name: Set up QEMU
        uses: docker/setup-qemu-action@v2
      -
        name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
        with:
          driver-opts: network=host
      -
        name: Build business-layer container
        uses: docker/build-push-action@v2
        with:
          load: true
          tags: localhost:5000/my-project/base
          context: business
          file: business/Dockerfile
      - 
        name: Build service
        uses: docker/build-push-action@v2
        with:
          push: true
          tags: my-ecr-repo/service
          context: service
          file: service/Dockerfile

Of course you have to update the service/Dockerfile to point to localhost:5000/my-project/base instead of just my-project/base .当然,您必须更新service/Dockerfile以指向localhost:5000/my-project/base而不仅仅是my-project/base

2. Use simple shell instead of build-push-action. 2. 使用简单的 shell 而不是 build-push-action。 If your old code works and that action does not, well may be the problem is in the action after all.如果您的旧代码有效而该操作无效,那么问题可能出在操作中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 带有 docker/build-push-action 和 GitHub Actions 的生产环境文件 - Production ENV file with docker/build-push-action and GitHub Actions Github 操作:如何在 build-push-action 构建的 docker 图像中运行容器化测试,而不会加倍执行时间 - Github Actions: How to run containerized tests in a docker image built by build-push-action without doubling execution time 如何缩短 docker build-push-action 映像名称 - How to shorten docker build-push-action image name 使用 docker/build-push-action 让 .NET Docker 映像知道其版本 - Let a .NET Docker image know its version using docker/build-push-action 使用 github-action 构建镜像并推送到 docker hub - Build image and push to docker hub using github-action 无法使用 GitHub 操作构建 Docker 映像 - Unable to Build Docker Image Using GitHub Actions Docker 构建推送操作“不是有效的 object 名称”; 输出 repo 的所有分支和标签 - Docker build-push-action "Not a valid object name"; outputs all branches and tags for repo Github 操作:推送 gradle 任务构建的 docker 映像 - Github Actions: Push docker image build by gradle task 使用 GitHub Actions 构建 Docker 镜像:没有这样的文件或目录 - Build Docker image using GitHub Actions: No such file or directory GitHub 操作 - 使用 docker/build-push-action@v2 指定多个标签 - GitHub Actions - Specify Multiple Tags with docker/build-push-action@v2
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM