From: Matthew Newton Date: Wed, 24 Apr 2024 16:18:41 +0000 (+0100) Subject: docker: generate dockerfiles from templates X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3461bb0fcc4ec1f243656dcc2cdf326cb2ff01d7;p=thirdparty%2Ffreeradius-server.git docker: generate dockerfiles from templates --- diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000000..f2c5ac5c2da --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +scripts/docker/build/ +scripts/docker/m4/ diff --git a/Makefile b/Makefile index 77bb24bb99a..7c5553f280d 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ endif # there's no point in requiring the developer to run configure # *before* making packages. # -ifeq "$(filter deb rpm pkg_version crossbuild.% freeradius-server-%,$(MAKECMDGOALS))" "" +ifeq "$(filter deb rpm pkg_version dist-check% crossbuild.% docker.% freeradius-server-%,$(MAKECMDGOALS))" "" $(if $(wildcard Make.inc),,$(error Missing 'Make.inc' Run './configure [options]' and retry)) include Make.inc else @@ -114,7 +114,7 @@ PROTOCOLS := \ # If we're building packages or crossbuilding, just do that. # Don't try to do a local build. # -ifeq "$(filter deb rpm pkg_version crossbuild.% freeradius-server-%,$(MAKECMDGOALS))" "" +ifeq "$(filter deb rpm pkg_version dist-check% crossbuild.% docker.% freeradius-server-%,$(MAKECMDGOALS))" "" # # Include all of the autoconf definitions into the Make variable space @@ -463,13 +463,15 @@ freeradius-server-$(PKG_VERSION).tar.bz2: freeradius-server-$(PKG_VERSION).tar gpg --default-key packages@freeradius.org -b $< # high-level targets -.PHONY: dist-check -dist-check: redhat/freeradius.spec debian/changelog +.PHONY: dist-check-rpm +dist-check-rpm: redhat/freeradius.spec @if [ `grep '^%global _version' redhat/freeradius.spec | cut -d' ' -f3` != "$(PKG_VERSION)" ]; then \ sed 's/^%global _version .*/%global _version $(PKG_VERSION)/' redhat/freeradius.spec > redhat/.foo; \ mv redhat/.foo redhat/freeradius.spec; \ echo Updated redhat/freeradius.spec '_version' to $(PKG_VERSION); \ fi +.PHONY: dist-check +dist-check: dist-check-rpm debian/changelog @if [ `head -n 1 doc/ChangeLog | awk '/^FreeRADIUS/{print $$2}'` != "$(PKG_VERSION)" ]; then \ echo doc/ChangeLog needs to be updated; \ exit 1; \ @@ -554,6 +556,13 @@ ifneq "$(findstring crossbuild,$(MAKECMDGOALS))" "" include scripts/docker/crossbuild.mk endif +# +# Conditionally include the docker make file +# +ifneq "$(findstring docker,$(MAKECMDGOALS))" "" + include scripts/docker/docker.mk +endif + # # Clean gcov files, too. # diff --git a/scripts/docker/docker.mk b/scripts/docker/docker.mk new file mode 100644 index 00000000000..0ac7e56f408 --- /dev/null +++ b/scripts/docker/docker.mk @@ -0,0 +1,126 @@ +# +# Docker targets to create Docker images that run FreeRADIUS +# +ifeq ($(shell which docker 2> /dev/null),) +.PHONY: docker docker.help +docker docker.help : + @echo docker targets require Docker to be installed +else + +# +# Short list of common builds +# +DOCKER_COMMON:=ubuntu22 + +# Top level of where all crossbuild and docker files are +CB_DIR:=$(dir $(realpath $(lastword $(MAKEFILE_LIST)))) + +# Where the docker directories are +DT:=$(CB_DIR)/build + +# Location of top-level m4 template +DOCKER_TMPL:=$(CB_DIR)/m4/Dockerfile.m4 + +# List of all the docker images (sorted for "docker.info") +IMAGES:=$(sort $(patsubst $(DT)/%,%,$(wildcard $(DT)/*))) + +# Don't use the Docker cache if asked +ifneq "$(NOCACHE)" "" + DOCKER_BUILD_OPTS += " --no-cache" +endif + +# Docker image name prefix +D_IPREFIX:=freeradius4 + +# +# This Makefile is included in-line, and not via the "boilermake" +# wrapper. But it's still useful to use the same process for +# seeing commands that are run. +# +ifeq "${VERBOSE}" "" + Q=@ +else + Q= +endif + +# +# Enter here: This builds everything +# +.PHONY: docker docker.common +docker: docker.info $(foreach IMG,${IMAGES},docker.${IMG}) +docker.common: docker.info $(foreach IMG,${DOCKER_COMMON},docker.${IMG}) + +# +# Dump out some useful information on what images we're going to test +# +.PHONY: docker.info docker.info_header docker.help +docker.info: docker.info_header $(foreach IMG,${IMAGES},docker.${IMG}.status) + @echo All images: $(IMAGES) + @echo Common images: $(DOCKER_COMMON) + +docker.info_header: + @echo Built images: + +docker.help: + @echo "" + @echo "Make targets:" + @echo " docker - build all images" + @echo " docker.common - build and test common images" + @echo " docker.info - list images" + @echo " docker.regen - regenerate all Dockerfiles" + @echo "" + @echo "Per-image targets:" + @echo " docker.IMAGE.build - build image as $(D_IPREFIX)/" + @echo " docker.IMAGE.regen - regenerate Dockerfile from template" + @echo "" + @echo "Use 'make NOCACHE=1 ...' to disregard the Docker cache on build" + +# +# Regenerate all Dockerfiles from m4 templates +# +docker.regen: $(foreach IMG,${IMAGES},docker.${IMG}.regen) + +# +# Define rules for building a particular image +# +define CROSSBUILD_IMAGE_RULE + +.PHONY: docker.${1}.status +docker.${1}.status: + ${Q}docker image ls --format "\t{{.Repository}} \t{{.CreatedAt}}" $(D_IPREFIX)/${1} + +# +# Build the docker image +# +.PHONY: docker.${1}.build +docker.${1}.build: + ${Q}echo "BUILD ${1} ($(D_IPREFIX)/${1}) from $(DT)/${1}/Dockerfile" + + ${Q}docker buildx build \ + $(DOCKER_BUILD_OPTS) \ + --progress=plain \ + . \ + -f $(DT)/${1}/Dockerfile \ + -t $(D_IPREFIX)/${1} + +# +# Regenerate the image Dockerfile from the m4 templates +# +.PHONY: docker.${1}.regen +docker.${1}.regen: $(DT)/${1}/Dockerfile + +$(DT)/${1}/Dockerfile: $(DOCKER_TMPL) $(CB_DIR)/m4/docker.deb.m4 $(CB_DIR)/m4/docker.rpm.m4 + ${Q}echo REGEN ${1} "->" $$@ + ${Q}m4 -I $(CB_DIR)/m4 -D D_NAME=${1} -D D_TYPE=docker $$< > $$@ + +endef + +# +# Add all the image building rules +# +$(foreach IMAGE,$(IMAGES),\ + $(eval $(call CROSSBUILD_IMAGE_RULE,$(IMAGE)))) + + +# if docker is defined +endif diff --git a/scripts/docker/etc/docker-entrypoint.sh.deb b/scripts/docker/etc/docker-entrypoint.sh.deb new file mode 100755 index 00000000000..93141b0d74b --- /dev/null +++ b/scripts/docker/etc/docker-entrypoint.sh.deb @@ -0,0 +1,24 @@ +#!/bin/sh +set -e + +# this if will check if the first argument is a flag +# but only works if all arguments require a hyphenated flag +# -v; -SL; -f arg; etc will work, but not arg1 arg2 +if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then + set -- freeradius "$@" +fi + +# check for the expected command +if [ "$1" = 'freeradius' ]; then + shift + exec freeradius -f "$@" +fi + +# many people are likely to call "radiusd" as well, so allow that +if [ "$1" = 'radiusd' ]; then + shift + exec freeradius -f "$@" +fi + +# else default to run whatever the user wanted like "bash" or "sh" +exec "$@" diff --git a/scripts/docker/etc/docker-entrypoint.sh.rpm b/scripts/docker/etc/docker-entrypoint.sh.rpm new file mode 100755 index 00000000000..900ad6b20fb --- /dev/null +++ b/scripts/docker/etc/docker-entrypoint.sh.rpm @@ -0,0 +1,24 @@ +#!/bin/sh +set -e + +# this if will check if the first argument is a flag +# but only works if all arguments require a hyphenated flag +# -v; -SL; -f arg; etc will work, but not arg1 arg2 +if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then + set -- radiusd "$@" +fi + +# check for the expected command +if [ "$1" = 'radiusd' ]; then + shift + exec radiusd -f "$@" +fi + +# debian people are likely to call "freeradius" as well, so allow that +if [ "$1" = 'freeradius' ]; then + shift + exec radiusd -f "$@" +fi + +# else default to run whatever the user wanted like "bash" or "sh" +exec "$@" diff --git a/scripts/docker/m4/docker.deb.m4 b/scripts/docker/m4/docker.deb.m4 new file mode 100644 index 00000000000..6e6b0517e95 --- /dev/null +++ b/scripts/docker/m4/docker.deb.m4 @@ -0,0 +1,98 @@ +ARG from=DOCKER_IMAGE +FROM ${from} as build + +ARG DEBIAN_FRONTEND=noninteractive + +# +# Install build tools +# +RUN apt-get update +RUN apt-get install -y devscripts equivs git quilt gcc curl + +# +# Set up NetworkRADIUS extras repository +# +RUN install -d -o root -g root -m 0755 /etc/apt/keyrings \ + && curl -o /etc/apt/keyrings/packages.networkradius.com.asc "https://packages.networkradius.com/pgp/packages%40networkradius.com" \ + && echo "deb [signed-by=/etc/apt/keyrings/packages.networkradius.com.asc] http://packages.networkradius.com/extras/OS_NAME/OS_CODENAME OS_CODENAME main" > /etc/apt/sources.list.d/networkradius-extras.list \ + && apt-get update + +# +# Create build directory +# +RUN mkdir -p /usr/local/src/repositories/freeradius-server +WORKDIR /usr/local/src/repositories/freeradius-server/ + +# +# Copy the FreeRADIUS directory in +# +COPY . . + +# +# Clean up tree - we want to build from the latest commit, not from +# any cruft left around on the local system +# +RUN git clean -fdxx \ + && git reset --hard HEAD + +# +# Install build dependencies +# +RUN if [ -e ./debian/control.in ]; then \ + debian/rules debian/control; \ + fi; \ + echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control + +# +# Build the server +# +RUN make -j$(nproc) deb + +# +# Clean environment and run the server +# +FROM ${from} +ARG DEBIAN_FRONTEND=noninteractive + +COPY --from=build /usr/local/src/repositories/*.deb /tmp/ + +# +# We need curl to get the signing key +# +RUN apt-get update \ + && apt-get install -y curl \ + && apt-get clean \ + && rm -r /var/lib/apt/lists/* + +# +# Set up NetworkRADIUS extras repository +# +RUN install -d -o root -g root -m 0755 /etc/apt/keyrings \ + && curl -o /etc/apt/keyrings/packages.networkradius.com.asc "https://packages.networkradius.com/pgp/packages%40networkradius.com" \ + && echo "deb [signed-by=/etc/apt/keyrings/packages.networkradius.com.asc] http://packages.networkradius.com/extras/OS_NAME/OS_CODENAME OS_CODENAME main" > /etc/apt/sources.list.d/networkradius-extras.list + +ifelse(ifelse( + D_NAME, `debian10', no, + D_NAME, `ubuntu18', no, + D_NAME, `ubuntu20', no, + yes), yes, `dnl +ARG freerad_uid=101 +ARG freerad_gid=101 + +RUN groupadd -g ${freerad_gid} -r freerad \ + && useradd -u ${freerad_uid} -g freerad -r -M -d /etc/freeradius -s /usr/sbin/nologin freerad \ + && apt-get update \', +`RUN apt-get update \') + && apt-get install -y /tmp/*.deb \ + && apt-get clean \ + && rm -r /var/lib/apt/lists/* /tmp/*.deb \ + \ + && ln -s /etc/freeradius /etc/raddb + +WORKDIR / +COPY scripts/docker/etc/docker-entrypoint.sh.PKG_TYPE docker-entrypoint.sh +RUN chmod +x docker-entrypoint.sh + +EXPOSE 1812/udp 1813/udp +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["freeradius"] diff --git a/scripts/docker/m4/docker.rpm.m4 b/scripts/docker/m4/docker.rpm.m4 new file mode 100644 index 00000000000..d75f8216580 --- /dev/null +++ b/scripts/docker/m4/docker.rpm.m4 @@ -0,0 +1,176 @@ +ARG from=DOCKER_IMAGE +FROM ${from} as build + +ifelse(OS_VER, 8, `dnl +RUN rpmkeys --import /etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial +')dnl +ifelse(OS_VER, 9, `dnl +RUN rpmkeys --import /etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 +') +# +# Install build tools +# +RUN yum groupinstall -y "Development Tools" +ifelse(OS_VER, 7,`dnl +RUN yum install -y rpmdevtools +RUN yum install -y openssl +',` +RUN yum install -y rpmdevtools openssl dnf-utils +') + +# +# Set up NetworkRADIUS extras repository +# +RUN echo $'[networkradius-extras]\n\ +name=NetworkRADIUS-extras-$releasever\n\ +baseurl=http://packages.networkradius.com/extras/OS_NAME/$releasever/\n\ +enabled=1\n\ +gpgcheck=1\n\ +gpgkey=https://packages.networkradius.com/pgp/packages@networkradius.com'\ +> /etc/yum.repos.d/networkradius-extras.repo +RUN rpm --import https://packages.networkradius.com/pgp/packages@networkradius.com + +# +# Create build directory +# +RUN mkdir -p /usr/local/src/repositories/freeradius-server +WORKDIR /usr/local/src/repositories/freeradius-server/ + +# +# Copy the FreeRADIUS directory in +# +COPY . . + +# +# Clean up tree - we want to build from the latest commit, not from +# any cruft left around on the local system +# +RUN git clean -fdxx \ + && git reset --hard HEAD + +# +# Other requirements +# +changequote(`{', `}')dnl +ifelse(ifelse(OS_VER, 8, yes, no), yes, { +# Use LTB's openldap packages instead of the distribution version to avoid linking against NSS +RUN echo $'[ltb-project]\n\ +name=LTB project packages\n\ +baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\ +enabled=1\n\ +gpgcheck=1\n\ +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\ +> /etc/yum.repos.d/ltb-project.repo +RUN rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project +})dnl +changequote({`}, {'})dnl + +# Enable EPEL repository for freetds and hiredis +RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-OS_VER.noarch.rpm +ifelse(OS_VER, 8, ` +# Enable powertools repo +RUN yum config-manager --enable powertools + +# Enable epel-testing, currently needed for hiredis-devel +RUN yum config-manager --enable epel-testing +')dnl +ifelse(OS_VER, 9, ` +# Enable Code Ready Builder repo (CentOS powertools equivalent) +RUN yum install -y yum-utils +RUN yum config-manager --enable crb +')dnl + +# +# Install build dependencies +# +# Run twice, it doesn't always get everything with one invocation +RUN [ -e redhat/freeradius.spec ] && \ + yum-builddep -y redhat/freeradius.spec && \ + yum-builddep -y redhat/freeradius.spec + +# +# Create RPM build environment +# +ENV BUILDDIR=/root/rpmbuild +RUN rpmdev-setuptree + +RUN ./configure +RUN make pkg_version > /VERSION +RUN cat /VERSION +RUN make freeradius-server-$(cat /VERSION).tar.bz2 +RUN cp freeradius-server-$(cat /VERSION).tar.bz2 $BUILDDIR/SOURCES/ +RUN cp -r redhat/* $BUILDDIR/SOURCES/ +RUN make dist-check-rpm +RUN cp -r redhat/freeradius.spec $BUILDDIR/SPECS/ +WORKDIR $BUILDDIR + +# +# Build the server +# +ENV QA_RPATHS=0x0003 +RUN rpmbuild -bb --define "_release $(cat /VERSION)" "$BUILDDIR/SPECS/freeradius.spec" + +RUN mkdir /root/rpms +RUN mv $BUILDDIR/RPMS/*/*.rpm /root/rpms/ + +# +# Clean environment and run the server +# +FROM ${from} + +COPY --from=build /root/rpms /tmp/ + +# +# Set up NetworkRADIUS extras repository +# +RUN echo $'[networkradius-extras]\n\ +name=NetworkRADIUS-extras-$releasever\n\ +baseurl=http://packages.networkradius.com/extras/OS_NAME/$releasever/\n\ +enabled=1\n\ +gpgcheck=1\n\ +gpgkey=https://packages.networkradius.com/pgp/packages@networkradius.com'\ +> /etc/yum.repos.d/networkradius-extras.repo +RUN rpm --import https://packages.networkradius.com/pgp/packages@networkradius.com + +# +# Other requirements +# +changequote(`{', `}')dnl +ifelse(ifelse(OS_VER, 8, yes, no), yes, {dnl +# Use LTB's openldap packages instead of the distribution version to avoid linking against NSS +RUN echo $'[ltb-project]\n\ +name=LTB project packages\n\ +baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\ +enabled=1\n\ +gpgcheck=1\n\ +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\ +> /etc/yum.repos.d/ltb-project.repo \ + && rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project +})dnl +changequote({`}, {'})dnl + +ifelse(OS_VER, 9, `dnl +# Needed for mysql-libs on Rocky 9 +RUN yum install -y yum-utils +RUN yum config-manager --enable crb +')dnl + +# EPEL repository for freetds and hiredis +RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-OS_VER.noarch.rpm \ + && yum install -y dnf-utils \ + && yum config-manager --enable epel-testing + +ARG radiusd_uid=95 +ARG radiusd_gid=95 + +RUN groupadd -g ${radiusd_gid} -r radiusd \ + && useradd -u ${radiusd_uid} -g radiusd -r -M -d /home/radiusd -s /sbin/nologin radiusd \ + && yum install -y /tmp/*.rpm + +WORKDIR / +COPY scripts/docker/etc/docker-entrypoint.sh.PKG_TYPE docker-entrypoint.sh +RUN chmod +x docker-entrypoint.sh + +EXPOSE 1812/udp 1813/udp +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["radiusd"]