This source is used to build an image for hooktftp.
Project URL: https://github.com/jumanjihouse/docker-hooktftp
Registry: https://registry.hub.docker.com/u/jumanjiman/hooktftp/
The primary artifact is a docker image with the hooktftp
binary
and a default, minimal configuration.
The runtime image contains only:
- a static binary,
- a default config file,
/etc/nsswitch.conf
so golang net resolver uses/etc/hosts
,- CA certificates, and
/etc/passwd
to provide an unprivileged user.
The container runs as an unprivileged user via the technique described in this Medium post.
The goal is to provide a compromise between a single, monolithic tftpd image that contains all the things and a flexible tftpd image that contains just enough to combine with custom-built data containers or volumes an organization needs to bootstrap their infrastructure.
Table of Contents
An unattended test harness runs the build script and acceptance tests. If all tests pass on master branch in the unattended test harness, circleci pushes the built image to the Docker hub.
The CI scripts apply two tags before pushing to docker hub:
jumanjiman/hooktftp:latest
: latest successful build on master branchjumanjiman/hooktftp:<date>T<time>-<git-hash>
: a particular build on master branch
Therefore you can docker pull
a specific tag if you don't want latest.
The runtime image is published as jumanjiman/hooktftp
.
docker pull jumanjiman/hooktftp
Each built image has labels that generally follow http://label-schema.org/
We add a label, ci-build-url
, that is not currently part of the schema.
This extra label provides a permanent link to the CI build for the image.
View the ci-build-url label on a built image:
docker inspect \
-f '{{ index .Config.Labels "io.github.jumanjiman.ci-build-url" }}' \
jumanjiman/hooktftp
Query all the labels inside a built image:
docker inspect jumanjiman/hooktftp | jq -M '.[].Config.Labels'
The image contains the typical syslinux, efi, and pxelinux files
from syslinux at /tftpboot/
.
However, the image is built from scratch, so
the image does not have typical shell utilities.
List the files with:
ci/build
docker-compose run --rm list_files_in_tftpboot
Add helpers to track connections:
sudo modprobe nf_conntrack_tftp
sudo modprobe nf_nat_tftp
The container reads the config file /etc/hooktftp/hooktftp.yml
inside the container. You can use the default config provided
inside the image or provide
your own at runtime.
The published image contains just enough files to provide a base tftpd to PXE-boot your hosts to a simple menu. The simple menu and pxelinux.cfg/default only allow to skip PXE. Therefore you probably want to override the built-in menu.
Run a container with your own pxelinux.cfg
files:
docker run -d -p 69:69/udp \
-v /path/to/your/pxelinux.cfg:/tftpboot/pxelinux.cfg:ro \
jumanjiman/hooktftp
Run a container with default config and your data:
docker run -d -p 69:69/udp \
-v /path/to/your/files:/tftpboot:ro \
jumanjiman/hooktftp
Run a container with your own config and your own data:
docker run -d -p 69:69/udp \
-v /path/to/your/files:/tftpboot:ro \
-v /path/to/your/config/dir:/etc/hooktftp:ro \
jumanjiman/hooktftp
Use multiple volumes to add site-local boot files and menus in addition to the built-in syslinux files:
docker run -d -p 69:69/udp \
-v /path/to/your/pxelinux.cfg:/tftpboot/pxelinux.cfg:ro \
-v /path/to/your/bootfiles:/tftpboot/site:ro \
jumanjiman/hooktftp
You can add entries to /etc/hosts
via docker run --add-host
or via the docker-compose extra_hosts
option.
docker run -d -p 69:69/udp \
-v /path/to/your/pxelinux.cfg:/tftpboot/pxelinux.cfg:ro \
-v /path/to/your/bootfiles:/tftpboot/site:ro \
--add-host some-host.example.com:10.0.0.1 \
jumanjiman/hooktftp
Review and potentially modify the sample systemd unit file at
systemd/hooktftp.service
, then run:
sudo cp systemd/hooktftp.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl start hooktftp
sudo systemctl enable hooktftp
The build script(s) produce multiple artifacts:
Image Tag | Size | Purpose |
---|---|---|
hooktftp-runtime | 8 MB | run hooktftp as a service |
tftp | 6 MB | test the runtime container |
On a docker host, run:
ci/build
On a docker host, run:
ci/test
You can also test via the docker remote API if you have configured a remote docker host:
export DOCKER_HOST=tcp://<remote_ip>:<port>
ci/build
ci/test
Output from ci/test
resembles:
===> Run file checks.
[forbid-binary] Forbid binaries..........................................(no files to check)Skipped
[git-check] Check for conflict markers and core.whitespace errors............................Passed
[git-dirty] Check if the git tree is dirty...................................................Passed
[shellcheck] Test shell scripts with shellcheck..............................................Passed
[yamllint] yamllint..........................................................................Passed
[check-added-large-files] Check for added large files........................................Passed
[check-case-conflict] Check for case conflicts...............................................Passed
[check-executables-have-shebangs] Check that executables have shebangs.......................Passed
[check-json] Check JSON..................................................(no files to check)Skipped
[check-merge-conflict] Check for merge conflicts.............................................Passed
[check-xml] Check Xml....................................................(no files to check)Skipped
[check-yaml] Check Yaml......................................................................Passed
[detect-private-key] Detect Private Key......................................................Passed
[forbid-crlf] CRLF end-lines checker.........................................................Passed
[forbid-tabs] No-tabs checker................................................................Passed
===> Clean up from previous test runs.
[RUN] docker_rm tftp
[RUN] docker_rm tftpd
[RUN] docker_rm downloads
[RUN] docker_rm fixtures
===> Create data container in which to download test files.
[RUN] docker create --name downloads -v /home/user base_image true
19d787a81fa8cc3d68fdd97f0d7fa85d2d3f95fadcd144e52f47aafda74fb763
[RUN] docker run --rm --volumes-from downloads base_image chown -R 1000:1000 /home/user
===> Create data container for fixtures.
[RUN] docker create --name fixtures hooktftp-fixtures true
35887d1b1761350b9dda5dac398822d91d9e7375cd29ef2b88feb3e7b97d7d41
===> Start hooktftp server.
[RUN] docker run -d -p 69:69/udp --volumes-from fixtures --name tftpd hooktftp-runtime
28cd162ee8edbe314354ec09d5bbd65bb40350d977d41d9544f6d1482a98f144
Server is up at 172.17.0.3
===> Run BATS tests.
1..11
ok 1 hooktftp drops privileges
ok 2 downloads site/menu from fixtures
ok 3 downloads pxelinux.0
ok 4 does not download a non-existent-file
ok 5 downloads pxelinux.cfg/default
ok 6 downloads pxelinux.cfg/F1.msg
ok 7 hooktftp server log is meaningful
ok 8 file command is available
ok 9 scanelf command is available
ok 10 hooktftp binary is stripped
ok 11 hooktftp binary is statically compiled
ci/test OK
You can push the built image to a private docker registry:
docker tag hooktftp-runtime registry_id/your_id/hooktftp
docker push registry_id/your_id/hooktftp
See CONTRIBUTING.md
in this repo.
See LICENSE
in this repo.