diff --git a/Dockerfile b/Dockerfile index 24283c7..f69c325 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,28 +1,33 @@ -FROM debian:stable - -VOLUME /srv/releases/jenkins - -EXPOSE 873 +FROM debian:bookworm-20230814-slim ARG TINI_VERSION=v0.19.0 - -## URL source: COPY cannot be used -# hadolint ignore=DL3020 -ADD "https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini" /bin/tini - -RUN chmod +x /bin/tini - -COPY config/rsyncd.conf /etc/rsyncd.conf - -COPY config/jenkins.motd /etc/jenkins.motd - ## We always want the latest rsync version # hadolint ignore=DL3008 RUN apt-get update && \ - apt-get install -y --no-install-recommends rsync && \ + apt-get install --yes --no-install-recommends ca-certificates curl rsync && \ + curl --silent --show-error --location --output /bin/tini \ + "https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-$(dpkg --print-architecture)" && \ + chmod +x /bin/tini && \ + apt-get remove --purge --yes ca-certificates curl && \ + apt-get autoremove --purge --yes && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* -ENTRYPOINT ["/bin/tini", "--"] +ARG RSYNCD_DIR=/rsyncd +ENV RSYNCD_DIR="${RSYNCD_DIR}" +RUN mkdir -p "${RSYNCD_DIR}/run" "${RSYNCD_DIR}/data" /etc/rsyncd.d && \ + chown -R nobody:nogroup "${RSYNCD_DIR}" + +COPY rsyncd.conf /etc/rsyncd.conf + +WORKDIR /rsyncd/data + +VOLUME ["/rsyncd/run","/rsyncd/data","/tmp"] + +EXPOSE 873 + +USER nobody:nogroup + +ENTRYPOINT ["/bin/tini","--"] -CMD [ "/usr/bin/rsync","--no-detach","--daemon","--config","/etc/rsyncd.conf" ] +CMD ["/usr/bin/rsync", "--no-detach","--daemon","--config","/etc/rsyncd.conf"] diff --git a/Jenkinsfile_k8s b/Jenkinsfile_k8s index 9352471..218edac 100644 --- a/Jenkinsfile_k8s +++ b/Jenkinsfile_k8s @@ -1 +1 @@ -parallelDockerUpdatecli([imageName: 'rsyncd']) +parallelDockerUpdatecli([imageName: 'rsyncd', rebuildImageOnPeriodicJob: false, buildDockerConfig : [targetplatforms: 'linux/amd64,linux/arm64']]) diff --git a/README.md b/README.md index 49bd5c6..064392b 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,40 @@ # README -This docker image is a rsync daemon, that serve files from directory /srv/releases/jenkins +This docker image is a rsync daemon, that serve files from directory /srv/releases/jenkins -## Testing +## Build the image -* `make run` -* `make shell` +```shell +docker build --tag rsyncd ./ +``` -`make test`, test that we can download, and more importantly that we can't upload +## Test the image + +- Unit testing the image with [`container-structure-test`](https://github.com/GoogleContainerTools/container-structure-test): + +```shell +container-structure-test test --image=rsyncd --config=cst.yml +``` + +- Manual acceptance testing of the the image with [`docker compose`](https://docs.docker.com/compose/): + +```shell +$ cd ./tests +$ docker compose up --build --detach +$ sleep 2 +$ rsync -av rsync://localhost:1873/jenkins +======================== +==== JENKINS MIRROR ==== +======================== + +**Read Only** + +Feel free to reach out on https://www.jenkins.io/chat/#jenkins-infra/ with any question you may have + +receiving file list ... done +drwxr-xr-x 96 2023/08/31 20:24:33 . +-rw-r--r-- 12 2023/08/31 20:24:37 sample.txt + +sent 16 bytes received 111 bytes 254.00 bytes/sec +total size is 12 speedup is 0.09 +``` diff --git a/config/rsyncd.conf b/config/rsyncd.conf deleted file mode 100644 index f338a63..0000000 --- a/config/rsyncd.conf +++ /dev/null @@ -1,34 +0,0 @@ -# /etc/rsyncd: configuration file for -rsync daemon mode - -# See rsyncd.conf man page for more options. - -# configuration example: - -uid = nobody -gid = nogroup -use chroot = yes -max connections = 0 -pid file = /var/run/rsyncd.pid -exclude = lost+found/ -transfer logging = yes -log file = /dev/stdout -ignore nonreadable = yes -dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2 -port = 873 -motd file = /etc/jenkins.motd - -# Timeout in seconds -timeout = 300 - -# Any attempted uploads will fail -read only = true - -# Downloads will be possible if file permissions on the daemon side allow them -write only = false - -hosts allow = localhost, get.jenkins.io, mirrors.jenkins-ci.org,172.16.0.0/12,10.0.0.0/8,192.168.0.0/16 - -[jenkins] -path = /srv/releases/jenkins -comment = "Jenkins Read-Only Mirror" diff --git a/cst.yml b/cst.yml new file mode 100644 index 0000000..6838c65 --- /dev/null +++ b/cst.yml @@ -0,0 +1,50 @@ +schemaVersion: 2.0.0 + +metadataTest: + entrypoint: ["/bin/tini", "--"] + cmd: ["/usr/bin/rsync","--no-detach","--daemon","--config","/etc/rsyncd.conf"] + exposedPorts: + - "873" + user: nobody:nogroup + volumes: ["/rsyncd/data", "/rsyncd/run", "/tmp"] + workdir: /rsyncd/data + +fileExistenceTests: + - name: "Rsyncd configuration file" + path: "/etc/rsyncd.conf" + shouldExist: true + uid: 0 + gid: 0 + - name: "Rsyncd configuration dir" + path: "/etc/rsyncd.d" + shouldExist: true + uid: 0 + gid: 0 + - name: "Tini process wrapper" + path: "/bin/tini" + shouldExist: true + isExecutableBy: "any" + uid: 0 + gid: 0 + - name: "Rsync" + path: "/usr/bin/rsync" + shouldExist: true + isExecutableBy: "any" + uid: 0 + gid: 0 + - name: "Rsync run dir" + path: "/rsyncd/data" + shouldExist: true + uid: 65534 + gid: 65534 + - name: "Rsync data dir" + path: "/rsyncd/run" + shouldExist: true + uid: 65534 + gid: 65534 + +commandTests: + - name: "Tini is installed with the correct version" + command: "tini" + args: ["--version"] + expectedOutput: ["0.19.0"] diff --git a/rsyncd.conf b/rsyncd.conf new file mode 100644 index 0000000..537f7b2 --- /dev/null +++ b/rsyncd.conf @@ -0,0 +1,28 @@ +# /etc/rsyncd: configuration file for +rsync daemon mode + +# See rsyncd.conf man page for more options. + +### Inside a restricted Docker container, no need to chroot / setuid / setgid +### You can override through the conf.d directory +# uid = nobody +# gid = nogroup +# use chroot = yes + +max connections = 0 + +exclude = lost+found/ +transfer logging = yes +log file = /dev/stdout +ignore nonreadable = yes +dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2 +port = 873 +pid file = /rsyncd/run/rsyncd.pid + +# Timeout in seconds +timeout = 300 + +# Merge any /etc/rsyncd.d/*.inc files (for global values that should stay in effect), +&merge /etc/rsyncd.d +# And then include any /etc/rsyncd.d/*.conf files (defining modules without any global-value cross-talk). +&include /etc/rsyncd.d diff --git a/tests/data/jenkins/sample.txt b/tests/data/jenkins/sample.txt new file mode 100644 index 0000000..557db03 --- /dev/null +++ b/tests/data/jenkins/sample.txt @@ -0,0 +1 @@ +Hello World diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml new file mode 100644 index 0000000..f8cf3b5 --- /dev/null +++ b/tests/docker-compose.yml @@ -0,0 +1,15 @@ +# Start this "lightly hardened" test with the command "docker compose up -d --build" +# Then check the result with the command "rsync -av rsync://localhost:1873/jenkins" +# which should shows the sample.txt file with the motd as header + +services: + rsyncd-readonly-jenkins: + build: ../ + read_only: true + user: 65534:65534 # nobody:nogroup + volumes: + - ./data:/rsyncd/data:ro + - ./rsyncd.d:/etc/rsyncd.d:ro + - ./jenkins.motd:/etc/jenkins.motd:ro + ports: + - 1873:873 diff --git a/config/jenkins.motd b/tests/jenkins.motd similarity index 100% rename from config/jenkins.motd rename to tests/jenkins.motd diff --git a/tests/rsyncd.d/jenkins.conf b/tests/rsyncd.d/jenkins.conf new file mode 100644 index 0000000..79aef93 --- /dev/null +++ b/tests/rsyncd.d/jenkins.conf @@ -0,0 +1,3 @@ +[jenkins] +path = /rsyncd/data/jenkins +comment = "Jenkins Read-Only Mirror" diff --git a/tests/rsyncd.d/rsyncd.inc b/tests/rsyncd.d/rsyncd.inc new file mode 100644 index 0000000..58ecae3 --- /dev/null +++ b/tests/rsyncd.d/rsyncd.inc @@ -0,0 +1,7 @@ +## Read Only Service +# Any attempted uploads will fail +read only = true +# Downloads will be possible if file permissions on the daemon side allow them +write only = false + +motd file = /etc/jenkins.motd