Skip to content

Commit a87b2db

Browse files
committed
feat: Add Podman support
# Conflicts: # releases/capi/cloud-controller.Dockerfile
1 parent c114258 commit a87b2db

11 files changed

Lines changed: 363 additions & 14 deletions

File tree

Makefile

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,28 @@ TARGET_ARCH ?= $(if $(filter true,$(LOCAL)),$(shell go env GOARCH),amd64)
33
# renovate: dataSource=github-releases depName=helmfile/helmfile
44
HELMFILE_VERSION ?= "1.5.0"
55

6+
# Build all images for the local architecture (arm64 on Apple Silicon, amd64 elsewhere).
7+
# This ensures Go binaries like storage-cli are native – not run under Rosetta,
8+
# which causes 'taggedPointerPack' panics with high memory addresses.
9+
build:
10+
@ . ./scripts/detect-runtime.sh; \
11+
if [ "$$CONTAINER_RUNTIME" = "podman" ]; then \
12+
echo "Building with Podman is not yet supported via docker-bake.hcl."; \
13+
echo "Use 'podman build' manually with the Dockerfiles in releases/."; \
14+
exit 1; \
15+
fi; \
16+
docker buildx bake --file docker-bake.hcl --set "*.platform=linux/$(TARGET_ARCH)" $(BAKE_TARGETS)
17+
618
init: temp/certs/ca.key temp/certs/ca.crt temp/certs/ssh_key temp/certs/ssh_key.pub temp/secrets.sh temp/secrets.env
719

820
temp/certs/ca.key temp/certs/ca.crt temp/certs/ssh_key temp/certs/ssh_key.pub temp/secrets.sh temp/secrets.env:
921
@ ./scripts/init.sh
1022

1123
install:
1224
kind get kubeconfig --name cfk8s > temp/kubeconfig
13-
docker run --rm --net=host --env-file temp/secrets.env \
25+
@ . ./scripts/detect-runtime.sh; \
26+
if [ "$$IS_PODMAN" = "true" ]; then ./scripts/setup-podman-vm.sh; fi; \
27+
$$CONTAINER_RUNTIME run --rm --net=host --env-file temp/secrets.env \
1428
--env INSTALL_OPTIONAL_COMPONENTS \
1529
-v "$$PWD/temp/certs:/certs" -v "$$PWD/temp/kubeconfig:/helm/.kube/config:ro" -v "$$PWD:/wd" --workdir /wd ghcr.io/helmfile/helmfile:v$(HELMFILE_VERSION) helmfile sync
1630

@@ -33,7 +47,7 @@ create-org:
3347
bootstrap: create-org
3448
@ ./scripts/upload_buildpacks.sh
3549

36-
bootstrap-complete: create-org
50+
bootstrap-complete: create-org
3751
@ ALL_BUILDPACKS=true ./scripts/upload_buildpacks.sh
3852

3953
up: create-kind init install

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ This repository provides a simple and fast way to run Cloud Foundry locally. It
66

77
The following tools need to be installed:
88

9-
- [`docker`](https://docs.docker.com/engine/install/)
9+
- [`docker`](https://docs.docker.com/engine/install/) or [podman](https://podman.io/docs/installation)
10+
- [`docker-compose`](https://docs.docker.com/compose/install) or [podman-compose](https://github.com/containers/podman-compose)
1011
- [`kind`](https://kind.sigs.k8s.io/docs/user/quick-start/#installing-from-release-binaries) (v0.31.0 or higher)
1112
- [`kubectl`](https://kubernetes.io/docs/tasks/tools/#kubectl) (v1.35.1 or higher)
1213
- `make`:
1314
- It should be already installed on MacOS and Linux.
1415
- For Windows installation see: <https://gnuwin32.sourceforge.net/packages/make.htm>
1516

17+
> [!IMPORTANT]
18+
> Please ensure that your Podman setup is configured as an alias for Docker, as this project relies on Docker commands. You can achieve this by executing `sudo ln -s /opt/podman/bin/podman /usr/local/bin/docker` and `sudo ln -s /opt/homebrew/bin/podman-compose /usr/local/bin/docker-compose` on Mac OS X.
19+
1620
## Run the Installation
1721

1822
```bash

helmfile.yaml.gotmpl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
helmDefaults:
33
wait: true
4-
timeout: 600
4+
timeout: 1200
55
recreatePods: false
66
force: false
77
createNamespace: true
@@ -381,6 +381,7 @@ releases:
381381
- name: capi
382382
namespace: {{ .Values.systemNamespace }}
383383
chart: ./releases/capi/helm
384+
timeout: 1200
384385
needs:
385386
- minio
386387
- diego
@@ -408,6 +409,7 @@ releases:
408409
namespace: {{ .Values.systemNamespace }}
409410
chart: ./releases/nfs-volume/helm
410411
installed: {{ .Values.installOptionalComponents }}
412+
timeout: 900
411413
needs:
412414
- capi
413415
values:

releases/capi/helm/templates/cloud_controller_ng.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,29 @@ spec:
6868
annotations:
6969
checksum/config: {{ cat (include (print $.Template.BasePath "/cloud-controller-config.yaml") .) (include (print $.Template.BasePath "/cloud-controller-route-registrar-config.yaml") .) (include (print $.Template.BasePath "/nginx-config.yaml") .) | sha256sum }}
7070
spec:
71+
# Fix for arm64 / Apple Silicon: download native storage-cli binary.
72+
# The image contains amd64 storage-cli which causes 'taggedPointerPack'
73+
# panic when run under Rosetta. This init container fetches the arm64
74+
# binary and mounts it into cloud-controller & local-worker containers.
75+
initContainers:
76+
- name: fix-storage-cli-arch
77+
image: alpine:latest
78+
command:
79+
- /bin/sh
80+
- -c
81+
- |
82+
ARCH=$(uname -m)
83+
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
84+
wget -q https://github.com/cloudfoundry/storage-cli/releases/download/v0.0.5/storage-cli-0.0.5-linux-arm64 -O /fix/storage-cli
85+
chmod +x /fix/storage-cli
86+
echo "Downloaded arm64 storage-cli"
87+
else
88+
echo "Not arm64 – skipping storage-cli fix"
89+
touch /fix/storage-cli
90+
fi
91+
volumeMounts:
92+
- name: storage-cli-fix
93+
mountPath: /fix
7194
containers:
7295
- name: cloud-controller
7396
image: {{ .Values.cloudController.image.repository }}:{{ default .Chart.AppVersion .Values.cloudController.image.tag }}
@@ -101,6 +124,11 @@ spec:
101124
mountPath: /var/run
102125
- name: tmpdir
103126
mountPath: /tmp
127+
{{- if .Values.cloudController.blobstore.storage_cli }}
128+
- name: storage-cli-fix
129+
mountPath: /usr/local/bin/storage-cli
130+
subPath: storage-cli
131+
{{- end }}
104132
- name: route-registrar
105133
image: {{ .Values.routeRegistrar.image.repository }}:{{ .Values.routeRegistrar.image.tag }}
106134
imagePullPolicy: {{ .Values.routeRegistrar.image.imagePullPolicy }}
@@ -155,6 +183,11 @@ spec:
155183
mountPath: /var/run
156184
- name: tmpdir
157185
mountPath: /tmp
186+
{{- if .Values.cloudController.blobstore.storage_cli }}
187+
- name: storage-cli-fix
188+
mountPath: /usr/local/bin/storage-cli
189+
subPath: storage-cli
190+
{{- end }}
158191
- name: nginx
159192
image: {{ .Values.nginx.image.repository }}:{{ default .Chart.AppVersion .Values.nginx.image.tag }}
160193
imagePullPolicy: {{ .Values.nginx.image.imagePullPolicy }}
@@ -254,4 +287,6 @@ spec:
254287
emptyDir: {}
255288
- name: tmpdir
256289
emptyDir: {}
290+
- name: storage-cli-fix
291+
emptyDir: {}
257292
{{- end }}

releases/nfs-volume/helm/templates/nfsv3driver.yaml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,43 @@ spec:
1414
labels:
1515
app: nfsv3driver
1616
spec:
17+
initContainers:
18+
- name: init-rpcbind-dir
19+
image: {{ .Values.nfsv3driver.image.repository }}:{{ default .Chart.AppVersion .Values.nfsv3driver.image.tag }}
20+
imagePullPolicy: {{ .Values.nfsv3driver.image.imagePullPolicy }}
21+
command:
22+
- /bin/bash
23+
- -ec
24+
- |
25+
mkdir -p /run/rpcbind
26+
# rpcbind init script checks 'stat -c "%U"' == "root" (by name).
27+
chown root:root /run/rpcbind
28+
chmod 0755 /run/rpcbind
29+
securityContext:
30+
runAsUser: 0
31+
runAsGroup: 0
32+
volumeMounts:
33+
- name: rpcbind-run
34+
mountPath: /run/rpcbind
1735
containers:
1836
- name: nfsv3driver
1937
image: {{ .Values.nfsv3driver.image.repository }}:{{ default .Chart.AppVersion .Values.nfsv3driver.image.tag }}
2038
imagePullPolicy: {{ .Values.nfsv3driver.image.imagePullPolicy }}
39+
# nfsv3driver.sh (v7.53.0+) calls 'service rpcbind start' which fails
40+
# in containers because the Ubuntu init script requires /run/rpcbind
41+
# to be owned by root *before* it is created by the service wrapper.
42+
# We bypass nfsv3driver.sh entirely: start rpcbind directly with -w
43+
# (warm start / no daemon-ize check) and exec the driver binary.
44+
command:
45+
- /bin/bash
46+
- -c
47+
- |
48+
mkdir -p /run/rpcbind
49+
chown root:root /run/rpcbind
50+
chmod 0755 /run/rpcbind
51+
/sbin/rpcbind -w
52+
exec /usr/local/bin/nfsv3driver "$@"
53+
- --
2154
env:
2255
- name: POD_IP
2356
valueFrom:
@@ -46,8 +79,12 @@ spec:
4679
- name: nfs-mounts
4780
mountPath: /var/lib/rep/volumes/nfs
4881
mountPropagation: Bidirectional
82+
- name: rpcbind-run
83+
mountPath: /run/rpcbind
4984
securityContext:
5085
privileged: true
86+
runAsUser: 0
87+
runAsGroup: 0
5188
{{- if .Values.nfsv3driver.nodeSelector }}
5289
nodeSelector:
5390
{{- toYaml .Values.nfsv3driver.nodeSelector | nindent 8 }}
@@ -63,4 +100,6 @@ spec:
63100
- name: nfs-mounts
64101
hostPath:
65102
path: /var/lib/rep/volumes/nfs
103+
- name: rpcbind-run
104+
emptyDir: {}
66105
{{- end }}

releases/nfs-volume/helm/values.schema.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@
4141
"resources": {
4242
"type": ["object", "null"]
4343
},
44+
"rpcbindStartMode": {
45+
"default": "auto",
46+
"enum": [
47+
"auto",
48+
"direct",
49+
"service"
50+
],
51+
"type": "string"
52+
},
4453
"tolerations": {
4554
"type": ["array", "null"],
4655
"items": {
@@ -99,6 +108,15 @@
99108
"resources": {
100109
"type": ["object", "null"]
101110
},
111+
"rpcbindStartMode": {
112+
"default": "auto",
113+
"enum": [
114+
"auto",
115+
"direct",
116+
"service"
117+
],
118+
"type": "string"
119+
},
102120
"tolerations": {
103121
"type": ["array", "null"],
104122
"items": {

scripts/create-kind.sh

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
set -e
44

5+
# Auto-detect Docker or Podman
6+
source "$(dirname "$0")/detect-runtime.sh"
7+
58
configure_registry_mirror() {
69
local cache_name=$1
710
local remote_url=$2
@@ -11,10 +14,10 @@ configure_registry_mirror() {
1114
echo "Configuring cache ${cache_name} on all nodes..."
1215
for node in $(kind get nodes --name cfk8s); do
1316
# Create containerd registry config directories
14-
docker exec "$node" mkdir -p /etc/containerd/certs.d/${registry_uri}
17+
${CONTAINER_RUNTIME} exec "$node" mkdir -p /etc/containerd/certs.d/${registry_uri}
1518

1619
# Configure registry to use cache as mirror (expand variables!)
17-
cat <<EOF | docker exec -i "$node" sh -c "cat > /etc/containerd/certs.d/${registry_uri}/hosts.toml"
20+
cat <<EOF | ${CONTAINER_RUNTIME} exec -i "$node" sh -c "cat > /etc/containerd/certs.d/${registry_uri}/hosts.toml"
1821
server = "${remote_url}"
1922
2023
[host."http://${cache_name}:5000"]
@@ -24,22 +27,37 @@ EOF
2427
done
2528
}
2629

30+
evaluate_progress_option() {
31+
# Podman compose does not support --progress
32+
if [ "${IS_PODMAN}" = "true" ]; then
33+
echo ""
34+
else
35+
echo "--progress plain"
36+
fi
37+
}
38+
2739
setup_registry_caches() {
28-
echo "Starting registry pull-through caches with docker-compose..."
29-
docker compose -p cache -f "${script_full_path}/docker-compose-registries.yaml" --progress plain up -d
40+
echo "Starting registry pull-through caches with ${COMPOSE_CMD}..."
41+
${COMPOSE_CMD} -p cache -f "${script_full_path}/docker-compose-registries.yaml" $(evaluate_progress_option) up -d
3042

3143
configure_registry_mirror "docker-io" "https://registry-1.docker.io" "docker.io"
3244
configure_registry_mirror "ghcr-io" "https://ghcr.io" "ghcr.io"
3345
configure_registry_mirror "quay-io" "https://quay.io" "quay.io"
3446
}
3547

3648
setup_nfs() {
37-
echo "Starting NFS server with docker-compose..."
38-
docker compose -p nfs -f "${script_full_path}/docker-compose-nfs.yaml" --progress plain up -d
49+
echo "Starting NFS server with ${COMPOSE_CMD}..."
50+
${COMPOSE_CMD} -p nfs -f "${script_full_path}/docker-compose-nfs.yaml" $(evaluate_progress_option) up -d
3951
}
4052

4153
script_full_path=$(dirname "$0")
4254

55+
# When running under Podman, ensure the Podman VM is ready (NFS modules, inotify, …)
56+
if [ "${IS_PODMAN}" = "true" ]; then
57+
echo "Podman detected – ensuring Podman VM is configured..."
58+
"${script_full_path}/setup-podman-vm.sh"
59+
fi
60+
4361
if kind get clusters | grep -q "cfk8s"; then
4462
echo "Kind cluster 'cfk8s' already exists."
4563
exit 0

scripts/delete-kind.sh

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@ script_full_path=$(dirname "$0")
66

77
kind delete cluster --name cfk8s
88

9+
# Detect container runtime behind docker (Docker vs Podman)
10+
if echo $(docker version) | grep -qi 'Podman'; then
11+
container_runtime_spects=""
12+
else
13+
container_runtime_spects="--progress plain"
14+
fi
15+
916
# Remove registry cache containers using docker-compose
1017
echo "Deleting registry cache containers..."
11-
docker compose -p cache -f "${script_full_path}/docker-compose-registries.yaml" --progress plain down
12-
docker compose -p nfs -f "${script_full_path}/docker-compose-nfs.yaml" --progress plain down
18+
docker compose -p cache -f "${script_full_path}/docker-compose-registries.yaml" $container_runtime_spects down
19+
docker compose -p nfs -f "${script_full_path}/docker-compose-nfs.yaml" $container_runtime_spects down

scripts/detect-runtime.sh

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env bash
2+
# detect-runtime.sh
3+
# Auto-detects the available container runtime (Docker or Podman).
4+
# Source this file – do NOT execute it directly.
5+
#
6+
# source "$(dirname "$0")/detect-runtime.sh"
7+
#
8+
# Exports:
9+
# CONTAINER_RUNTIME – the CLI command to use ("docker" or "podman")
10+
# COMPOSE_CMD – e.g. "docker compose" or "podman compose"
11+
# IS_PODMAN – "true" or "false"
12+
#
13+
# Detection strategy (in order):
14+
# 1. Honour explicit CONTAINER_RUNTIME env override.
15+
# 2. If 'podman' binary exists → Podman (alias docker=podman counts too)
16+
# 3. If 'docker' binary exists and is NOT Podman → Docker
17+
# 4. Neither found → error.
18+
#
19+
# NOTE: We intentionally do NOT call 'docker info' / 'podman info' here
20+
# because the Podman machine may not be running yet at detection time.
21+
# The machine is started later by setup-podman-vm.sh.
22+
23+
# Allow explicit override
24+
if [ -n "${CONTAINER_RUNTIME:-}" ]; then
25+
IS_PODMAN="false"
26+
[ "${CONTAINER_RUNTIME}" = "podman" ] && IS_PODMAN="true"
27+
else
28+
# Prefer podman binary when it exists
29+
if command -v podman &>/dev/null; then
30+
CONTAINER_RUNTIME="podman"
31+
IS_PODMAN="true"
32+
elif command -v docker &>/dev/null; then
33+
CONTAINER_RUNTIME="docker"
34+
# Check if 'docker' is actually Podman (socket compat or renamed binary)
35+
if docker version 2>/dev/null | grep -qi 'podman'; then
36+
IS_PODMAN="true"
37+
else
38+
IS_PODMAN="false"
39+
fi
40+
else
41+
echo "ERROR: Neither 'podman' nor 'docker' binary found in PATH." >&2
42+
echo " Install Podman Desktop (https://podman-desktop.io) or Docker Desktop." >&2
43+
exit 1
44+
fi
45+
fi
46+
47+
if [ "${IS_PODMAN}" = "true" ]; then
48+
# kind requires this provider hint when using Podman
49+
export KIND_EXPERIMENTAL_PROVIDER=podman
50+
fi
51+
52+
# Compose sub-command
53+
COMPOSE_CMD="${CONTAINER_RUNTIME} compose"
54+
55+
export CONTAINER_RUNTIME IS_PODMAN COMPOSE_CMD

scripts/init.sh

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ set -euo pipefail
44

55
mkdir -p temp/certs
66

7-
OPENSSL="docker run --rm -v $(pwd)/temp/certs:/certs -v $(pwd)/certs/all-in-one.conf:/all-in-one.conf alpine/openssl"
8-
SSH_KEYGEN="docker run --rm -v $(pwd)/temp/certs:/certs --entrypoint /usr/bin/ssh-keygen linuxserver/openssh-server"
7+
# Auto-detect Docker or Podman
8+
source "$(dirname "$0")/detect-runtime.sh"
9+
10+
OPENSSL="${CONTAINER_RUNTIME} run --rm -v $(pwd)/temp/certs:/certs -v $(pwd)/certs/all-in-one.conf:/all-in-one.conf alpine/openssl"
11+
SSH_KEYGEN="${CONTAINER_RUNTIME} run --rm -v $(pwd)/temp/certs:/certs --entrypoint /usr/bin/ssh-keygen linuxserver/openssh-server"
912

1013
$OPENSSL genrsa -traditional -out /certs/ca.key 4096
1114
$OPENSSL req -x509 -key /certs/ca.key -out /certs/ca.crt -days 365 -noenc -subj "/CN=ca/O=ca" \

0 commit comments

Comments
 (0)