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.
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=alexellis2Key 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.ymlThe 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.ymlThis pulls three base images:
FROM openfaas/of-watchdog:0.7.3 as watchdog
FROM golang:1.13-alpine3.11 as build
FROM alpine:3.125. Using Docker with BuildKit
DOCKER_BUILDKIT=1 faas-cli build -f build-test.ymlBuildKit 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 buildkitdThen 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=trueDocker 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:latestKaniko 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.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.