Docker: Executing Startup Script When Running Container Interactively

PROBLEM

When running the Docker container interactively (ex: docker run --rm -it myimage), you want to run a startup script every time.

SOLUTION

For Ubuntu, Debian and Centos images, write the startup script to /root/.bashrc:

# UBUNTU
FROM ubuntu:latest
RUN echo "echo 'Welcome!'" >> /root/.bashrc
WORKDIR /home

# DEBIAN
FROM debian:latest
RUN echo "echo 'Welcome!'" >> /root/.bashrc
WORKDIR /home

# CENTOS
FROM centos:latest
RUN echo "echo 'Welcome!'" >> /root/.bashrc
WORKDIR /home

For Alpine image, it’s a little different because it uses Ash shell. Besides writing the startup script to /root/.profile, you also need to set that path to an environment variable called ENV:

FROM alpine:latest
ENV ENV=/root/.profile
RUN echo "echo 'Welcome!'" > $ENV
WORKDIR /home

Git: Querying Tags Without Cloning the Repository

PROBLEM

A typical way to get a list of tags from a repository is to clone it before running git tag:-

git clone git@ssh.dev.azure.com:v3/test/my-shitty-repo
cd my-shitty-repo
git -c 'versionsort.suffix=-' tag --sort='v:refname'

# output
1.0.0-b20200317174203
1.0.0
1.0.1-b20200318174753
1.0.1-b20200318174841
1.0.1-b20200407185909
1.0.1
1.0.2-b20200413205910
1.0.2

versionsort.suffix=- ensures 1.0.0-XXXXXX comes after 1.0.0.

To retrieve the latest tag:-

git clone git@ssh.dev.azure.com:v3/test/my-shitty-repo
cd my-shitty-repo
git -c 'versionsort.suffix=-' tag --sort='v:refname' |
tail -n1

# output
1.0.2

While it works, it requires us to clone the repository first, and if we want to retrieve tags from multiple repositories, we are quickly filling our hard drive space.

SOLUTION

Git has a way to perform a remote query through git ls-remote.

To perform the same task without cloning the repository, we can run this:-

git -c 'versionsort.suffix=-' ls-remote \
--tags \
--sort='v:refname' \
git@ssh.dev.azure.com:v3/test/my-shitty-repo

# output
b90df3d12413db22d051db1f7c7286cdd2f00b66	refs/tags/1.0.0-b20200317174203
e355a58829a2d2895ab2d7610fad1ab26dc0c1e7	refs/tags/1.0.0
345153c39a588a6ab2782772ee9dcf9f9123efa9	refs/tags/1.0.1-b20200318174753
efc40f0bd68bb8c7920be7700cab81db0e6bdf83	refs/tags/1.0.1-b20200318174841
efc40f0bd68bb8c7920be7700cab81db0e6bdf83	refs/tags/1.0.1-b20200407185909
c5ed5fe30cba621f40daa542c0613fa2c1c1a47d	refs/tags/1.0.1
7205ada5d8bd4318f82e58e8752ba651211f9d82	refs/tags/1.0.2-b20200413205910
6ba62a0f06f831812cbb13a6d1e83602ffe9e8d3	refs/tags/1.0.2

To retrieve the latest tag:-

git -c 'versionsort.suffix=-' ls-remote \
--tags \
--sort='v:refname' \
git@ssh.dev.azure.com:v3/test/my-shitty-repo |
tail -n1 |
sed -E 's|.*refs/tags/(.+)|\1|'

# output
1.0.2

RPM: Performing Offline Installation

PROBLEM

To perform an offline (or airgapped) installation, sometimes it’s not sufficient to download just the needed RPM package. In most cases, this package requires a list of dependencies to be installed too.

For example, Nginx requires at least 20 different packages in order for its installation to be successful:-

$ sudo yum deplist nginx
package: nginx.x86_64 1:1.16.1-1.el7
  dependency: /bin/sh
   provider: bash.x86_64 4.2.46-34.el7
  dependency: libc.so.6(GLIBC_2.17)(64bit)
   provider: glibc.x86_64 2.17-307.el7.1
  dependency: libcrypt.so.1()(64bit)
   provider: glibc.x86_64 2.17-307.el7.1
  ...
  ...
  ...
  dependency: system-logos
   provider: redhat-logos.noarch 70.7.0-1.el7
  dependency: systemd
   provider: systemd.x86_64 219-73.el7_8.8

SOLUTION

The first step to spin up an instance using the same Linux distro/version and this instance must have internet access.

Download the following yum plugin that allows the package(s) to be downloaded without installing them:-

sudo yum install yum-plugin-downloadonly

Download the needed package (in this case, Nginx) and its dependencies into a directory:-

sudo yum install --downloadonly --downloaddir=/tmp/nginx nginx

To inspect what’s being downloaded:-

$ ls -a /tmp/nginx | sort
.
..
dejavu-fonts-common-2.33-6.el7.noarch.rpm
dejavu-sans-fonts-2.33-6.el7.noarch.rpm
fontconfig-2.13.0-4.3.el7.x86_64.rpm
fontpackages-filesystem-1.44-8.el7.noarch.rpm
gd-2.0.35-26.el7.x86_64.rpm
gperftools-libs-2.6.1-1.el7.x86_64.rpm
libjpeg-turbo-1.2.90-8.el7.x86_64.rpm
libX11-1.6.7-2.el7.x86_64.rpm
libX11-common-1.6.7-2.el7.noarch.rpm
libXau-1.0.8-2.1.el7.x86_64.rpm
libxcb-1.13-1.el7.x86_64.rpm
libXpm-3.5.12-1.el7.x86_64.rpm
nginx-1.16.1-1.el7.x86_64.rpm
nginx-all-modules-1.16.1-1.el7.noarch.rpm
nginx-filesystem-1.16.1-1.el7.noarch.rpm
nginx-mod-http-image-filter-1.16.1-1.el7.x86_64.rpm
nginx-mod-http-perl-1.16.1-1.el7.x86_64.rpm
nginx-mod-http-xslt-filter-1.16.1-1.el7.x86_64.rpm
nginx-mod-mail-1.16.1-1.el7.x86_64.rpm
nginx-mod-stream-1.16.1-1.el7.x86_64.rpm
redhat-indexhtml-7-13.el7.noarch.rpm	

Now, this directory can be safely compressed into a tarball to be copied to the target instance without internet access.

After extracting the tarball in the target instance, it’s time to install the package:-

sudo yum -y --disablerepo=* localinstall /tmp/nginx/*.rpm

This command is smart enough to figure out all the dependencies within the directory and install them in the proper order.

Nginx: Requesting and Configuring SSL Certificate

INTRO

Step by step instructions for my future self to obtain the SSL certificate and to configure it in Nginx because my fragile little brain cannot retain them at the moment.

INSTRUCTIONS

Generate a private key and store it in a safe place.

openssl genrsa -out myshittycode_com.key 2048  

Generate a certificate signing request (CSR).

openssl req -new -sha256 \
  -key myshittycode_com.key \
  -out myshittycode_com.csr	\
  -subj "/C=US/ST=ShittyState/L=ShittyCity/OU=ShittyUnit/O=ShittyCompany/CN=myshittycode.com"	

Request a SSL certificate from Certificate Authority (ex: Sectigo) using the generated CSR.

If approved, you will receive an email similar to the below.

ssl-certificate

To configure the SSL certificate in Nginx, don’t use Certificate (w/ chain), PEM encoded because it contains the certificates in the following order:-

  • Root CA certificate
  • Intermediate CA certificate
  • Certificate

Nginx wants them in this order:-

  • Certificate
  • Root CA certificate
  • Intermediate CA certificate

To pull this off, download Certificate only, PEM encoded and Root/Intermediate(s) only, PEM encoded.

Then combine them into one file in the proper order.

cat myshittycode_com_cert.cer myshittycode_com_interm.cer > myshittycode_com_bundle.crt

In nginx.conf, add the bundle certificate, private key and server name.

server {
  listen               443;
  ssl                  on;
  ssl_certificate      /etc/pki/tls/certs/myshittycode_com_bundle.crt;
  ssl_certificate_key  /etc/pki/tls/private/myshittycode_com.key;
  server_name          myshittycode.com;

  location / {
    ...
  }
}

Restart Nginx service.