Cloud Native 16 min read

Building Containers Without Docker: Using BuildKit, Podman, Kaniko, and img

This article demonstrates several Docker‑free methods for building OCI container images—using Docker’s built‑in BuildKit, the standalone BuildKit daemon, Google’s Kaniko, and the img tool—through a practical OpenFaaS Go middleware example, comparing their features, commands, and limitations.

Top Architect
Top Architect
Top Architect
Building Containers Without Docker: Using BuildKit, Podman, Kaniko, and img

In this article the author presents multiple ways to build container images without relying on Docker, using OpenFaaS as a reference case whose workloads run OCI‑format images. The examples cover Docker CLI with the built‑in BuildKit option, a standalone BuildKit daemon, Google’s Kaniko, and the img tool.

1. Why consider alternatives to Docker? Docker works well on armhf, arm64, and x86_64 platforms, but the Docker CLI bundles many features (Swarm, EE) that are unnecessary for simple image builds.

2. Docker‑free options

Docker now uses containerd and supports BuildKit for efficient cached builds.

Podman + buildah (Red Hat/IBM) provide daemon‑less, root‑less builds.

pouch (Alibaba) is an enterprise‑grade engine built on containerd with optional lightweight VM support.

Standalone BuildKit (originally created by Docker’s Tonis Tiigi) runs as a daemon and offers caching and concurrency.

img (Jess Frazelle) wraps BuildKit; it is daemon‑less but only provides binaries for x86_64 .

k3c combines containerd and BuildKit to recreate a lightweight Docker‑like experience.

The author prefers k3c but finds it cumbersome due to its bundled binaries.

3. Building a test application

The example starts with a simple Go HTTP middleware function for OpenFaaS:

faas-cli template store pull golang-middleware
faas-cli new --lang golang-middleware build-test --prefix=alexellis2

Key flags:

--lang – selects the build template.

build-test – function name.

--prefix – Docker Hub username for pushing the OCI image.

The resulting directory structure is:

./
├── build-test
│   └── handler.go
└── build-test.yml

The handler code (shown below) reads the request body and returns a greeting:

package function
import (
    "fmt"
    "io/ioutil"
    "net/http"
)
func Handle(w http.ResponseWriter, r *http.Request) {
    var input []byte
    if r.Body != nil {
        defer r.Body.Close()
        body, _ := ioutil.ReadAll(r.Body)
        input = body
    }
    w.WriteHeader(http.StatusOK)
    w.Write([]byte(fmt.Sprintf("Hello world, input was: %s", string(input))))
}

4. Building with the default Docker workflow

faas-cli build -f build-test.yml

This pulls three base images:

FROM openfaas/of-watchdog:0.7.3 as watchdog
FROM golang:1.13-alpine3.11 as build
FROM alpine:3.12

5. Using Docker with BuildKit

DOCKER_BUILDKIT=1 faas-cli build -f build-test.yml

BuildKit provides better caching, parallel layer fetching, and dramatically faster subsequent builds.

6. Standalone BuildKit

Install BuildKit on a Linux host and run the daemon:

curl -sSL https://github.com/moby/buildkit/releases/download/v0.6.3/buildkit-v0.6.3.linux-amd64.tar.gz | sudo tar -xz -C /usr/local/bin/ --strip-components=1
sudo buildkitd

Then build using buildctl :

sudo -E buildctl build --frontend dockerfile.v0 \
  --local context=./build/build-test/ \
  --local dockerfile=./build/build-test/ \
  --output type=image,name=docker.io/alexellis2/build-test:latest,push=true

Docker login or a valid ~/.docker/config.json is required before pushing.

7. Building with img

Install the latest img binary for x86_64 :

sudo curl -fSL "https://github.com/genuinetools/img/releases/download/v0.5.7/img-linux-amd64" -o "/usr/local/bin/img" && sudo chmod a+x "/usr/local/bin/img"

Build command (subset of buildctl options):

img build -f ./build/build-test/Dockerfile -t alexellis2/build-test:latest ./build/build-test/

The attempt fails on the author's system with a segmentation fault, referencing known issues on the img GitHub repository.

8. Building with Kaniko

Kaniko runs as a container (or binary) and builds in a sandboxed environment:

docker run -v $PWD/build/build-test:/workspace \
  -v ~/.docker/config.json:/kaniko/config.json \
  -e DOCKER_CONFIG=/kaniko \
  gcr.io/kaniko-project/executor:latest \
  -d alexellis2/build-test:latest

Kaniko supports caching but requires manual management because it runs in a one‑shot mode.

9. Summary of tools

Docker (traditional) – heavyweight, slow, and may cause network bridge conflicts.

Docker + BuildKit – fastest with minimal changes (set DOCKER_BUILDKIT=1 ).

Standalone BuildKit – ideal for CI/CD or environments without Docker; works best on Linux.

Kaniko – sandboxed builds, still requires Docker for image push.

For OpenFaaS users, the author recommends using Docker with BuildKit for a fully automated CI/CD experience, while users of faasd (containerd‑only) should install BuildKit directly.

CI/CDcontaineropenfaasBuildKitDocker Alternativekaniko
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.