Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cmd/imagebuilder/imagebuilder
go/imagebuilder
62 changes: 62 additions & 0 deletions go/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Build stage
FROM docker.io/library/golang:1.23-bookworm AS builder

# Install build dependencies for CGO
RUN apt-get update && apt-get install -y gcc libc6-dev libgpgme-dev libseccomp-dev libsqlite3-dev libbtrfs-dev libdevmapper-dev && rm -rf /var/lib/apt/lists/*

WORKDIR /build

# Copy source code
COPY . ./

# Download dependencies
RUN go mod download

# Build the application with CGO enabled
RUN go build -o image-builder ./cmd/image-builder

# Runtime stage
FROM docker.io/library/almalinux:9.6

RUN dnf clean all && \
dnf update --nogpgcheck -y && \
dnf install -y epel-release

RUN dnf install -y \
bash \
buildah \
squashfs-tools \
fuse-overlayfs

# Create local user for rootless image builds
RUN useradd --uid 1002 builder && \
chown -R builder /home/builder

# Set up capabilities for newuidmap/newgidmap
RUN setcap cap_setuid=ep "$(command -v newuidmap)" && \
setcap cap_setgid=ep "$(command -v newgidmap)" &&\
chmod 0755 "$(command -v newuidmap)" && \
chmod 0755 "$(command -v newgidmap)" && \
rpm --restore shadow-utils && \
echo "builder:2000:50000" > /etc/subuid && \
echo "builder:2000:50000" > /etc/subgid

# Make builder the default user when running container
USER builder
WORKDIR /home/builder

ENV BUILDAH_ISOLATION=chroot

# Configure container storage for builder user
# Using 'vfs' storage driver to work around whiteout file handling issues in nested containers
RUN mkdir -p /home/builder/.config/containers && \
{ \
echo '[storage]'; \
echo 'driver = "vfs"'; \
echo 'graphroot = "/home/builder/.local/share/containers/storage"'; \
} > /home/builder/.config/containers/storage.conf

# Copy binary from builder
COPY --from=builder /build/image-builder /app/image-builder

ENTRYPOINT ["/app/image-builder"]
7 changes: 7 additions & 0 deletions go/Dockerfile.scratch-helper
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM docker.io/library/almalinux:8.8

RUN dnf clean all && \
dnf update --nogpgcheck -y && \
dnf install -y epel-release && \
dnf config-manager -y --set-enabled powertools

17 changes: 17 additions & 0 deletions go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
This version of image-build uses the buildah API directly instead of shelling out to the buildah command line tool. See the [buildah API documentation](https://pkg.go.dev/github.com/containers/buildah) for more details. The idea is that it will give us tighter integration with container APIs and is a cleaner approach than using subprocesses.

Its designed to be a drop-in replacement for the python implementation, so the CLI is very similar, appart from following the Go conventions, such as using a single dash for flags. It operates on the same configuration files as the python version.

It supports:

- scratch parents using a helper container to provide dnf, yum etc. without them having to be installed on the host.
- ansible layers again using a helper container and the chroot connection plugin, again not need to ansible to be installed on the host.
- publishing to S3, registries and local

It currently doesn't support the following flags ( although they could be added if needed):
- -scap-benchmark
- -oval-eval
- -install-scap

Support for `--buildah_extra_args` such as when running command is not implemented, as it probably makes more sense to explictly support the options with
additions to the configation file format, for example supporting mounting volumes when running commands.
72 changes: 72 additions & 0 deletions go/cmd/image-builder/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package main

import (
"log"
"os"

"github.com/OpenCHAMI/image-builder/go/pkg/arguments"
"github.com/OpenCHAMI/image-builder/go/pkg/config"
"github.com/OpenCHAMI/image-builder/go/pkg/layer"
"github.com/containers/buildah"
"github.com/containers/storage/pkg/reexec"
"github.com/containers/storage/pkg/unshare"
)

func needsRootlessSetup(layerType, parent string) bool {
// Only need rootless setup if we're not running as root
if os.Getuid() == 0 {
return false
}

// Need rootless setup for layers that require mounting:
// - ansible layers (need to mount for chroot operations)
// - scratch parent (need to mount to build from scratch)
return layerType == "ansible" || parent == "scratch"
}

func main() {
// Initialize reexec for buildah/containers libraries
if reexec.Init() {
return
}

// Parse command-line arguments first to determine if we need rootless setup
args, err := arguments.ParseCommandLine()
if err != nil {
log.Fatalf("Error parsing arguments: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a bit of a nit pick, but other OpenCHAMI Go repos use github.com/rs/zerolog/log for logging. I'm not exactly sure what are our goals going forward with logging, but I figured I'd at least mention it here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PCS is using github.com/sirupsen/logrus 😄 Happy to adopt anything ...

}

// Load configuration file to check layer type and parent
log.Printf("DEBUG: Loading config file: %s", args.ConfigFile)
cfg, err := config.LoadConfig(args.ConfigFile)
if err != nil {
log.Fatalf("Error loading config: %v", err)
}

// Merge command-line arguments into the loaded config
cfg.MergeCommandLineArgs(args)

// Only initialize rootless setup if needed
if needsRootlessSetup(cfg.LayerType, cfg.Parent) {
log.Printf("DEBUG: Initializing rootless setup for layer_type=%s, parent=%s", cfg.LayerType, cfg.Parent)
// Initialize buildah reexec for rootless operation
if buildah.InitReexec() {
return
}
// Handle user namespace setup for rootless containers
unshare.MaybeReexecUsingUserNamespace(false)
}

// Create layer builder with unified config
layerBuilder, err := layer.NewLayer(cfg)
if err != nil {
log.Fatalf("Error creating layer builder: %v", err)
}

// Build the layer
if err := layerBuilder.BuildLayer(); err != nil {
log.Fatalf("Error building layer: %v", err)
}

log.Printf("Image build completed successfully")
}
160 changes: 160 additions & 0 deletions go/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
module github.com/OpenCHAMI/image-builder/go

go 1.23.3

toolchain go1.23.4

require (
github.com/aws/aws-sdk-go-v2 v1.39.2
github.com/aws/aws-sdk-go-v2/config v1.31.11
github.com/aws/aws-sdk-go-v2/service/s3 v1.88.3
github.com/containers/buildah v1.41.4
github.com/containers/image/v5 v5.36.2
github.com/containers/storage v1.59.1
github.com/opencontainers/runtime-spec v1.2.1
gopkg.in/yaml.v3 v3.0.1
)

require (
dario.cat/mergo v1.0.2 // indirect
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/Microsoft/hcsshim v0.13.0 // indirect
github.com/VividCortex/ewma v1.2.0 // indirect
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
github.com/aead/serpent v0.0.0-20160714141033-fba169763ea6 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.18.15 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.9 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.29.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.38.6 // indirect
github.com/aws/smithy-go v1.23.0 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/containerd/cgroups/v3 v3.0.5 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v1.0.0-rc.1 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.17.0 // indirect
github.com/containerd/typeurl/v2 v2.2.3 // indirect
github.com/containernetworking/cni v1.3.0 // indirect
github.com/containernetworking/plugins v1.7.1 // indirect
github.com/containers/common v0.64.2 // indirect
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
github.com/containers/luksy v0.0.0-20250609192159-bc60f96d4194 // indirect
github.com/containers/ocicrypt v1.2.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/disiqueira/gotree/v3 v3.0.2 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker v28.3.3+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.3 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fsouza/go-dockerclient v1.12.1 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-containerregistry v0.20.3 // indirect
github.com/google/go-intervals v0.0.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jinzhu/copier v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/mattn/go-sqlite3 v1.14.28 // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mistifyio/go-zfs/v3 v3.0.1 // indirect
github.com/moby/buildkit v0.23.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/go-archive v0.1.0 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/capability v0.4.0 // indirect
github.com/moby/sys/mountinfo v0.7.2 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/cgroups v0.0.4 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/opencontainers/runc v1.3.0 // indirect
github.com/opencontainers/runtime-tools v0.9.1-0.20250523060157-0ea5ed0382a2 // indirect
github.com/opencontainers/selinux v1.12.0 // indirect
github.com/openshift/imagebuilder v1.2.16 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/proglottis/gpgme v0.1.4 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/seccomp/libseccomp-golang v0.11.0 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.9.0 // indirect
github.com/sigstore/fulcio v1.6.6 // indirect
github.com/sigstore/protobuf-specs v0.4.1 // indirect
github.com/sigstore/sigstore v1.9.5 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/smallstep/pkcs7 v0.1.1 // indirect
github.com/spf13/cobra v1.9.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect
github.com/sylabs/sif/v2 v2.21.1 // indirect
github.com/tchap/go-patricia/v2 v2.3.3 // indirect
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
github.com/ulikunitz/xz v0.5.15 // indirect
github.com/vbatts/tar-split v0.12.1 // indirect
github.com/vbauerster/mpb/v8 v8.10.2 // indirect
github.com/vishvananda/netlink v1.3.1 // indirect
github.com/vishvananda/netns v0.0.5 // indirect
go.etcd.io/bbolt v1.4.2 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/mod v0.25.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/term v0.33.0 // indirect
golang.org/x/text v0.27.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
google.golang.org/grpc v1.72.2 // indirect
google.golang.org/protobuf v1.36.6 // indirect
sigs.k8s.io/yaml v1.5.0 // indirect
tags.cncf.io/container-device-interface v1.0.1 // indirect
tags.cncf.io/container-device-interface/specs-go v1.0.0 // indirect
)
Loading