Add support for 'platform' parameter

Signed-off-by: James Addison <jay@jp-hosting.net>
This commit is contained in:
James Addison 2021-10-14 13:44:43 +01:00
parent 979e6a6c6e
commit dc51083ce0
9 changed files with 119 additions and 21 deletions

View file

@ -11,8 +11,8 @@ env:
IMAGE_TAG: latest IMAGE_TAG: latest
jobs: jobs:
build: build-multiarch:
name: Build image using Buildah name: Build multi-architecture image using Buildah
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
fail-fast: false fail-fast: false
@ -51,7 +51,7 @@ jobs:
EOF EOF
- name: Build Image - name: Build Image
id: build_image id: build_image_multiarch
uses: ./buildah-build/ uses: ./buildah-build/
with: with:
image: ${{ env.IMAGE_NAME }} image: ${{ env.IMAGE_NAME }}
@ -63,9 +63,9 @@ jobs:
- name: Echo Outputs - name: Echo Outputs
run: | run: |
echo "Image: ${{ steps.build_image.outputs.image }}" echo "Image: ${{ steps.build_image_multiarch.outputs.image }}"
echo "Tags: ${{ steps.build_image.outputs.tags }}" echo "Tags: ${{ steps.build_image_multiarch.outputs.tags }}"
echo "Tagged Image: ${{ steps.build_image.outputs.image-with-tag }}" echo "Tagged Image: ${{ steps.build_image_multiarch.outputs.image-with-tag }}"
- name: Check images created - name: Check images created
run: buildah images | grep '${{ env.IMAGE_NAME }}' run: buildah images | grep '${{ env.IMAGE_NAME }}'
@ -73,9 +73,76 @@ jobs:
- name: Check image metadata - name: Check image metadata
run: | run: |
set -x set -x
buildah inspect ${{ steps.build_image.outputs.image }}:${{ env.IMAGE_TAG }} | jq ".OCIv1.architecture" buildah inspect ${{ steps.build_image_multiarch.outputs.image }}:${{ env.IMAGE_TAG }} | jq ".OCIv1.architecture"
buildah inspect ${{ steps.build_image.outputs.image }}:${{ env.IMAGE_TAG }} | jq ".Docker.architecture" buildah inspect ${{ steps.build_image_multiarch.outputs.image }}:${{ env.IMAGE_TAG }} | jq ".Docker.architecture"
- name: Run image - name: Run image
run: | run: |
podman run --rm ${{ steps.build_image.outputs.image }}:${{ env.IMAGE_TAG }} podman run --rm ${{ steps.build_image_multiarch.outputs.image }}:${{ env.IMAGE_TAG }}
build-multiplatform:
name: Build multi-platform image using Buildah
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
platform: [ "linux/amd64", "linux/arm64/v8" ]
install_latest: [ true, false ]
steps:
# Checkout buildah action github repository
- name: Checkout Buildah action
uses: actions/checkout@v2
with:
path: "buildah-build"
- name: Install latest buildah
if: matrix.install_latest
run: |
bash buildah-build/.github/install_latest_buildah.sh
- name: Install qemu dependency
run: |
sudo apt-get update
sudo apt-get install -y qemu-user-static
- name: Create Containerfile
run: |
cat > Containerfile<<EOF
FROM docker.io/alpine:3.14
RUN echo "hello world"
ENTRYPOINT [ "sh", "-c", "echo -n 'Machine: ' && uname -m && echo -n 'Bits: ' && getconf LONG_BIT && echo 'goodbye world'" ]
EOF
- name: Build Image
id: build_image_multiplatform
uses: ./buildah-build/
with:
image: ${{ env.IMAGE_NAME }}
tags: ${{ env.IMAGE_TAG }}
platform: ${{ matrix.platform }}
containerfiles: |
./Containerfile
- name: Echo Outputs
run: |
echo "Image: ${{ steps.build_image_multiplatform.outputs.image }}"
echo "Tags: ${{ steps.build_image_multiplatform.outputs.tags }}"
echo "Tagged Image: ${{ steps.build_image_multiplatform.outputs.image-with-tag }}"
- name: Check images created
run: buildah images | grep '${{ env.IMAGE_NAME }}'
- name: Check image metadata
run: |
set -x
buildah inspect ${{ steps.build_image_multiplatform.outputs.image }}:${{ env.IMAGE_TAG }} | jq ".OCIv1.architecture"
buildah inspect ${{ steps.build_image_multiplatform.outputs.image }}:${{ env.IMAGE_TAG }} | jq ".Docker.architecture"
- name: Run image
run: |
podman run --rm ${{ steps.build_image_multiplatform.outputs.image }}:${{ env.IMAGE_TAG }}

View file

@ -26,6 +26,7 @@ After building your image, use [push-to-registry](https://github.com/redhat-acti
| Input Name | Description | Default | | Input Name | Description | Default |
| ---------- | ----------- | ------- | | ---------- | ----------- | ------- |
| arch | Label the image with this architecture, instead of defaulting to the host architecture. Refer to [Multi arch builds](#multi-arch-builds) for more information. | None (host architecture) | arch | Label the image with this architecture, instead of defaulting to the host architecture. Refer to [Multi arch builds](#multi-arch-builds) for more information. | None (host architecture)
| platform | Label the image with this platform, instead of defaulting to the host platform. Refer to [Multi arch builds](#multi-arch-builds) for more information. | None (host platform)
| build-args | Build arguments to pass to the Docker build using `--build-arg`, if using a Containerfile that requires ARGs. Use the form `arg_name=arg_value`, and separate arguments with newlines. | None | build-args | Build arguments to pass to the Docker build using `--build-arg`, if using a Containerfile that requires ARGs. Use the form `arg_name=arg_value`, and separate arguments with newlines. | None
| context | Path to directory to use as the build context. | `.` | context | Path to directory to use as the build context. | `.`
| containerfiles\* | The list of Containerfile paths to perform a build using docker instructions. This is a multiline input to allow multiple Containerfiles. | **Must be provided** | containerfiles\* | The list of Containerfile paths to perform a build using docker instructions. This is a multiline input to allow multiple Containerfiles. | **Must be provided**
@ -43,6 +44,7 @@ After building your image, use [push-to-registry](https://github.com/redhat-acti
| Input Name | Description | Default | | Input Name | Description | Default |
| ---------- | ----------- | ------- | | ---------- | ----------- | ------- |
| arch | Label the image with this architecture, instead of defaulting to the host architecture. Refer to [Multi arch builds](#multi-arch-builds) for more information. | None (host architecture) | arch | Label the image with this architecture, instead of defaulting to the host architecture. Refer to [Multi arch builds](#multi-arch-builds) for more information. | None (host architecture)
| platform | Label the image with this platform, instead of defaulting to the host platform. Refer to [Multi arch builds](#multi-arch-builds) for more information. | None (host platform)
| base-image | The base image to use for the container. | **Must be provided** | base-image | The base image to use for the container. | **Must be provided**
| content | Paths to files or directories to copy inside the container to create the file image. This is a multiline input to allow you to copy multiple files/directories.| None | content | Paths to files or directories to copy inside the container to create the file image. This is a multiline input to allow you to copy multiple files/directories.| None
| entrypoint | The entry point to set for the container. This is a multiline input; split arguments across lines. | None | entrypoint | The entry point to set for the container. This is a multiline input; split arguments across lines. | None
@ -179,8 +181,8 @@ sudo podman run --rm --privileged docker.io/tonistiigi/binfmt --install all
``` ```
This registration remains active until the host reboots. This registration remains active until the host reboots.
### The `arch` input ### The `arch` and `platform` inputs
The `arch` argument overrides the Architecture label in the output image. It does not actually affect the architectures the output image will run on. The image must still be built for the required architecture. The `arch` and `platform` arguments override the Architecture and Platform labels in the output image, respectively. They do not actually affect the architectures and platforms the output image will run on. The image must still be built for the required architecture or platform.
There is a simple example [in this issue](https://github.com/redhat-actions/buildah-build/issues/60#issuecomment-876552452). There is a simple example [in this issue](https://github.com/redhat-actions/buildah-build/issues/60#issuecomment-876552452).

View file

@ -56,6 +56,9 @@ inputs:
archs: archs:
description: 'Alias for "arch". "arch" takes precedence if both are set.' description: 'Alias for "arch". "arch" takes precedence if both are set.'
required: false required: false
platform:
description: 'Label the image with this PLATFORM, instead of defaulting to the host platform.'
required: false
extra-args: extra-args:
description: | description: |
Extra args to be passed to buildah bud. Extra args to be passed to buildah bud.

2
dist/index.js vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View file

@ -15,12 +15,13 @@ export interface BuildahConfigSettings {
port?: string; port?: string;
workingdir?: string; workingdir?: string;
arch?: string; arch?: string;
platform?: string;
} }
interface Buildah { interface Buildah {
buildUsingDocker( buildUsingDocker(
image: string, context: string, containerFiles: string[], buildArgs: string[], image: string, context: string, containerFiles: string[], buildArgs: string[],
useOCI: boolean, arch: string, layers: string, extraArgs: string[] useOCI: boolean, arch: string, platform: string, layers: string, extraArgs: string[]
): Promise<CommandResult>; ): Promise<CommandResult>;
from(baseImage: string): Promise<CommandResult>; from(baseImage: string): Promise<CommandResult>;
config(container: string, setting: BuildahConfigSettings): Promise<CommandResult>; config(container: string, setting: BuildahConfigSettings): Promise<CommandResult>;
@ -63,13 +64,17 @@ export class BuildahCli implements Buildah {
async buildUsingDocker( async buildUsingDocker(
image: string, context: string, containerFiles: string[], buildArgs: string[], image: string, context: string, containerFiles: string[], buildArgs: string[],
useOCI: boolean, arch: string, layers: string, extraArgs: string[] useOCI: boolean, arch: string, platform: string, layers: string, extraArgs: string[]
): Promise<CommandResult> { ): Promise<CommandResult> {
const args: string[] = [ "bud" ]; const args: string[] = [ "bud" ];
if (arch) { if (arch) {
args.push("--arch"); args.push("--arch");
args.push(arch); args.push(arch);
} }
if (platform) {
args.push("--platform");
args.push(platform);
}
containerFiles.forEach((file) => { containerFiles.forEach((file) => {
args.push("-f"); args.push("-f");
args.push(file); args.push(file);
@ -135,6 +140,10 @@ export class BuildahCli implements Buildah {
args.push("--arch"); args.push("--arch");
args.push(settings.arch); args.push(settings.arch);
} }
if (settings.platform) {
args.push("--platform");
args.push(settings.platform);
}
if (settings.workingdir) { if (settings.workingdir) {
args.push("--workingdir"); args.push("--workingdir");
args.push(settings.workingdir); args.push(settings.workingdir);

View file

@ -85,6 +85,12 @@ export enum Inputs {
* Default: "false" * Default: "false"
*/ */
OCI = "oci", OCI = "oci",
/**
* Label the image with this PLATFORM, instead of defaulting to the host platform.
* Required: false
* Default: None.
*/
PLATFORM = "platform",
/** /**
* The port to expose when running containers based on image * The port to expose when running containers based on image
* Required: false * Required: false

View file

@ -9,7 +9,7 @@ import * as path from "path";
import { Inputs, Outputs } from "./generated/inputs-outputs"; import { Inputs, Outputs } from "./generated/inputs-outputs";
import { BuildahCli, BuildahConfigSettings } from "./buildah"; import { BuildahCli, BuildahConfigSettings } from "./buildah";
import { import {
getArch, getContainerfiles, getInputList, splitByNewline, getArch, getPlatform, getContainerfiles, getInputList, splitByNewline,
isFullImageName, getFullImageName, isFullImageName, getFullImageName,
} from "./utils"; } from "./utils";
@ -54,12 +54,17 @@ export async function run(): Promise<void> {
const useOCI = core.getInput(Inputs.OCI) === "true"; const useOCI = core.getInput(Inputs.OCI) === "true";
const arch = getArch(); const arch = getArch();
const platform = getPlatform();
if (arch && platform) {
throw new Error("The --platform option may not be used in combination with the --arch option.");
}
if (containerFiles.length !== 0) { if (containerFiles.length !== 0) {
await doBuildUsingContainerFiles(cli, newImage, workspace, containerFiles, useOCI, arch); await doBuildUsingContainerFiles(cli, newImage, workspace, containerFiles, useOCI, arch, platform);
} }
else { else {
await doBuildFromScratch(cli, newImage, useOCI, arch); await doBuildFromScratch(cli, newImage, useOCI, arch, platform);
} }
if (tagsList.length > 1) { if (tagsList.length > 1) {
@ -71,7 +76,8 @@ export async function run(): Promise<void> {
} }
async function doBuildUsingContainerFiles( async function doBuildUsingContainerFiles(
cli: BuildahCli, newImage: string, workspace: string, containerFiles: string[], useOCI: boolean, arch: string cli: BuildahCli, newImage: string, workspace: string, containerFiles: string[], useOCI: boolean, arch: string,
platform: string
): Promise<void> { ): Promise<void> {
if (containerFiles.length === 1) { if (containerFiles.length === 1) {
core.info(`Performing build from Containerfile`); core.info(`Performing build from Containerfile`);
@ -94,12 +100,12 @@ async function doBuildUsingContainerFiles(
buildahBudExtraArgs = lines.flatMap((line) => line.split(" ")).map((arg) => arg.trim()); buildahBudExtraArgs = lines.flatMap((line) => line.split(" ")).map((arg) => arg.trim());
} }
await cli.buildUsingDocker( await cli.buildUsingDocker(
newImage, context, containerFileAbsPaths, buildArgs, useOCI, arch, layers, buildahBudExtraArgs newImage, context, containerFileAbsPaths, buildArgs, useOCI, arch, platform, layers, buildahBudExtraArgs
); );
} }
async function doBuildFromScratch( async function doBuildFromScratch(
cli: BuildahCli, newImage: string, useOCI: boolean, arch: string cli: BuildahCli, newImage: string, useOCI: boolean, arch: string, platform: string
): Promise<void> { ): Promise<void> {
core.info(`Performing build from scratch`); core.info(`Performing build from scratch`);
@ -119,6 +125,7 @@ async function doBuildFromScratch(
workingdir: workingDir, workingdir: workingDir,
envs, envs,
arch, arch,
platform,
}; };
await cli.config(containerId, newImageConfig); await cli.config(containerId, newImageConfig);
await cli.copy(containerId, content); await cli.copy(containerId, content);

View file

@ -81,6 +81,10 @@ export function getArch(): string {
return arch || archs; return arch || archs;
} }
export function getPlatform(): string {
return core.getInput(Inputs.PLATFORM);
}
export function getContainerfiles(): string[] { export function getContainerfiles(): string[] {
// 'containerfile' should be used over 'dockerfile', // 'containerfile' should be used over 'dockerfile',
// see https://github.com/redhat-actions/buildah-build/issues/57 // see https://github.com/redhat-actions/buildah-build/issues/57