Skip to content

Commit

Permalink
Make the image more slim and a lot more
Browse files Browse the repository at this point in the history
  • Loading branch information
felipecrs committed Nov 20, 2023
1 parent 268c063 commit 09ce08e
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 189 deletions.
281 changes: 96 additions & 185 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
FROM buildpack-deps:focal AS base
FROM jenkins/inbound-agent:latest AS jenkins-agent


FROM buildpack-deps:jammy AS base

# set bash as the default interpreter for the build with:
# -e: exits on error, so we can use colon as line separator
Expand All @@ -21,52 +24,40 @@ RUN shc -S -r -f /init_as_root.sh -o /init_as_root; \
chmod 4755 /init_as_root


FROM ghcr.io/felipecrs/skopeo-bin:latest AS skopeo-bin


FROM scratch AS rootfs

COPY --from=init_as_root /init_as_root /
COPY --from=jenkins-agent /usr/local/bin/jenkins-agent /usr/local/bin/jenkins-slave /usr/local/bin/
COPY --from=jenkins-agent /usr/share/jenkins /usr/share/jenkins
COPY --from=jenkins-agent /opt/java/openjdk /opt/java/openjdk
COPY rootfs /
COPY --from=skopeo-bin / /usr/local/bin/


FROM base

ENV NON_ROOT_USER=jenkins
ENV NON_ROOT_USER="jenkins"
ARG HOME="/home/${NON_ROOT_USER}"

# build helpers
ARG DEBIANFRONTEND="noninteractive"
ARG APT_GET="apt-get"
ARG APT_GET_INSTALL="${APT_GET} install -yq --no-install-recommends"
ARG SUDO_APT_GET="sudo ${APT_GET}"
ARG SUDO_APT_GET_INSTALL="sudo DEBIANFRONTEND=noninteractive ${APT_GET_INSTALL}"
ARG CLEAN_DATA="rm -rf /tmp/* /var/cache/* /usr/share/doc/* /usr/share/man/* /var/lib/apt/lists/*"
ARG CURL="curl -fsSL"
ARG NPM_PREFIX="${HOME}/.npm"

ENV AGENT_WORKDIR="${HOME}/agent" \
CI=true \
PATH="${NPM_PREFIX}/bin:${HOME}/.local/bin:${PATH}" \
JAVA_HOME="/usr/lib/jvm/temurin-11-jdk-amd64" \
# locale and encoding \
LANG="en_US.UTF-8" \
LANGUAGE="en_US:en" \
LC_ALL="en_US.UTF-8" \
# from jenkins/docker-agent \
TZ="Etc/UTC" \
## Entrypoint related \
# Fails if cont-init and fix-attrs fails \
S6_BEHAVIOUR_IF_STAGE2_FAILS=2 \
# Wait for services before running CMD \
S6_CMD_WAIT_FOR_SERVICES=1 \
# Give 15s for services to start \
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=15000 \
# Give 15s for services to stop \
S6_SERVICES_GRACETIME=15000 \
# Honor container env on CMD \
S6_KEEP_ENV=1
ENV AGENT_WORKDIR="${HOME}/agent"
ENV CI="true"
ENV EDITOR="nano"
ENV PATH="${HOME}/.local/bin:${PATH}:/opt/java/openjdk/bin"
## Locale and encoding
ENV LANG="en_US.UTF-8"
ENV LANGUAGE="en_US:en"
ENV LC_ALL="en_US.UTF-8"
ENV TZ="Etc/UTC"
## Entrypoint related
# Fails if cont-init and fix-attrs fails
ENV S6_BEHAVIOUR_IF_STAGE2_FAILS=2
# Wait for services before running CMD
ENV S6_CMD_WAIT_FOR_SERVICES=1
# Give 15s for services to start
ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=15000
# Give 15s for services to stop
ENV S6_SERVICES_GRACETIME=15000
# Honor container env on CMD
ENV S6_KEEP_ENV=1

# create non-root user
RUN group="${NON_ROOT_USER}"; \
Expand All @@ -75,203 +66,123 @@ RUN group="${NON_ROOT_USER}"; \
groupadd -g "${gid}" "${group}"; \
useradd -l -c "Jenkins user" -d "${HOME}" -u "${uid}" -g "${gid}" -m "${NON_ROOT_USER}" -s /bin/bash -p ""; \
# install sudo and locales\
${APT_GET} update; \
${APT_GET_INSTALL} \
apt_get="env DEBIANFRONTEND=noninteractive apt-get" ; \
apt_get_install="${apt_get} install -yq --no-install-recommends"; \
CURL="curl -fsSL"; \
${apt_get} update; \
${apt_get_install} \
sudo \
locales; \
# clean not needed data \
${CLEAN_DATA}; \
# setup locale \
sudo sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen; \
sudo locale-gen; \
sed -i "/${LANG}/s/^# //g" /etc/locale.gen; \
locale-gen; \
# setup sudo \
usermod -aG sudo "${NON_ROOT_USER}"; \
echo "${NON_ROOT_USER} ALL=(ALL) NOPASSWD:ALL" | tee "/etc/sudoers.d/${NON_ROOT_USER}"; \
# dismiss sudo welcome message \
sudo -u "${NON_ROOT_USER}" sudo true


# use non-root user with sudo when needed
USER "${NON_ROOT_USER}:${NON_ROOT_USER}"

WORKDIR "${AGENT_WORKDIR}"

VOLUME "${AGENT_WORKDIR}"

RUN \
# ensure jenkins-agent directory exists \
sudo -u "${NON_ROOT_USER}" sudo true; \
# create agent workdir \
mkdir -p "${AGENT_WORKDIR}"; \
## apt \
${SUDO_APT_GET} update; \
# upgrade system \
${SUDO_APT_GET} -yq upgrade; \
# install add-apt-repository \
${SUDO_APT_GET_INSTALL} software-properties-common; \
## apt repositories \
# adoptium openjdk \
${CURL} https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo apt-key add -; \
sudo add-apt-repository --no-update -y "https://packages.adoptium.net/artifactory/deb"; \
# jdk installation expects this folder but we deleted during cleanup; \
sudo mkdir -p /usr/share/man/man1; \
# kubernetes \
${CURL} https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -; \
sudo add-apt-repository --no-update -y "deb https://apt.kubernetes.io/ kubernetes-xenial main"; \
# yarn \
${CURL} https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -; \
sudo add-apt-repository --no-update -y "deb https://dl.yarnpkg.com/debian/ stable main"; \
# jfrog \
${CURL} https://releases.jfrog.io/artifactory/api/gpg/key/public | sudo apt-key add -; \
sudo add-apt-repository --no-update -y "deb https://releases.jfrog.io/artifactory/jfrog-debs xenial contrib"; \
# git \
sudo add-apt-repository --no-update -y ppa:git-core/ppa; \
# yq \
sudo add-apt-repository --no-update -y ppa:rmescandon/yq; \
# git-lfs \
${CURL} https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo -E bash -; \
# nodejs \
${CURL} https://deb.nodesource.com/setup_lts.x | sudo -E bash -; \
# docker \
sudo install -m 0755 -d /etc/apt/keyrings; \
${CURL} https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg; \
sudo chmod a+r /etc/apt/keyrings/docker.gpg; \
chown -R "${NON_ROOT_USER}:${NON_ROOT_USER}" "${AGENT_WORKDIR}" ; \
# add docker apt repo \
install -m 0755 -d /etc/apt/keyrings; \
${CURL} https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg; \
chmod a+r /etc/apt/keyrings/docker.gpg; \
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "${VERSION_CODENAME}")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list; \
tee /etc/apt/sources.list.d/docker.list; \
# install apt packages \
${SUDO_APT_GET} update; \
${SUDO_APT_GET_INSTALL} \
${apt_get} update; \
${apt_get_install} \
# from https://github.com/jenkinsci/docker-agent/blob/de96775948b89697556993f829713f70af5e2f8a/debian/Dockerfile \
ca-certificates \
curl \
fontconfig \
git \
git-lfs \
less \
netbase \
openssh-client \
patch \
tzdata \
# miscelaneous packages \
wget \
gnupg \
tree \
jq \
yq \
parallel \
rsync \
sshpass \
python3-pip \
temurin-11-jdk \
nodejs \
yarn \
kubectl \
jfrog-cli \
jfrog-cli-v2-jf \
shellcheck \
maven \
ant \
ant-contrib \
zip \
unzip \
time \
# from jenkins/docker-agent \
openssh-client \
patch \
tzdata \
netbase \
less \
fontconfig \
ca-certificates \
# required for docker in docker \
iptables \
xz-utils \
btrfs-progs \
# network \
time \
# troubleshooting \
net-tools \
iputils-ping \
traceroute \
dnsutils \
netcat \
openssh-server \
# docker pre-requisites \
ca-certificates \
curl \
gnupg \
nano \
# required for docker in docker \
iptables \
btrfs-progs \
# docker \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin; \
${SUDO_APT_GET} autoremove -yq; \
sudo ${CLEAN_DATA}; \
rm -rf /var/lib/apt/lists/*; \
# setup docker \
sudo usermod -aG docker "${NON_ROOT_USER}"; \
## setup docker-switch (docker-compose v1 compatibility) \
usermod -aG docker "${NON_ROOT_USER}"; \
## setup docker-switch (for docker-compose v1 compatibility) \
version=$(basename "$(${CURL} -o /dev/null -w "%{url_effective}" https://github.com/docker/compose-switch/releases/latest)"); \
sudo ${CURL} --create-dirs -o "/usr/local/bin/docker-compose" "https://github.com/docker/compose-switch/releases/download/${version}/docker-compose-$(uname -s)-amd64"; \
sudo chmod +x /usr/local/bin/docker-compose; \
${CURL} --create-dirs -o "/usr/local/bin/docker-compose" "https://github.com/docker/compose-switch/releases/download/${version}/docker-compose-$(uname -s)-amd64"; \
chmod +x /usr/local/bin/docker-compose; \
## dind \
# set up subuid/subgid so that "--userns-remap=default" works out-of-the-box \
sudo addgroup --system dockremap; \
sudo adduser --system --ingroup dockremap dockremap; \
echo 'dockremap:165536:65536' | sudo tee -a /etc/subuid; \
echo 'dockremap:165536:65536' | sudo tee -a /etc/subgid; \
addgroup --system dockremap; \
adduser --system --ingroup dockremap dockremap; \
echo 'dockremap:165536:65536' | tee -a /etc/subuid; \
echo 'dockremap:165536:65536' | tee -a /etc/subgid; \
# install dind hack \
# https://github.com/moby/moby/commits/master/hack/dind \
version="d58df1fc6c866447ce2cd129af10e5b507705624"; \
sudo ${CURL} -o /usr/local/bin/dind "https://raw.githubusercontent.com/moby/moby/${version}/hack/dind"; \
sudo chmod +x /usr/local/bin/dind; \
# install jenkins-agent \
# the same version as being used in the official agent image \
version=$(basename "$(${CURL} -o /dev/null -w "%{url_effective}" https://github.com/jenkinsci/docker-agent/releases/latest)" | cut -d'-' -f1) ; \
sudo curl --create-dirs -fsSLo /usr/share/jenkins/agent.jar "https://repo.jenkins-ci.org/public/org/jenkins-ci/main/remoting/${version}/remoting-${version}.jar"; \
sudo chmod 755 /usr/share/jenkins; \
sudo chmod +x /usr/share/jenkins/agent.jar; \
sudo ln -sf /usr/share/jenkins/agent.jar /usr/share/jenkins/slave.jar; \
# install jenkins-agent wrapper from inbound-agent \
version=$(basename "$(${CURL} -o /dev/null -w "%{url_effective}" https://github.com/jenkinsci/docker-inbound-agent/releases/latest)"); \
sudo ${CURL} -o /usr/local/bin/jenkins-agent "https://raw.githubusercontent.com/jenkinsci/docker-inbound-agent/${version}/jenkins-agent"; \
sudo chmod +x /usr/local/bin/jenkins-agent; \
sudo ln -sf /usr/local/bin/jenkins-agent /usr/local/bin/jenkins-slave; \
## pip \
# setup python and pip aliases \
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 1; \
sudo update-alternatives --install /usr/bin/pip pip /usr/bin/pip3 1; \
# upgrade pip \
sudo pip install --no-cache-dir --upgrade pip; \
# install pip packages \
sudo pip install --no-cache-dir ansible; \
## npm \
# upgrade npm \
sudo npm install -g npm@latest; \
# allow npm --global to run as non-root \
mkdir "${NPM_PREFIX}"; \
npm config set prefix "${NPM_PREFIX}"; \
# install npm packages \
sudo npm install --global \
semver \
bats; \
# clean npm cache \
sudo npm cache clean --force; \
## miscellaneous \
# install kind \
version=$(basename "$(${CURL} -o /dev/null -w "%{url_effective}" https://github.com/kubernetes-sigs/kind/releases/latest)"); \
sudo ${CURL} -o /usr/local/bin/kind "https://github.com/kubernetes-sigs/kind/releases/download/${version}/kind-$(uname)-amd64"; \
sudo chmod +x /usr/local/bin/kind; \
# install hadolint \
version=$(basename "$(${CURL} -o /dev/null -w "%{url_effective}" https://github.com/hadolint/hadolint/releases/latest)"); \
sudo ${CURL} -o /usr/local/bin/hadolint "https://github.com/hadolint/hadolint/releases/download/${version}/hadolint-Linux-x86_64"; \
sudo chmod +x /usr/local/bin/hadolint; \
# install helm 3 \
${CURL} https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | sudo -E bash -; \
${CURL} -o /usr/local/bin/dind "https://raw.githubusercontent.com/moby/moby/${version}/hack/dind"; \
chmod +x /usr/local/bin/dind; \
# install retry \
version=$(basename "$(${CURL} -o /dev/null -w "%{url_effective}" "https://github.com/kadwanev/retry/releases/latest")"); \
${CURL} "https://github.com/kadwanev/retry/releases/download/${version}/retry-${version}.tar.gz" | \
sudo tar -C /usr/local/bin -xzf -; \
${CURL} "https://github.com/kadwanev/retry/releases/download/${version}/retry-${version}.tar.gz" \
| tar -C /usr/local/bin -xzf - retry; \
# install pkgx \
version=$(basename "$(${CURL} -o /dev/null -w "%{url_effective}" "https://github.com/pkgxdev/pkgx/releases/latest")"); \
${CURL} "https://github.com/pkgxdev/pkgx/releases/download/${version}/pkgx-${version#v}+linux+$(uname -m | sed "s/_/-/g").tar.xz" \
| tar -C /usr/local/bin -xJf - pkgx; \
# install s6-overlay \
version="3.1.6.2"; \
${CURL} https://github.com/just-containers/s6-overlay/releases/download/v${version}/s6-overlay-noarch.tar.xz | sudo tar -C / -Jxpf -; \
${CURL} https://github.com/just-containers/s6-overlay/releases/download/v${version}/s6-overlay-x86_64.tar.xz | sudo tar -C / -Jxpf -; \
${CURL} "https://github.com/just-containers/s6-overlay/releases/download/v${version}/s6-overlay-noarch.tar.xz" \
| tar -C / -Jxpf -; \
${CURL} "https://github.com/just-containers/s6-overlay/releases/download/v${version}/s6-overlay-x86_64.tar.xz" \
| tar -C / -Jxpf -; \
# fix sshd not starting \
sudo mkdir -p /run/sshd; \
mkdir -p /run/sshd; \
# install fixuid \
# https://github.com/boxboat/fixuid/releases \
version="0.6.0" ; \
curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v${version}/fixuid-${version}-linux-amd64.tar.gz" | sudo tar -C /usr/local/bin -xzf -; \
sudo chown root:root /usr/local/bin/fixuid;\
sudo chmod 4755 /usr/local/bin/fixuid; \
sudo mkdir -p /etc/fixuid; \
printf '%s\n' "user: ${NON_ROOT_USER}" "group: ${NON_ROOT_USER}" "paths:" " - /" " - ${AGENT_WORKDIR}" | sudo tee /etc/fixuid/config.yml
curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v${version}/fixuid-${version}-linux-amd64.tar.gz" | tar -C /usr/local/bin -xzf -; \
chown root:root /usr/local/bin/fixuid;\
chmod 4755 /usr/local/bin/fixuid; \
mkdir -p /etc/fixuid; \
printf '%s\n' "user: ${NON_ROOT_USER}" "group: ${NON_ROOT_USER}" "paths:" " - /" " - ${AGENT_WORKDIR}" | tee /etc/fixuid/config.yml

USER "${NON_ROOT_USER}:${NON_ROOT_USER}"

WORKDIR "${AGENT_WORKDIR}"

VOLUME "${AGENT_WORKDIR}"

COPY --from=rootfs / /

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
[![Docker Pulls](https://img.shields.io/docker/pulls/felipecrs/jenkins-agent-dind)](https://hub.docker.com/r/felipecrs/jenkins-agent-dind)
[![Docker Image Size](https://img.shields.io/docker/image-size/felipecrs/jenkins-agent-dind/latest)](https://hub.docker.com/r/felipecrs/jenkins-agent-dind)

A full fledged Docker in Docker image to act as a Jenkins Agent. Based on [buildpack-deps:focal](https://github.com/docker-library/buildpack-deps/blob/master/focal/Dockerfile), it is a mashup of [jenkins/inbound-agent](https://github.com/jenkinsci/docker-inbound-agent) with [docker:dind](https://github.com/docker-library/docker).
A full fledged Docker in Docker image to act as a Jenkins Agent. Based on [buildpack-deps:jammy](https://github.com/docker-library/buildpack-deps/blob/master/ubuntu/jammy/Dockerfile), it is a mashup of [jenkins/inbound-agent](https://github.com/jenkinsci/docker-inbound-agent) with [docker:dind](https://github.com/docker-library/docker).

- Source code: <https://github.com/felipecrs/jenkins-agent-dind>
- Docker image: <https://hub.docker.com/r/felipecrs/jenkins-agent-dind>

## Features

- Based on **Ubuntu 20.04 Focal Fossa**: a more common OS to run your builds.
- Based on **Ubuntu 22.04 Jammy Jellyfish**: a more common OS to run your builds.
- From `buildpack-deps`: a image with many common dependencies installed, run your builds without hassle.
- Fully working Docker in Docker: run your `docker build` commands with no intervention and share of resources between the host.
- Act just as a Jenkins Agent out-of-the-box: run ephemeral build containers by using Docker Plugin (or Kubernetes Plugin) for Jenkins. Works as the official `jnlp`/`inbound-agent`.
- Act just as a Jenkins Agent out-of-the-box: run ephemeral build containers by using Docker Plugin (or Kubernetes Plugin) on Jenkins. Works as the official `jnlp`/`inbound-agent`.

## Usage

Expand Down Expand Up @@ -112,7 +112,7 @@ You can use a Kubernetes Pod Template to automatically expose SSH access for all
First you'll need to have [`dynamic-hostports`](https://github.com/felipecrs/dynamic-hostports-k8s) installed in your cluster. You can install it with the following command:

```sh
kubectl apply -f https://raw.githubusercontent.com/felipecrs/jenkins-agent-dind/master/dynamic-hostports.yaml
kubectl apply -f https://github.com/felipecrs/dynamic-hostports-k8s/raw/master/deploy.yaml
```

Then you can use the following Pod Template:
Expand Down
1 change: 1 addition & 0 deletions rootfs/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ uid="$(id -u)"
if [[ "${uid}" -eq 0 ]]; then
# If running as root, simply execute s6-overlay
export USER="root"
export HOME="/root"
cmd=(/init_as_root)
else
# Otherwise, fix uid and gid, run s6-overlay as root and then drop
Expand Down

0 comments on commit 09ce08e

Please sign in to comment.