winloong
3 years ago
5 changed files with 429 additions and 0 deletions
@ -0,0 +1,145 @@ |
|||
FROM jenkins/inbound-agent:latest-alpine |
|||
|
|||
USER root |
|||
|
|||
RUN sed -i "s@https://dl-cdn.alpinelinux.org/@https://mirrors.huaweicloud.com/@g" /etc/apk/repositories; \ |
|||
apk add --no-cache \ |
|||
ca-certificates \ |
|||
libc6-compat \ |
|||
openssh-client |
|||
|
|||
RUN [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf |
|||
|
|||
ENV DOCKER_VERSION 20.10.15 |
|||
|
|||
RUN set -eux; \ |
|||
\ |
|||
apkArch="$(apk --print-arch)"; \ |
|||
case "$apkArch" in \ |
|||
'x86_64') \ |
|||
url='https://download.docker.com/linux/static/stable/x86_64/docker-20.10.15.tgz'; \ |
|||
;; \ |
|||
'armhf') \ |
|||
url='https://download.docker.com/linux/static/stable/armel/docker-20.10.15.tgz'; \ |
|||
;; \ |
|||
'armv7') \ |
|||
url='https://download.docker.com/linux/static/stable/armhf/docker-20.10.15.tgz'; \ |
|||
;; \ |
|||
'aarch64') \ |
|||
url='https://download.docker.com/linux/static/stable/aarch64/docker-20.10.15.tgz'; \ |
|||
;; \ |
|||
*) echo >&2 "error: unsupported architecture ($apkArch)"; exit 1 ;; \ |
|||
esac; \ |
|||
\ |
|||
wget -O docker.tgz "$url"; \ |
|||
\ |
|||
tar --extract \ |
|||
--file docker.tgz \ |
|||
--strip-components 1 \ |
|||
--directory /usr/local/bin/ \ |
|||
; \ |
|||
rm docker.tgz; \ |
|||
\ |
|||
dockerd --version; \ |
|||
docker --version |
|||
|
|||
COPY modprobe.sh /usr/local/bin/modprobe |
|||
COPY docker-entrypoint.sh /usr/local/bin/ |
|||
|
|||
ENV DOCKER_TLS_CERTDIR=/certs |
|||
RUN mkdir /certs /certs/client && chmod 1777 /certs /certs/client |
|||
|
|||
#ENTRYPOINT ["docker-entrypoint.sh"] |
|||
#CMD ["sh"] |
|||
|
|||
RUN set -eux; \ |
|||
apk add --no-cache \ |
|||
btrfs-progs \ |
|||
e2fsprogs \ |
|||
e2fsprogs-extra \ |
|||
ip6tables \ |
|||
iptables \ |
|||
openssl \ |
|||
shadow-uidmap \ |
|||
xfsprogs \ |
|||
xz \ |
|||
pigz \ |
|||
; \ |
|||
if zfs="$(apk info --no-cache --quiet zfs)" && [ -n "$zfs" ]; then \ |
|||
apk add --no-cache zfs; \ |
|||
fi |
|||
|
|||
ENV DIND_COMMIT 42b1175eda071c0e9121e1d64345928384a93df1 |
|||
RUN set -eux; \ |
|||
addgroup -S dockremap; \ |
|||
adduser -S -G dockremap dockremap; \ |
|||
echo 'dockremap:165536:65536' >> /etc/subuid; \ |
|||
echo 'dockremap:165536:65536' >> /etc/subgid; \ |
|||
wget -O /usr/local/bin/dind "https://raw.githubusercontent.com/docker/docker/${DIND_COMMIT}/hack/dind"; \ |
|||
chmod +x /usr/local/bin/dind; \ |
|||
sed -i '40i\nohup dockerd-entrypoint.sh > nohup.out 2>&1 &' /usr/local/bin/jenkins-agent; \ |
|||
mkdir -p /root/.docker; \ |
|||
echo $'{ \n\ |
|||
"auths": { \n\ |
|||
"repository.anxinyun.cn": { \n\ |
|||
"auth": "YWRtaW46SGFyYm9yMTIzNDU=" \n\ |
|||
} \n\ |
|||
} \n\ |
|||
}' >> /root/.docker/config.json |
|||
|
|||
COPY dockerd-entrypoint.sh /usr/local/bin/ |
|||
|
|||
VOLUME /var/lib/docker |
|||
EXPOSE 2375 2376 |
|||
|
|||
#ENTRYPOINT ["dockerd-entrypoint.sh"] |
|||
#CMD [] |
|||
|
|||
#RUN apk add --no-cache iproute2 |
|||
# |
|||
#RUN mkdir /run/user && chmod 1777 /run/user |
|||
# |
|||
#RUN set -eux; \ |
|||
# echo 'jenkins:100000:65536' >> /etc/subuid; \ |
|||
# echo 'jenkins:100000:65536' >> /etc/subgid |
|||
# |
|||
#RUN set -eux; \ |
|||
# \ |
|||
# apkArch="$(apk --print-arch)"; \ |
|||
# case "$apkArch" in \ |
|||
# 'x86_64') \ |
|||
# url='https://download.docker.com/linux/static/stable/x86_64/docker-rootless-extras-20.10.15.tgz'; \ |
|||
# ;; \ |
|||
# 'aarch64') \ |
|||
# url='https://download.docker.com/linux/static/stable/aarch64/docker-rootless-extras-20.10.15.tgz'; \ |
|||
# ;; \ |
|||
# *) echo >&2 "error: unsupported architecture ($apkArch)"; exit 1 ;; \ |
|||
# esac; \ |
|||
# \ |
|||
# wget -O rootless.tgz "$url"; \ |
|||
# \ |
|||
# tar --extract \ |
|||
# --file rootless.tgz \ |
|||
# --strip-components 1 \ |
|||
# --directory /usr/local/bin/ \ |
|||
# 'docker-rootless-extras/rootlesskit' \ |
|||
# 'docker-rootless-extras/rootlesskit-docker-proxy' \ |
|||
# 'docker-rootless-extras/vpnkit' \ |
|||
# ; \ |
|||
# rm rootless.tgz; \ |
|||
# \ |
|||
# rootlesskit --version; \ |
|||
# vpnkit --version |
|||
# |
|||
## pre-create "/var/lib/docker" for our rootless user |
|||
#RUN set -eux; \ |
|||
# mkdir -p /home/jenkins/.local/share/docker; \ |
|||
# chown -R jenkins:jenkins /home/jenkins/.local/share/docker; \ |
|||
# sed -i '40i\nohup dockerd-entrypoint.sh > nohup.out 2>&1 &' /usr/local/bin/jenkins-agent |
|||
#VOLUME /home/jenkins/.local/share/docker |
|||
|
|||
|
|||
|
|||
#USER jenkins |
|||
|
|||
|
@ -0,0 +1,61 @@ |
|||
#!/bin/sh |
|||
set -eu |
|||
|
|||
# first arg is `-f` or `--some-option` |
|||
if [ "${1#-}" != "$1" ]; then |
|||
set -- docker "$@" |
|||
fi |
|||
|
|||
# if our command is a valid Docker subcommand, let's invoke it through Docker instead |
|||
# (this allows for "docker run docker ps", etc) |
|||
if docker help "$1" > /dev/null 2>&1; then |
|||
set -- docker "$@" |
|||
fi |
|||
|
|||
_should_tls() { |
|||
[ -n "${DOCKER_TLS_CERTDIR:-}" ] \ |
|||
&& [ -s "$DOCKER_TLS_CERTDIR/client/ca.pem" ] \ |
|||
&& [ -s "$DOCKER_TLS_CERTDIR/client/cert.pem" ] \ |
|||
&& [ -s "$DOCKER_TLS_CERTDIR/client/key.pem" ] |
|||
} |
|||
|
|||
# if we have no DOCKER_HOST but we do have the default Unix socket (standard or rootless), use it explicitly |
|||
if [ -z "${DOCKER_HOST:-}" ] && [ -S /var/run/docker.sock ]; then |
|||
export DOCKER_HOST=unix:///var/run/docker.sock |
|||
elif [ -z "${DOCKER_HOST:-}" ] && XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" && [ -S "$XDG_RUNTIME_DIR/docker.sock" ]; then |
|||
export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/docker.sock" |
|||
fi |
|||
|
|||
# if DOCKER_HOST isn't set (no custom setting, no default socket), let's set it to a sane remote value |
|||
if [ -z "${DOCKER_HOST:-}" ]; then |
|||
if _should_tls || [ -n "${DOCKER_TLS_VERIFY:-}" ]; then |
|||
export DOCKER_HOST='tcp://docker:2376' |
|||
else |
|||
export DOCKER_HOST='tcp://docker:2375' |
|||
fi |
|||
fi |
|||
if [ "${DOCKER_HOST#tcp:}" != "$DOCKER_HOST" ] \ |
|||
&& [ -z "${DOCKER_TLS_VERIFY:-}" ] \ |
|||
&& [ -z "${DOCKER_CERT_PATH:-}" ] \ |
|||
&& _should_tls \ |
|||
; then |
|||
export DOCKER_TLS_VERIFY=1 |
|||
export DOCKER_CERT_PATH="$DOCKER_TLS_CERTDIR/client" |
|||
fi |
|||
|
|||
if [ "$1" = 'dockerd' ]; then |
|||
cat >&2 <<-'EOW' |
|||
|
|||
������ Hey there! It looks like you're trying to run a Docker daemon. |
|||
|
|||
You probably should use the "dind" image variant instead, something like: |
|||
|
|||
docker run --privileged --name some-docker ... docker:dind ... |
|||
|
|||
See https://hub.docker.com/_/docker/ for more documentation and usage examples. |
|||
|
|||
EOW |
|||
sleep 3 |
|||
fi |
|||
|
|||
exec "$@" |
@ -0,0 +1,198 @@ |
|||
#!/bin/sh |
|||
set -eu |
|||
|
|||
_tls_ensure_private() { |
|||
local f="$1"; shift |
|||
[ -s "$f" ] || openssl genrsa -out "$f" 4096 |
|||
} |
|||
_tls_san() { |
|||
{ |
|||
ip -oneline address | awk '{ gsub(/\/.+$/, "", $4); print "IP:" $4 }' |
|||
{ |
|||
cat /etc/hostname |
|||
echo 'docker' |
|||
echo 'localhost' |
|||
hostname -f |
|||
hostname -s |
|||
} | sed 's/^/DNS:/' |
|||
[ -z "${DOCKER_TLS_SAN:-}" ] || echo "$DOCKER_TLS_SAN" |
|||
} | sort -u | xargs printf '%s,' | sed "s/,\$//" |
|||
} |
|||
_tls_generate_certs() { |
|||
local dir="$1"; shift |
|||
|
|||
# if ca/key.pem || !ca/cert.pem, generate CA public if necessary |
|||
# if ca/key.pem, generate server public |
|||
# if ca/key.pem, generate client public |
|||
# (regenerating public certs every startup to account for SAN/IP changes and/or expiration) |
|||
|
|||
# https://github.com/FiloSottile/mkcert/issues/174 |
|||
local certValidDays='825' |
|||
|
|||
if [ -s "$dir/ca/key.pem" ] || [ ! -s "$dir/ca/cert.pem" ]; then |
|||
# if we either have a CA private key or do *not* have a CA public key, then we should create/manage the CA |
|||
mkdir -p "$dir/ca" |
|||
_tls_ensure_private "$dir/ca/key.pem" |
|||
openssl req -new -key "$dir/ca/key.pem" \ |
|||
-out "$dir/ca/cert.pem" \ |
|||
-subj '/CN=docker:dind CA' -x509 -days "$certValidDays" |
|||
fi |
|||
|
|||
if [ -s "$dir/ca/key.pem" ]; then |
|||
# if we have a CA private key, we should create/manage a server key |
|||
mkdir -p "$dir/server" |
|||
_tls_ensure_private "$dir/server/key.pem" |
|||
openssl req -new -key "$dir/server/key.pem" \ |
|||
-out "$dir/server/csr.pem" \ |
|||
-subj '/CN=docker:dind server' |
|||
cat > "$dir/server/openssl.cnf" <<-EOF |
|||
[ x509_exts ] |
|||
subjectAltName = $(_tls_san) |
|||
EOF |
|||
openssl x509 -req \ |
|||
-in "$dir/server/csr.pem" \ |
|||
-CA "$dir/ca/cert.pem" \ |
|||
-CAkey "$dir/ca/key.pem" \ |
|||
-CAcreateserial \ |
|||
-out "$dir/server/cert.pem" \ |
|||
-days "$certValidDays" \ |
|||
-extfile "$dir/server/openssl.cnf" \ |
|||
-extensions x509_exts |
|||
cp "$dir/ca/cert.pem" "$dir/server/ca.pem" |
|||
openssl verify -CAfile "$dir/server/ca.pem" "$dir/server/cert.pem" |
|||
fi |
|||
|
|||
if [ -s "$dir/ca/key.pem" ]; then |
|||
# if we have a CA private key, we should create/manage a client key |
|||
mkdir -p "$dir/client" |
|||
_tls_ensure_private "$dir/client/key.pem" |
|||
chmod 0644 "$dir/client/key.pem" # openssl defaults to 0600 for the private key, but this one needs to be shared with arbitrary client contexts |
|||
openssl req -new \ |
|||
-key "$dir/client/key.pem" \ |
|||
-out "$dir/client/csr.pem" \ |
|||
-subj '/CN=docker:dind client' |
|||
cat > "$dir/client/openssl.cnf" <<-'EOF' |
|||
[ x509_exts ] |
|||
extendedKeyUsage = clientAuth |
|||
EOF |
|||
openssl x509 -req \ |
|||
-in "$dir/client/csr.pem" \ |
|||
-CA "$dir/ca/cert.pem" \ |
|||
-CAkey "$dir/ca/key.pem" \ |
|||
-CAcreateserial \ |
|||
-out "$dir/client/cert.pem" \ |
|||
-days "$certValidDays" \ |
|||
-extfile "$dir/client/openssl.cnf" \ |
|||
-extensions x509_exts |
|||
cp "$dir/ca/cert.pem" "$dir/client/ca.pem" |
|||
openssl verify -CAfile "$dir/client/ca.pem" "$dir/client/cert.pem" |
|||
fi |
|||
} |
|||
|
|||
# no arguments passed |
|||
# or first arg is `-f` or `--some-option` |
|||
if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then |
|||
# set "dockerSocket" to the default "--host" *unix socket* value (for both standard or rootless) |
|||
uid="$(id -u)" |
|||
if [ "$uid" = '0' ]; then |
|||
dockerSocket='unix:///var/run/docker.sock' |
|||
else |
|||
# if we're not root, we must be trying to run rootless |
|||
: "${XDG_RUNTIME_DIR:=/run/user/$uid}" |
|||
dockerSocket="unix://$XDG_RUNTIME_DIR/docker.sock" |
|||
fi |
|||
case "${DOCKER_HOST:-}" in |
|||
unix://*) |
|||
dockerSocket="$DOCKER_HOST" |
|||
;; |
|||
esac |
|||
|
|||
# add our default arguments |
|||
if [ -n "${DOCKER_TLS_CERTDIR:-}" ] \ |
|||
&& _tls_generate_certs "$DOCKER_TLS_CERTDIR" \ |
|||
&& [ -s "$DOCKER_TLS_CERTDIR/server/ca.pem" ] \ |
|||
&& [ -s "$DOCKER_TLS_CERTDIR/server/cert.pem" ] \ |
|||
&& [ -s "$DOCKER_TLS_CERTDIR/server/key.pem" ] \ |
|||
; then |
|||
# generate certs and use TLS if requested/possible (default in 19.03+) |
|||
set -- dockerd \ |
|||
--host="$dockerSocket" \ |
|||
--host=tcp://0.0.0.0:2376 \ |
|||
--tlsverify \ |
|||
--tlscacert "$DOCKER_TLS_CERTDIR/server/ca.pem" \ |
|||
--tlscert "$DOCKER_TLS_CERTDIR/server/cert.pem" \ |
|||
--tlskey "$DOCKER_TLS_CERTDIR/server/key.pem" \ |
|||
"$@" |
|||
DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} -p 0.0.0.0:2376:2376/tcp" |
|||
else |
|||
# TLS disabled (-e DOCKER_TLS_CERTDIR='') or missing certs |
|||
set -- dockerd \ |
|||
--host="$dockerSocket" \ |
|||
--host=tcp://0.0.0.0:2375 \ |
|||
"$@" |
|||
DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} -p 0.0.0.0:2375:2375/tcp" |
|||
fi |
|||
fi |
|||
|
|||
if [ "$1" = 'dockerd' ]; then |
|||
# explicitly remove Docker's default PID file to ensure that it can start properly if it was stopped uncleanly (and thus didn't clean up the PID file) |
|||
find /run /var/run -iname 'docker*.pid' -delete || : |
|||
|
|||
if dockerd --version | grep -qF ' 20.10.'; then |
|||
# XXX inject "docker-init" (tini) as pid1 to workaround https://github.com/docker-library/docker/issues/318 (zombie container-shim processes) |
|||
set -- docker-init -- "$@" |
|||
fi |
|||
|
|||
if ! iptables -nL > /dev/null 2>&1; then |
|||
# if iptables fails to run, chances are high the necessary kernel modules aren't loaded (perhaps the host is using nftables with the translating "iptables" wrappers, for example) |
|||
# https://github.com/docker-library/docker/issues/350 |
|||
# https://github.com/moby/moby/issues/26824 |
|||
modprobe ip_tables || : |
|||
fi |
|||
|
|||
uid="$(id -u)" |
|||
if [ "$uid" != '0' ]; then |
|||
# if we're not root, we must be trying to run rootless |
|||
if ! command -v rootlesskit > /dev/null; then |
|||
echo >&2 "error: attempting to run rootless dockerd but missing 'rootlesskit' (perhaps the 'docker:dind-rootless' image variant is intended?)" |
|||
exit 1 |
|||
fi |
|||
user="$(id -un 2>/dev/null || :)" |
|||
if ! grep -qE "^($uid${user:+|$user}):" /etc/subuid || ! grep -qE "^($uid${user:+|$user}):" /etc/subgid; then |
|||
echo >&2 "error: attempting to run rootless dockerd but missing necessary entries in /etc/subuid and/or /etc/subgid for $uid" |
|||
exit 1 |
|||
fi |
|||
: "${XDG_RUNTIME_DIR:=/run/user/$uid}" |
|||
export XDG_RUNTIME_DIR |
|||
if ! mkdir -p "$XDG_RUNTIME_DIR" || [ ! -w "$XDG_RUNTIME_DIR" ] || ! mkdir -p "$HOME/.local/share/docker" || [ ! -w "$HOME/.local/share/docker" ]; then |
|||
echo >&2 "error: attempting to run rootless dockerd but need writable HOME ($HOME) and XDG_RUNTIME_DIR ($XDG_RUNTIME_DIR) for user $uid" |
|||
exit 1 |
|||
fi |
|||
if [ -f /proc/sys/kernel/unprivileged_userns_clone ] && unprivClone="$(cat /proc/sys/kernel/unprivileged_userns_clone)" && [ "$unprivClone" != '1' ]; then |
|||
echo >&2 "error: attempting to run rootless dockerd but need 'kernel.unprivileged_userns_clone' (/proc/sys/kernel/unprivileged_userns_clone) set to 1" |
|||
exit 1 |
|||
fi |
|||
if [ -f /proc/sys/user/max_user_namespaces ] && maxUserns="$(cat /proc/sys/user/max_user_namespaces)" && [ "$maxUserns" = '0' ]; then |
|||
echo >&2 "error: attempting to run rootless dockerd but need 'user.max_user_namespaces' (/proc/sys/user/max_user_namespaces) set to a sufficiently large value" |
|||
exit 1 |
|||
fi |
|||
# TODO overlay support detection? |
|||
exec rootlesskit \ |
|||
--net="${DOCKERD_ROOTLESS_ROOTLESSKIT_NET:-vpnkit}" \ |
|||
--mtu="${DOCKERD_ROOTLESS_ROOTLESSKIT_MTU:-1500}" \ |
|||
--disable-host-loopback \ |
|||
--port-driver=builtin \ |
|||
--copy-up=/etc \ |
|||
--copy-up=/run \ |
|||
${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} \ |
|||
"$@" |
|||
elif [ -x '/usr/local/bin/dind' ]; then |
|||
# if we have the (mostly defunct now) Docker-in-Docker wrapper script, use it |
|||
set -- '/usr/local/bin/dind' "$@" |
|||
fi |
|||
else |
|||
# if it isn't `dockerd` we're trying to run, pass it through `docker-entrypoint.sh` so it gets `DOCKER_HOST` set appropriately too |
|||
set -- docker-entrypoint.sh "$@" |
|||
fi |
|||
|
|||
exec "$@" |
@ -0,0 +1,5 @@ |
|||
#!/bin/sh |
|||
|
|||
nohup dockerd-entrypoint.sh > nohup.out 2>&1 & |
|||
/usr/local/bin/jenkins-agent |
|||
|
@ -0,0 +1,20 @@ |
|||
#!/bin/sh |
|||
set -eu |
|||
|
|||
# "modprobe" without modprobe |
|||
# https://twitter.com/lucabruno/status/902934379835662336 |
|||
|
|||
# this isn't 100% fool-proof, but it'll have a much higher success rate than simply using the "real" modprobe |
|||
|
|||
# Docker often uses "modprobe -va foo bar baz" |
|||
# so we ignore modules that start with "-" |
|||
for module; do |
|||
if [ "${module#-}" = "$module" ]; then |
|||
ip link show "$module" || true |
|||
lsmod | grep "$module" || true |
|||
fi |
|||
done |
|||
|
|||
# remove /usr/local/... from PATH so we can exec the real modprobe as a last resort |
|||
export PATH='/usr/sbin:/usr/bin:/sbin:/bin' |
|||
exec modprobe "$@" |
Reference in new issue