Skip to content
Merged
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: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ jobs:

case "$FOLDER" in
envoy*) unsupportedPlatforms=(linux/arm/v7 linux/riscv64) ;;
actions-runner* | calico*) unsupportedPlatforms=(linux/riscv64) ;;
actions-runner*) unsupportedPlatforms=(linux/riscv64) ;;
*) unsupportedPlatforms=() ;;
esac

Expand Down
89 changes: 89 additions & 0 deletions images/calico-cni/v3.29.7-1/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# https://github.com/projectcalico/calico/blob/v3.29.2/cni-plugin/Dockerfile

ARG \
VERSION=3.29.7 \
HASH=d60fd083ad0279a4bd20109d01689e4eecb7a5e8c6d5e8be2b1718e6057f85e9 \
# https://github.com/projectcalico/calico/blob/v3.29.7/metadata.mk#L52-L55
# Calico has FLANNEL_VERSION=main branch and CNI_VERSION=master.
# v3.29.7 was released 2025-11-20: https://github.com/projectcalico/calico/releases/tag/v3.29.7
#
# https://github.com/projectcalico/calico/blob/v3.29.7/cni-plugin/Makefile#L169
# https://github.com/projectcalico/flannel-cni-plugin/commits/main/?since=2024-09-12&until=2025-11-20
FLANNEL_VERSION=v1.2.0-flannel2-go1.22.7 \
#
# https://github.com/projectcalico/calico/blob/v3.29.7/cni-plugin/Makefile#L150
# https://github.com/projectcalico/containernetworking-plugins/commits/master/?since=2025-01-27&until=2025-11-20
CNI_PLUGINS_VERSION=9ffe547cb3b66f80dd32a00fc69a6d0082b55321 \
CNI_PLUGINS_HASH=97162c06333ba91c1d4ab8085ed4be09a81a45216c594eb3011332c953a501ba

FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.25.6-alpine3.23 AS build-base


FROM build-base AS builder
ARG VERSION HASH
WORKDIR /go/src/calico
RUN --mount=type=tmpfs,target=/tmp \
wget -qO /tmp/sources.tar.gz https://github.com/projectcalico/calico/archive/refs/tags/v$VERSION.tar.gz \
&& { echo $HASH /tmp/sources.tar.gz | sha256sum -c -; } \
&& tar xf /tmp/sources.tar.gz --strip-components=1
RUN go mod download

ARG TARGETARCH
RUN --mount=type=cache,id=calico-gocache-$TARGETARCH,target=/root/.cache/go-build \
--network=none \
export GOARCH=$TARGETARCH \
&& export CGO_ENABLED=0 \
&& go build \
-mod=readonly -trimpath -buildvcs=false \
-o /out/ \
-ldflags "-s -w -X main.VERSION=v$VERSION" \
./cni-plugin/cmd/calico ./cni-plugin/cmd/install

RUN set -e \
&& cd /out \
&& ln -s calico calico-ipam


FROM build-base AS flannel-cni-plugin
RUN apk add --no-cache git bash

ARG FLANNEL_VERSION
WORKDIR /go/src/flannel-cni-plugin
RUN git -C .. -c advice.detachedHead=false clone -b $FLANNEL_VERSION https://github.com/projectcalico/flannel-cni-plugin.git
RUN go mod download

ARG TARGETARCH
RUN --mount=type=cache,id=calico-gocache-$TARGETARCH,target=/root/.cache/go-build \
--network=none \
GOARCH=$TARGETARCH TAG=$FLANNEL_VERSION EXTRA_LDFLAGS=-s scripts/build_flannel.sh


FROM build-base AS cni-plugins
RUN apk add --no-cache make bash

ARG CNI_PLUGINS_VERSION CNI_PLUGINS_HASH
WORKDIR /go/src/cni-plugins
RUN --mount=type=tmpfs,target=/tmp \
wget -qO /tmp/sources.tar.gz https://github.com/projectcalico/containernetworking-plugins/archive/$CNI_PLUGINS_VERSION.tar.gz \
&& { echo $CNI_PLUGINS_HASH /tmp/sources.tar.gz | sha256sum -c -; } \
&& tar xf /tmp/sources.tar.gz --strip-components=1

ARG TARGETARCH
RUN --mount=type=cache,id=calico-gocache-$TARGETARCH,target=/root/.cache/go-build \
--network=none \
export GOARCH=$TARGETARCH \
&& export CGO_ENABLED=0 \
&& export GOFLAGS='-trimpath -buildvcs=false' \
&& ./build_linux.sh \
-ldflags "-s -w -X github.com/containernetworking/plugins/pkg/utils/buildversion.BuildVersion=$CNI_PLUGINS_VERSION"


FROM scratch
LABEL org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.source="https://github.com/projectcalico/calico"
COPY --from=builder /out/* /opt/cni/bin/
COPY --from=flannel-cni-plugin /go/src/flannel-cni-plugin/dist/flannel-* /opt/cni/bin/flannel
COPY --from=cni-plugins /go/src/cni-plugins/bin/* /opt/cni/bin/
ENV PATH=/opt/cni/bin
WORKDIR /opt/cni/bin
CMD ["/opt/cni/bin/install"]
41 changes: 41 additions & 0 deletions images/calico-kube-controllers/v3.29.7-1/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# https://github.com/projectcalico/calico/blob/v3.29.7/kube-controllers/Dockerfile

ARG \
VERSION=3.29.7 \
HASH=d60fd083ad0279a4bd20109d01689e4eecb7a5e8c6d5e8be2b1718e6057f85e9

FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.25.6-alpine3.23 AS builder

ARG VERSION HASH
WORKDIR /go/src/calico
RUN --mount=type=tmpfs,target=/tmp \
wget -qO /tmp/sources.tar.gz https://github.com/projectcalico/calico/archive/refs/tags/v$VERSION.tar.gz \
&& { echo $HASH /tmp/sources.tar.gz | sha256sum -c -; } \
&& tar xf /tmp/sources.tar.gz --strip-components=1
RUN go mod download

ARG TARGETARCH
RUN --mount=type=cache,id=calico-gocache-$TARGETARCH,target=/root/.cache/go-build \
--network=none \
export GOARCH=$TARGETARCH \
&& export CGO_ENABLED=0 \
&& go build \
-mod=readonly -trimpath -buildvcs=false \
-ldflags "-s -w -X main.VERSION=v$VERSION" \
-o /out/usr/bin/kube-controllers \
./kube-controllers/cmd/kube-controllers \
&& go build \
-mod=readonly -trimpath -buildvcs=false \
-ldflags "-s -w -X main.VERSION=v$VERSION" \
-o /out/usr/bin/check-status \
./kube-controllers/cmd/check-status

RUN mkdir /out/licenses && cp -a kube-controllers/LICENSE /out/licenses/
RUN mkdir /out/status && touch /out/status/status.json && chown 999 /out/status/status.json

FROM scratch
LABEL org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.source="https://github.com/projectcalico/calico"
COPY --from=builder /out/ /
USER 999
ENTRYPOINT ["/usr/bin/kube-controllers"]
167 changes: 167 additions & 0 deletions images/calico-node/v3.29.7-1/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# https://github.com/projectcalico/calico/blob/v3.29.7/node/Dockerfile.amd64

ARG \
VERSION=3.29.7 \
HASH=d60fd083ad0279a4bd20109d01689e4eecb7a5e8c6d5e8be2b1718e6057f85e9 \
IPSET_VERSION=7.23 \
IPSET_HASH=5a43c790abf157a55db5a9a22cb5f28a225f5c7969beda81566a2259aa82c9d852979eb805b11b4347f47c6a0c2cc4de6f14e4733bee5b562844422a45fb9dab \
# https://github.com/projectcalico/calico/blob/v3.29.7/metadata.mk#L36
BIRD_COMMIT=9111ec3c3ff3e769727a5940d3d829a0be8b5201 \
BIRD_HASH=5aaf11e2f0ba3c44cdf27746c0b5da631befd67636579ff5e2ac65b144bee0b3 \
ALPINE_IMAGE=docker.io/library/alpine:3.23.3 \
BUILDER_IMAGE=docker.io/library/golang:1.25.6-alpine3.23 \
IPTABLES_VERSION=1.8.11

FROM --platform=$BUILDPLATFORM $BUILDER_IMAGE AS builder

ARG VERSION HASH
WORKDIR /go/src/calico
RUN --mount=type=tmpfs,target=/tmp \
wget -qO /tmp/sources.tar.gz https://github.com/projectcalico/calico/archive/refs/tags/v$VERSION.tar.gz \
&& { echo $HASH /tmp/sources.tar.gz | sha256sum -c -; } \
&& tar xf /tmp/sources.tar.gz --strip-components=1
RUN go mod download

ARG TARGETARCH
RUN --mount=type=cache,id=calico-gocache-$TARGETARCH,target=/root/.cache/go-build \
--network=none \
export GOARCH=$TARGETARCH \
&& export CGO_ENABLED=0 \
&& go build -mod=readonly -trimpath -buildvcs=false -ldflags "-s -w -X main.VERSION=v$VERSION" ./node/cmd/calico-node \
&& go build -mod=readonly -trimpath -buildvcs=false -ldflags "-s -w -X main.VERSION=v$VERSION" ./node/cmd/mountns \
&& chmod u+s mountns

FROM $ALPINE_IMAGE AS ipset
RUN apk add --no-cache \
build-base pkgconf curl \
libmnl-dev libmnl-static

ARG IPSET_VERSION IPSET_HASH
RUN curl -sSLo ipset.tar.bz2 "http://ipset.netfilter.org/ipset-$IPSET_VERSION.tar.bz2" \
&& { echo $IPSET_HASH ipset.tar.bz2 | sha512sum -c -; } \
&& mkdir -p /src/ipset && tar xf "ipset.tar.bz2" --strip-components=1 -C /src/ipset \
&& rm -- "ipset.tar.bz2"

WORKDIR /src/ipset
RUN printf '#!/usr/bin/env sh\nexec cc -static "$@"\n' >/src/cc-static && chmod +x /src/cc-static
RUN CC=/src/cc-static CFLAGS=-static LDFLAGS=-static ./configure --enable-static --disable-shared --with-kmod=no
RUN make && strip src/ipset
RUN make install
# Just a sanity check that it's not segfaulting
RUN ipset -h


FROM --platform=$BUILDPLATFORM $ALPINE_IMAGE AS bird-sources
ARG BIRD_COMMIT BIRD_HASH
WORKDIR /bird
RUN --mount=type=tmpfs,target=/tmp \
wget -qO /tmp/sources.tar.gz https://github.com/projectcalico/bird/archive/$BIRD_COMMIT.tar.gz \
&& sha256sum -b /tmp/sources.tar.gz \
&& { echo $BIRD_HASH /tmp/sources.tar.gz | sha256sum -c -; } \
&& tar xf /tmp/sources.tar.gz --strip-components=1


FROM $ALPINE_IMAGE AS bird
RUN apk add --no-cache gcc musl-dev make autoconf flex bison linux-headers
RUN --mount=from=bird-sources,source=/bird,target=/run/stage/bird,ro \
--mount=type=tmpfs,target=/bird \
--network=none \
cp -a /run/stage/bird / \
&& cd /bird \
&& export ARCH=$(uname -m) \
&& DIST=dist OBJ=obj sh -x ./create_binaries.sh \
&& find dist/ -type f -mindepth 2 -maxdepth 2 -exec strip '{}' ';' \
&& mkdir /dist \
&& find dist/ -type f -mindepth 2 -maxdepth 2 -exec mv '{}' /dist ';'


# Build iptables
FROM $ALPINE_IMAGE AS iptables
ARG IPTABLES_VERSION

RUN apk add build-base curl pkgconf \
linux-headers \
libmnl-dev libmnl-static \
libnftnl-dev

RUN curl --proto '=https' --tlsv1.2 -L https://www.netfilter.org/projects/iptables/files/iptables-$IPTABLES_VERSION.tar.xz \
| tar -C / -Jx

ARG TARGET_OS
# -D__UAPI_DEF_ETHHDR is required to build on musl.
# If this CFLAG isn't defined, itpables will define it in include/xtables.h
# and will have a conflict with musl, which defines it in
# /usr/include/netinet/if_ether.h
RUN cd /iptables-$IPTABLES_VERSION && \
CFLAGS="-Os -D__UAPI_DEF_ETHHDR=0" ./configure --sysconfdir=/etc --enable-static --disable-shared --without-kernel --disable-devel

RUN make -j$(nproc) -C /iptables-$IPTABLES_VERSION LDFLAGS=-all-static
RUN make -j$(nproc) -C /iptables-$IPTABLES_VERSION install

RUN strip /usr/local/sbin/xtables-legacy-multi
RUN strip /usr/local/sbin/xtables-nft-multi
RUN scanelf -Rn /usr/local && file /usr/local/sbin/*

FROM --platform=$BUILDPLATFORM $BUILDER_IMAGE AS iptables-wrapper
RUN apk add --no-cache patch make

ARG IPTABLES_WRAPPER_VERSION=06cad2ec6cb5ed0945b383fb185424c0a67f55eb
ARG IPTABLES_WRAPPER_HASH=fde9ccd22b337fd297180cd21938c0a82030187fc29aabb6800472295d62752a

WORKDIR /go/src/iptables-wrapper
RUN --mount=type=tmpfs,target=/tmp \
wget -qO /tmp/sources.tar.gz https://github.com/kubernetes-sigs/iptables-wrappers/archive/$IPTABLES_WRAPPER_VERSION.tar.gz \
&& { echo $IPTABLES_WRAPPER_HASH /tmp/sources.tar.gz | sha256sum -c -; } \
&& tar xf /tmp/sources.tar.gz --strip-components=1
RUN go mod download

ARG TARGETARCH
RUN --mount=source=files,target=/run/stage/files,ro \
--mount=type=tmpfs,target=/go/iptables-wrapper/bin \
--mount=type=cache,id=calico-gocache-$TARGETARCH,target=/root/.cache/go-build \
--network=none \
set -euo pipefail \
&& patch </run/stage/files/iptables-wrapper.patch \
&& GOARCH="$TARGETARCH" make build \
&& mv bin/iptables-wrapper .

# Build the image based on alpine
FROM $ALPINE_IMAGE
LABEL org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.source="https://github.com/projectcalico/calico"
ARG TARGETARCH

RUN apk add --no-cache bash iputils iproute2 conntrack-tools runit ca-certificates

# Copy the calico-node binary from the builder image
COPY --from=builder /go/src/calico/calico-node /usr/bin/calico-node
COPY --from=builder /go/src/calico/mountns /usr/bin/mountns

COPY --from=ipset /usr/local/sbin/ipset /usr/sbin/ipset
COPY --from=ipset /src/ipset/ChangeLog /usr/share/doc/ipset/ChangeLog

# Copy the config etc filesystem from builder
COPY --from=builder /go/src/calico/node/filesystem/ /
COPY --from=builder /go/src/calico/confd/etc/ /etc/

# Change permissions to make confd templates and output available in /etc/calico
# to all container users.
RUN chgrp -R 0 /etc/calico && \
chmod -R g=u /etc/calico

COPY --from=bird /dist/* /usr/bin/

# Copy iptables and wrappers
COPY --from=iptables \
/usr/local/sbin/xtables-* \
/usr/local/sbin/iptables* \
/usr/local/sbin/ip6tables* \
/sbin/
RUN --mount=from=iptables-wrapper,source=/go/src/iptables-wrapper,target=/run/stage/iptables-wrapper,ro \
cp -a /run/stage/iptables-wrapper/iptables-wrapper-installer.sh /run/stage/iptables-wrapper/iptables-wrapper / \
&& /iptables-wrapper-installer.sh

RUN echo "hosts: files dns" > /etc/nsswitch.conf

ENV SVDIR=/etc/service/enabled
CMD ["start_runit"]
33 changes: 33 additions & 0 deletions images/calico-node/v3.29.7-1/files/iptables-wrapper.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--- Makefile
+++ Makefile
@@ -7,7 +7,7 @@ $(BIN_DIR):
mkdir -p $(BIN_DIR)

build: $(BIN_DIR)
- CGO_ENABLED=0 $(GO) build -ldflags='-s -w -extldflags="-static" -buildid=""' -trimpath -o $(BIN_DIR)/iptables-wrapper github.com/kubernetes-sigs/iptables-wrappers
+ CGO_ENABLED=0 $(GO) build -ldflags='-s -w -extldflags="-static" -buildid=""' -trimpath -buildvcs=false -o $(BIN_DIR)/iptables-wrapper github.com/kubernetes-sigs/iptables-wrappers

vet: ## Run go vet against code.
$(GO) vet ./...
--- iptables-wrapper-installer.sh
+++ iptables-wrapper-installer.sh
@@ -85,11 +85,15 @@ done

if [ -z "${no_sanity_check}" ]; then
# Ensure dependencies are installed
- if ! version=$("${sbin}/iptables-nft" --version 2> /dev/null); then
- echo "ERROR: iptables-nft is not installed" 1>&2
- exit 1
+ # NOTE(k0s): iptables-nft will fail under QEMU with the below error
+ # message, hence use iptables-legacy for the version check
+ if ! version=$("${sbin}/iptables-nft" --version 2>&1); then
+ if [ "$version" != "iptables: Failed to initialize nft: Protocol not supported" ]; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think you are missing some kernel options in your QEMU riscv64 kernel. I hade the same problem with my own kernel on real hardware. iptables-nft need some kernel options enabled.

I added some CONFIG_NFT_* options in my .config and did a rebuild of the kernel. No idea with one a needed, but i added all this options after 3 rebuilds and still missing some options:

CONFIG_NETFILTER_SKIP_EGRESS
CONFIG_NETFILTER_FAMILY_ARP
CONFIG_NETFILTER_NETLINK_HOOK
CONFIG_NETFILTER_CONNCOUNT
CONFIG_NETFILTER_SYNPROXY
CONFIG_NF_TABLES_INET
CONFIG_NF_TABLES_NETDEV
CONFIG_NFT_NUMGEN
CONFIG_NFT_CT
CONFIG_NFT_FLOW_OFFLOAD
CONFIG_NFT_CONNLIMIT
CONFIG_NFT_LOG
CONFIG_NFT_LIMIT
CONFIG_NFT_MASQ
CONFIG_NFT_REDIR
CONFIG_NFT_NAT
CONFIG_NFT_TUNNEL
CONFIG_NFT_QUOTA
CONFIG_NFT_REJECT
CONFIG_NFT_REJECT_INET
CONFIG_NFT_COMPAT
CONFIG_NFT_HASH
CONFIG_NFT_FIB
CONFIG_NFT_FIB_INET
CONFIG_NFT_XFRM
CONFIG_NFT_SOCKET
CONFIG_NFT_OSF
CONFIG_NFT_TPROXY
CONFIG_NFT_SYNPROXY
CONFIG_NF_DUP_NETDEV
CONFIG_NFT_DUP_NETDEV
CONFIG_NFT_FWD_NETDEV
CONFIG_NFT_FIB_NETDEV
CONFIG_NFT_REJECT_NETDEV
CONFIG_NF_FLOW_TABLE_INET
CONFIG_NF_FLOW_TABLE
CONFIG_NF_FLOW_TABLE_PROCFS
CONFIG_NETFILTER_XT_TARGET_CT
CONFIG_NF_SOCKET_IPV4
CONFIG_NF_TPROXY_IPV4
CONFIG_NF_TABLES_IPV4
CONFIG_NFT_REJECT_IPV4
CONFIG_NFT_DUP_IPV4
CONFIG_NFT_FIB_IPV4
CONFIG_NF_TABLES_ARP
CONFIG_NF_DUP_IPV4
CONFIG_NFT_COMPAT_ARP
CONFIG_IP_NF_ARP_MANGLE
CONFIG_NF_SOCKET_IPV6
CONFIG_NF_TPROXY_IPV6
CONFIG_NF_TABLES_IPV6
CONFIG_NFT_REJECT_IPV6
CONFIG_NFT_DUP_IPV6
CONFIG_NFT_FIB_IPV6
CONFIG_NF_DUP_IPV6
CONFIG_IP6_NF_TARGET_NPT
CONFIG_NF_TABLES_BRIDGE
CONFIG_NFT_BRIDGE_META
CONFIG_NFT_BRIDGE_REJECT
CONFIG_IFB

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah, that'd probably a proper way to fix it. However, CI is relying on tonistiigi/binfmt, and that doesn't have these, neither does my distro's binfmt_misc stuff, which I use for local dev/testing.

+ echo "ERROR: iptables-nft is not installed" 1>&2
+ exit 1
+ fi
fi
- if ! "${sbin}/iptables-legacy" --version > /dev/null 2>&1; then
+ if ! version=$("${sbin}/iptables-legacy" --version 2> /dev/null); then
echo "ERROR: iptables-legacy is not installed" 1>&2
exit 1
fi