How’s it going, good I hope!, Hope this year is a blast for you.
What is this?
Creating a preconfigured container for a precompiled binary utilizing docker.
Reason / Motivation:
I’ve been using hugo, even since my blog migration post, the one problem that I am facing with hugo is that,
- whenever I run update os host system,hugo version also updates, the problem with that is some features are deprecated in the new release, my site design depends upon those features. so what I was doing is constantly degrading the hugo version back to old version, before I write a post everytime.
- I work in new environments all the time, so downloading the appropriate version and installing takes time.
goal
At the end of this venture, I should be able to
- create a image from scratch
- install a required binary with its dependencies, either using source or binary distribution
- create a container from the image and export it
- upload the container image to a docker hub or something similar
- setup an environment using the container
- link the local binary executable to the binary inside the container
- whenever I run the binary locally, the binary inside the container should be executed on the files from the host system’s current path.
- I should be able to run the binary, with or without its parameters and environment options
Is this even possible?
what I am trying to achieve is completely possible using docker, its a feature completely baked into the docker core, using ‘–rm’ with ‘docker -run’
Lets start
Choosing the best base image, I recommend alpine.
why?
Alpine Linux is a Linux distribution built around musl libc and BusyBox. The image is only 5 MB in size and has access to a package repository
Set up a container from alpine
aghontpi@elitebook:~$ docker run --name testalpine -d -it alpine:latest /bin/sh
1be3fb1ba1c46786dc5034745dcdab31c6588627c086c08f3c0ff8493d270544
aghontpi@elitebook:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1be3fb1ba1c4 alpine:latest "/bin/sh" 4 seconds ago Up 3 seconds testalpine
Login to the shell to install your binary
aghontpi@elitebook:~$ docker exec -it testalpine /bin/sh
/ # whoami
root
/ # apk update
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/community/x86_64/APKINDEX.tar.gz
v3.13.2-8-g7bb1c88019 [https://dl-cdn.alpinelinux.org/alpine/v3.13/main]
v3.13.2-9-gd3529c068e [https://dl-cdn.alpinelinux.org/alpine/v3.13/community]
OK: 13884 distinct packages available
/ # apk list vim
vim-8.2.2320-r0 x86_64 {vim} (Vim)
/ # apk add --no-cache vim
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/community/x86_64/APKINDEX.tar.gz
(1/5) Installing xxd (8.2.2320-r0)
(2/5) Installing lua5.3-libs (5.3.6-r0)
(3/5) Installing ncurses-terminfo-base (6.2_p20210109-r0)
(4/5) Installing ncurses-libs (6.2_p20210109-r0)
(5/5) Installing vim (8.2.2320-r0)
Executing busybox-1.32.1-r0.trigger
OK: 25 MiB in 19 packages
/ # vim test
/ # cd home
/home # wget https://github.com/gohugoio/hugo/releases/download/v0.56.3/hugo_0.56.3_Linux-64bit.tar.gz
Connecting to github.com (13.234.210.38:443)
Connecting to github-releases.githubusercontent.com (185.199.108.154:443)
saving to 'hugo_0.56.3_Linux-64bit.tar.gz'
hugo_0.56.3_Linux-64 100% |*********************************************************************************************************************************************************************************************************************************| 11.4M 0:00:00 ETA
'hugo_0.56.3_Linux-64bit.tar.gz' saved
/home # ls
hugo_0.56.3_Linux-64bit.tar.gz
/home # tar -xf hugo_0.56.3_Linux-64bit.tar.gz
/home # ls
LICENSE README.md hugo hugo_0.56.3_Linux-64bit.tar.gz
/home # cp hugo /usr/bin/
/home # mkdir test
/home # cd test/hugo
/home # ls
LICENSE README.md hugo hugo_0.56.3_Linux-64bit.tar.gz test
/home # cd test/
/home/test # hugo
Building sites … WARN 2021/02/19 16:52:24 found no layout file for "HTML" for "taxonomyTerm": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
WARN 2021/02/19 16:52:24 found no layout file for "HTML" for "home": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
WARN 2021/02/19 16:52:24 found no layout file for "HTML" for "taxonomyTerm": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
| EN
+------------------+----+
Pages | 3
Paginator pages | 0
Non-page files | 0
Static files | 0
Processed images | 0
Aliases | 0
Sitemaps | 1
Cleaned | 0
Total in 4 ms
/home/test # ls
public resources
/home/test # cd ..
/home # ls
LICENSE README.md hugo hugo_0.56.3_Linux-64bit.tar.gz test
/home # rm -rf ./*
/home # exit
aghontpi@elitebook:~$
aghontpi@elitebook:~$ docker container stop testalpine
testalpine
aghontpi@elitebook:~$ docker commit testalpine testalpinewithhugo/0.1
sha256:c305edf7f82a912801ae44dfe6ffe9e834e0541728295c2968ef69ad2ba9e90f
aghontpi@elitebook:~$ docker image ls testalpinewithhugo/0.1
REPOSITORY TAG IMAGE ID CREATED SIZE
testalpinewithhugo/0.1 latest c305edf7f82a 14 seconds ago 60.1MB
Host the image remotely in a service of your choice.
Then use services like docker-hub to your private repo, it will look like below.
Shell script to orchestrate the whole thing.
Didn’t want to brushup my sheel script so wrote a python script and used it as executable instead.
#! /usr/bin/python3
import os
calling_directory = os.getcwd()
cmd = f"docker run --rm -it \
--user $(id -u):$(id -g) \
-v '/etc/group:/etc/group:ro' \
-v '/etc/passwd:/etc/passwd:ro' \
-v '/etc/shadow:/etc/shadow:ro'
-v {calling_directory}/:/tmp/ \
-e HUGO_ENV \
-p 80:1313 \
bluepie/hugo:0.1 \
/bin/sh -c 'cd /tmp/ && hugo " + ' '.join(sys.argv[1:]) +" '"
print(cmd)
os.system(cmd)
Finally Installation script
The code is verbose, so check it out through the link.
what the script does..
- check if hugo and docker is already installed
- create .bin directory inside $HOME
- downloads the code and places it as executable inside $HOME/.bin/hugo
- adds the path $HOME/.bin to .bashrc
Script in action
aghontpi@elitebook:/tmp$ ./install-script.py
> docker-hugo custom binary script v0.0.1
> docker is installed proceeding..
> hugo does not exists, initiating docker pull and installation
> authenticating /w docker, enter credential when asked
Authenticating with existing credentials...
WARNING! Your password will be stored unencrypted in /home/aghontpi/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
> pulling from docker repo
0.1: Pulling from bluepie/hugo
Digest: sha256:db54d94cfb7ad12726b1ee9f5fa7b2a2ad9d7e567021886fe2dd74e4262a43ea
Status: Image is up to date for bluepie/hugo:0.1
docker.io/bluepie/hugo:0.1
> getting the custom script
> writing to disc
> setting permission
> backup cmd -> cp /home/aghontpi/.bashrc /home/aghontpi/.bashrc_bkp_19022021-21:20:15
> modifying bashrc of user
> installation complete
---> use a new terminal to test <---
aghontpi@elitebook:/tmp$
End
I learned a lot through this little experiment, It saves a ton of my time.