Skip to content

Commit eb77fe2

Browse files
committed
feat: Add Podman support as drop-in replacement for Docker
Signed-off-by: ZPascal <pascal.zimmermann01@sap.com>
1 parent 4ee7edf commit eb77fe2

18 files changed

Lines changed: 957 additions & 137 deletions

.github/workflows/kind-cats.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
--privileged \
3838
--pid host \
3939
-v /lib/modules:/lib/modules:ro \
40-
alpine sh -c "sysctl -w fs.inotify.max_user_instances=512 && modprobe nfs && modprobe nfsd"
40+
alpine sh -c "sysctl -w fs.inotify.max_user_instances=512 && sysctl -w net.ipv4.ip_unprivileged_port_start=80 && modprobe nfs && modprobe nfsd"
4141
- name: Install dependencies
4242
if: steps.check_changes.outputs.skip != 'true'
4343
run: |

.github/workflows/kind-smoke.yaml

Lines changed: 17 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -21,114 +21,23 @@ on:
2121

2222
jobs:
2323
kind-smoke:
24-
runs-on: ubuntu-latest
24+
uses: ./.github/workflows/smoke-run.yaml
2525
permissions:
2626
id-token: write
2727
contents: read
28-
steps:
29-
- uses: actions/checkout@v6
30-
with:
31-
fetch-depth: 0
32-
- name: Check if only ignored paths changed
33-
id: check_changes
34-
run: |
35-
if [ "${{ github.event_name }}" == "pull_request" ]; then
36-
CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.sha }})
37-
RELEVANT_FILES=$(echo "$CHANGED_FILES" | grep -v -E '.*\.Dockerfile|^releases/.*/files/|^\.github/|^docs/|\.md$|^renovate\.json$' || true)
38-
if [ -z "$RELEVANT_FILES" ]; then
39-
echo "Only ignored paths were changed. Skipping workflow."
40-
echo "skip=true" >> $GITHUB_OUTPUT
41-
else
42-
echo "skip=false" >> $GITHUB_OUTPUT
43-
fi
44-
else
45-
echo "skip=false" >> $GITHUB_OUTPUT
46-
fi
47-
- name: Set kernel settings
48-
if: steps.check_changes.outputs.skip != 'true'
49-
run: |
50-
docker run --rm \
51-
--privileged \
52-
--pid host \
53-
alpine sh -c "sysctl -w fs.inotify.max_user_instances=512"
54-
- name: Install dependencies
55-
if: steps.check_changes.outputs.skip != 'true'
56-
run: |
57-
mkdir -p $HOME/.local/bin && echo "$HOME/.local/bin" >> "$GITHUB_PATH"
58-
curl -L https://kind.sigs.k8s.io/dl/v${KIND_VERSION}/kind-linux-amd64 -o $HOME/.local/bin/kind
59-
chmod +x $HOME/.local/bin/kind
60-
curl -L https://github.com/helmfile/helmfile/releases/download/v${HELMFILE_VERSION}/helmfile_${HELMFILE_VERSION}_linux_amd64.tar.gz | tar -zx
61-
mv helmfile $HOME/.local/bin/helmfile
62-
curl -L "https://packages.cloudfoundry.org/stable?release=linux64-binary&version=${CF_CLI_VERSION}&source=github" | tar -zx
63-
mv cf8 $HOME/.local/bin/cf
64-
env:
65-
# renovate: dataSource=github-releases depName=cloudfoundry/cli
66-
CF_CLI_VERSION: "8.18.3"
67-
# renovate: dataSource=github-releases depName=kubernetes-sigs/kind
68-
KIND_VERSION: "0.32.0"
69-
# renovate: dataSource=github-releases depName=helmfile/helmfile
70-
HELMFILE_VERSION: "1.5.3"
71-
- name: Use develop versions of cf-deployment
72-
id: pre_validation
73-
if: steps.check_changes.outputs.skip != 'true' && github.event_name == 'workflow_dispatch' && github.event.inputs.fresh-validation == 'true'
74-
env:
75-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
76-
run: |
77-
pip3 install -r scripts/requirements.txt
78-
python3 scripts/sync-cf-deployment-versions.py --ref develop
79-
- name: Run make up (default)
80-
if: steps.check_changes.outputs.skip != 'true' && github.event_name == 'pull_request'
81-
run: make up
82-
- name: Run make up
83-
if: steps.check_changes.outputs.skip != 'true' && github.event_name != 'pull_request'
84-
run: make up
85-
env:
86-
INSTALL_OPTIONAL_COMPONENTS: ${{ inputs.minimal }}
87-
- name: Login
88-
if: steps.check_changes.outputs.skip != 'true'
89-
run: make login
90-
- name: Init
91-
if: steps.check_changes.outputs.skip != 'true'
92-
run: make bootstrap-complete
93-
- name: setup CF tests
94-
if: steps.check_changes.outputs.skip != 'true'
95-
uses: ./.github/actions/setup-cf-tests
96-
with:
97-
test-repo: cf-smoke-tests
98-
test-branch: main
99-
config-template: ./.github/smoke-config.tpl
100-
config-output: ./.github/smoke-config.json
101-
- name: run smoke test
102-
if: steps.check_changes.outputs.skip != 'true'
103-
env:
104-
CONFIG: "${{ github.workspace }}/.github/smoke-config.json"
105-
GINKGO_NO_COLOR: "true"
106-
run: |
107-
./cf-smoke-tests/bin/test --no-color --github-output --timeout=30m --procs=4 --json-report report.json
108-
- name: debug events
109-
if: failure()
110-
run: kubectl get events -A --sort-by='.lastTimestamp'
111-
- name: debug pods
112-
if: failure()
113-
run: |
114-
echo "===== CLOUD_CONTROLLER ====="
115-
kubectl get pod -n cf-system -l app.kubernetes.io/name=cloud-controller -o wide
116-
kubectl get pod -n cf-system -l app.kubernetes.io/name=cloud-controller -o jsonpath='{.status.containerStatuses[*].state}' | jq
117-
kubectl logs -n cf-system -l app.kubernetes.io/name=cloud-controller --all-containers=true
118-
echo "===== CC_WORKER ====="
119-
kubectl get pod -n cf-system -l app.kubernetes.io/name=cc-worker -o wide
120-
kubectl logs -n cf-system -l app.kubernetes.io/name=cc-worker
121-
echo "===== CC_UPLOADER ====="
122-
kubectl get pod -n cf-system -l app=cc-uploader -o wide
123-
kubectl logs -n cf-system -l app=cc-uploader
124-
echo "===== CC_DEPLOYMENT_UPDATER ====="
125-
kubectl get pod -n cf-system -l app.kubernetes.io/name=cc-deployment-updater -o wide
126-
kubectl logs -n cf-system -l app.kubernetes.io/name=cc-deployment-updater
127-
echo "===== CC_WORKER_CLOCK ====="
128-
kubectl get pod -n cf-system -l app.kubernetes.io/name=cc-worker-clock -o wide
129-
kubectl logs -n cf-system -l app.kubernetes.io/name=cc-worker-clock
130-
- uses: actions/upload-artifact@v7
131-
if: always()
132-
with:
133-
name: report.json
134-
path: ./cf-smoke-tests/report.json
28+
with:
29+
container-runtime: docker
30+
install-optional-components: ${{ github.event_name == 'pull_request' && 'false' || inputs.minimal != true && 'true' || 'false' }}
31+
fresh-validation: ${{ inputs.fresh-validation == true }}
32+
artifact-name: report.json
33+
34+
kind-smoke-podman:
35+
uses: ./.github/workflows/smoke-run.yaml
36+
permissions:
37+
id-token: write
38+
contents: read
39+
with:
40+
container-runtime: podman
41+
install-optional-components: ${{ github.event_name == 'pull_request' && 'false' || inputs.minimal != true && 'true' || 'false' }}
42+
fresh-validation: ${{ inputs.fresh-validation == true }}
43+
artifact-name: report-podman.json

.github/workflows/smoke-run.yaml

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
name: Smoke Run (reusable)
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
container-runtime:
7+
description: 'Container runtime to use (docker or podman)'
8+
type: string
9+
required: true
10+
install-optional-components:
11+
description: 'Whether to install optional CF components'
12+
type: string
13+
required: true
14+
artifact-name:
15+
description: 'Name of the uploaded test report artifact'
16+
type: string
17+
required: true
18+
fresh-validation:
19+
description: 'Use versions of cf-deployment from the develop branch'
20+
type: boolean
21+
required: false
22+
default: false
23+
24+
jobs:
25+
smoke-run:
26+
runs-on: ubuntu-latest
27+
permissions:
28+
id-token: write
29+
contents: read
30+
steps:
31+
- uses: actions/checkout@v6
32+
with:
33+
fetch-depth: 0
34+
- name: Check if only ignored paths changed
35+
id: check_changes
36+
run: |
37+
if [ "${{ github.event_name }}" == "pull_request" ]; then
38+
CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.sha }})
39+
RELEVANT_FILES=$(echo "$CHANGED_FILES" | grep -v -E '.*\.Dockerfile|^releases/.*/files/|^\.github/|^docs/|\.md$|^renovate\.json$' || true)
40+
if [ -z "$RELEVANT_FILES" ]; then
41+
echo "Only ignored paths were changed. Skipping workflow."
42+
echo "skip=true" >> $GITHUB_OUTPUT
43+
else
44+
echo "skip=false" >> $GITHUB_OUTPUT
45+
fi
46+
else
47+
echo "skip=false" >> $GITHUB_OUTPUT
48+
fi
49+
- name: Pin nip.io domains to localhost
50+
if: steps.check_changes.outputs.skip != 'true'
51+
run: |
52+
# nip.io is an external DNS service; CI runners sometimes can't resolve it.
53+
printf '127.0.0.1 api.127-0-0-1.nip.io\n127.0.0.1 uaa.127-0-0-1.nip.io\n127.0.0.1 login.127-0-0-1.nip.io\n127.0.0.1 apps.127-0-0-1.nip.io\n127.0.0.1 doppler.127-0-0-1.nip.io\n127.0.0.1 log-stream.127-0-0-1.nip.io\n' | sudo tee -a /etc/hosts
54+
- name: Set kernel settings
55+
if: steps.check_changes.outputs.skip != 'true'
56+
run: |
57+
sudo sysctl -w fs.inotify.max_user_instances=512
58+
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
59+
- name: Set kernel settings (Podman extras)
60+
if: steps.check_changes.outputs.skip != 'true' && inputs.container-runtime == 'podman'
61+
run: |
62+
# Mount BPF filesystem on the host (needed by kindnet on some kernels)
63+
sudo mount bpffs /sys/fs/bpf -t bpf -o nosuid,nodev,noexec,relatime || true
64+
- name: Install podman-compose
65+
if: steps.check_changes.outputs.skip != 'true' && inputs.container-runtime == 'podman'
66+
run: |
67+
sudo apt-get update -qq
68+
sudo apt-get install -y podman-compose
69+
# Ensure podman-compose is used instead of the docker-compose plugin shim
70+
sudo ln -sf /usr/bin/podman-compose /usr/local/bin/podman-compose
71+
- name: Install dependencies
72+
if: steps.check_changes.outputs.skip != 'true'
73+
run: |
74+
mkdir -p $HOME/.local/bin && echo "$HOME/.local/bin" >> "$GITHUB_PATH"
75+
curl -L https://kind.sigs.k8s.io/dl/v${KIND_VERSION}/kind-linux-amd64 -o $HOME/.local/bin/kind
76+
chmod +x $HOME/.local/bin/kind
77+
curl -L https://github.com/helmfile/helmfile/releases/download/v${HELMFILE_VERSION}/helmfile_${HELMFILE_VERSION}_linux_amd64.tar.gz | tar -zx
78+
mv helmfile $HOME/.local/bin/helmfile
79+
curl -L "https://packages.cloudfoundry.org/stable?release=linux64-binary&version=${CF_CLI_VERSION}&source=github" | tar -zx
80+
mv cf8 $HOME/.local/bin/cf
81+
env:
82+
# renovate: dataSource=github-releases depName=cloudfoundry/cli
83+
CF_CLI_VERSION: "8.18.3"
84+
# renovate: dataSource=github-releases depName=kubernetes-sigs/kind
85+
KIND_VERSION: "0.32.0"
86+
# renovate: dataSource=github-releases depName=helmfile/helmfile
87+
HELMFILE_VERSION: "1.5.3"
88+
- name: Use develop versions of cf-deployment
89+
id: pre_validation
90+
if: steps.check_changes.outputs.skip != 'true' && inputs.fresh-validation == true
91+
env:
92+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
93+
run: |
94+
pip3 install -r scripts/requirements.txt
95+
python3 scripts/sync-cf-deployment-versions.py --ref develop
96+
- name: Run make up
97+
if: steps.check_changes.outputs.skip != 'true'
98+
run: make up
99+
env:
100+
CONTAINER_RUNTIME: ${{ inputs.container-runtime }}
101+
INSTALL_OPTIONAL_COMPONENTS: ${{ inputs.install-optional-components }}
102+
- name: Login
103+
if: steps.check_changes.outputs.skip != 'true'
104+
run: make login
105+
- name: Init
106+
if: steps.check_changes.outputs.skip != 'true'
107+
run: make bootstrap-complete
108+
- name: setup CF tests
109+
if: steps.check_changes.outputs.skip != 'true'
110+
uses: ./.github/actions/setup-cf-tests
111+
with:
112+
test-repo: cf-smoke-tests
113+
test-branch: main
114+
config-template: ./.github/smoke-config.tpl
115+
config-output: ./.github/smoke-config.json
116+
- name: run smoke test
117+
if: steps.check_changes.outputs.skip != 'true'
118+
env:
119+
CONFIG: "${{ github.workspace }}/.github/smoke-config.json"
120+
GINKGO_NO_COLOR: "true"
121+
run: |
122+
./cf-smoke-tests/bin/test --no-color --github-output --timeout=30m --procs=4 --json-report report.json
123+
- name: debug events
124+
if: failure()
125+
run: kubectl get events -A --sort-by='.lastTimestamp'
126+
- name: debug cilium
127+
if: failure() && inputs.container-runtime == 'podman'
128+
run: |
129+
echo "===== CILIUM PODS ====="
130+
kubectl get pod -n kube-system -l k8s-app=cilium -o wide
131+
echo "===== CILIUM AGENT LOGS (all pods) ====="
132+
for pod in $(kubectl get pod -n kube-system -l k8s-app=cilium -o jsonpath='{.items[*].metadata.name}'); do
133+
echo "--- $pod ---"
134+
kubectl logs -n kube-system "$pod" --all-containers=true --previous 2>/dev/null || kubectl logs -n kube-system "$pod" --all-containers=true 2>/dev/null || true
135+
done
136+
echo "===== CILIUM OPERATOR LOGS ====="
137+
kubectl logs -n kube-system -l name=cilium-operator --all-containers=true 2>/dev/null || true
138+
echo "===== CILIUM STATUS ====="
139+
kubectl exec -n kube-system $(kubectl get pod -n kube-system -l k8s-app=cilium -o jsonpath='{.items[0].metadata.name}' 2>/dev/null) -- cilium status 2>/dev/null || true
140+
- name: debug pods
141+
if: failure()
142+
run: |
143+
echo "===== CLOUD_CONTROLLER ====="
144+
kubectl get pod -n cf-system -l app.kubernetes.io/name=cloud-controller -o wide
145+
kubectl get pod -n cf-system -l app.kubernetes.io/name=cloud-controller -o jsonpath='{.status.containerStatuses[*].state}' | jq
146+
kubectl logs -n cf-system -l app.kubernetes.io/name=cloud-controller --all-containers=true
147+
echo "===== CC_WORKER ====="
148+
kubectl get pod -n cf-system -l app.kubernetes.io/name=cc-worker -o wide
149+
kubectl logs -n cf-system -l app.kubernetes.io/name=cc-worker
150+
echo "===== CC_UPLOADER ====="
151+
kubectl get pod -n cf-system -l app=cc-uploader -o wide
152+
kubectl logs -n cf-system -l app=cc-uploader
153+
echo "===== CC_DEPLOYMENT_UPDATER ====="
154+
kubectl get pod -n cf-system -l app.kubernetes.io/name=cc-deployment-updater -o wide
155+
kubectl logs -n cf-system -l app.kubernetes.io/name=cc-deployment-updater
156+
echo "===== CC_WORKER_CLOCK ====="
157+
kubectl get pod -n cf-system -l app.kubernetes.io/name=cc-worker-clock -o wide
158+
kubectl logs -n cf-system -l app.kubernetes.io/name=cc-worker-clock
159+
- name: debug pods (Podman extras)
160+
if: failure() && inputs.container-runtime == 'podman'
161+
run: |
162+
echo "===== CF_TCP_ROUTER ====="
163+
kubectl get pod -n cf-system -l app=cf-tcp-router -o wide
164+
kubectl get pod -n cf-system -l app=cf-tcp-router -o jsonpath='{.items[*].status.containerStatuses[*].state}' | jq 2>/dev/null || true
165+
kubectl logs -n cf-system -l app=cf-tcp-router --all-containers=true 2>/dev/null || true
166+
echo "===== ROUTING_API ====="
167+
kubectl get pod -n cf-system -l app=routing-api -o wide
168+
kubectl logs -n cf-system -l app=routing-api --all-containers=true 2>/dev/null || true
169+
- uses: actions/upload-artifact@v7
170+
if: always()
171+
with:
172+
name: ${{ inputs.artifact-name }}
173+
path: ./cf-smoke-tests/report.json

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
temp/
2-
2+
.idea

Makefile

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

6+
build:
7+
@ . ./scripts/detect-runtime.sh; \
8+
if [ "$$CONTAINER_RUNTIME" = "podman" ]; then \
9+
echo "Building with Podman is not yet supported via docker-bake.hcl."; \
10+
echo "Use 'podman build' manually with the Dockerfiles in releases/."; \
11+
exit 1; \
12+
fi; \
13+
docker buildx bake --file docker-bake.hcl --set "*.platform=linux/$(TARGET_ARCH)" $(BAKE_TARGETS)
14+
615
init: temp/certs/ca.key temp/certs/ca.crt temp/certs/ssh_key temp/certs/ssh_key.pub temp/secrets.sh temp/secrets.env
716

817
temp/certs/ca.key temp/certs/ca.crt temp/certs/ssh_key temp/certs/ssh_key.pub temp/secrets.sh temp/secrets.env:
918
@ ./scripts/init.sh
1019

1120
install:
12-
kind get kubeconfig --name cfk8s > temp/kubeconfig
13-
docker run --rm --net=host --env-file temp/secrets.env \
21+
@ . ./scripts/detect-runtime.sh; \
22+
if [ "$$IS_PODMAN" = "true" ]; then export SKIP_CILIUM="true"; fi; \
23+
kind get kubeconfig --name cfk8s > temp/kubeconfig; \
24+
$$CONTAINER_RUNTIME run --rm --net=host --env-file temp/secrets.env \
1425
--env INSTALL_OPTIONAL_COMPONENTS \
26+
--env CILIUM_EXTRA_VALUES \
27+
--env SKIP_CILIUM \
1528
-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
1629

1730
login:
18-
@ . temp/secrets.sh; \
31+
@ echo "Waiting for CF API to become ready..."; \
32+
for i in $$(seq 1 60); do \
33+
status=$$(curl -sk -o /dev/null -w "%{http_code}" https://api.127-0-0-1.nip.io/v2/info); \
34+
if [ "$$status" = "200" ]; then echo "CF API is ready."; break; fi; \
35+
echo " attempt $$i/60: HTTP $$status – retrying in 10s..."; \
36+
sleep 10; \
37+
done; \
38+
if [ "$$status" != "200" ]; then echo "ERROR: CF API did not become ready after 10 minutes." >&2; exit 1; fi; \
39+
. temp/secrets.sh; \
1940
cf login -a https://api.127-0-0-1.nip.io -u ccadmin -p "$$CC_ADMIN_PASSWORD" --skip-ssl-validation
2041

2142
create-kind:
@@ -33,12 +54,12 @@ create-org:
3354
bootstrap: create-org
3455
@ ./scripts/upload_buildpacks.sh
3556

36-
bootstrap-complete: create-org
57+
bootstrap-complete: create-org
3758
@ ALL_BUILDPACKS=true ./scripts/upload_buildpacks.sh
3859

3960
up: create-kind init install
4061

4162
down: delete-kind
4263
@ rm -rf temp
4364

44-
PHONY: install login create-kind delete-kind up down create-org bootstrap bootstrap-complete
65+
.PHONY: build install login create-kind delete-kind up down create-org bootstrap bootstrap-complete

0 commit comments

Comments
 (0)