[英]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.