/viix-img

A minimal Ubuntu base image modified for Docker-friendliness

Primary LanguagePythonMIT LicenseMIT

viix : minimal Ubuntu base image modified for Docker-friendliness

Fork of phusion/baseimage-docker

Current version was based on ubuntu:22.04


Table of contents


Docker:

Use Dockerfile1

build

docker build -f image/Dockerfile1 -t viix:22.04 .

run

docker run -d --name new_container viix:22.04

run with SSH

docker run -d --name new_container -p 2222:22 viix:22.04

access into docker

winpty docker exec -it new_container bash

stop all active containers

docker stop $(docker ps -q)

Docker-compose:

run containers orchestration:

docker-compose up -d --build

stop containers orchestration:

docker-compose down --volumes

SSH:

SSH status

service ssh status

Location, where all SSH keys are automatically generated by script 00_regen_ssh_host_keys.sh (if SSH enabled):

cd /etc/ssh

SSH settings:

cat /etc/ssh/sshd_config

Container administration

One of the ideas behind Docker is that containers should be stateless, easily restartable, and behave like a black box. However, you may occasionally encounter situations where you want to login to a container, or to run a command inside a container, for development, inspection and debugging purposes. This section describes how you can administer the container for those purposes.

Running a one-shot command in a new container

Note: This section describes how to run a command insider a -new- container. To run a command inside an existing running container, see Running a command in an existing, running container.

Normally, when you want to create a new container in order to run a single command inside it, and immediately exit after the command exits, you invoke Docker like this:

docker run YOUR_IMAGE COMMAND ARGUMENTS...

However the downside of this approach is that the init system is not started. That is, while invoking COMMAND, important daemons such as cron and syslog are not running. Also, orphaned child processes are not properly reaped, because COMMAND is PID 1.

Baseimage-docker provides a facility to run a single one-shot command, while solving all of the aforementioned problems. Run a single command in the following manner:

docker run YOUR_IMAGE /sbin/my_init -- COMMAND ARGUMENTS ...

This will perform the following:

  • Runs all system startup files, such as /etc/my_init.d/* and /etc/rc.local.
  • Starts all runit services.
  • Runs the specified command.
  • When the specified command exits, stops all runit services.

For example:

$ docker run phusion/baseimage:<VERSION> /sbin/my_init -- ls
*** Running /etc/rc.local...
*** Booting runit daemon...
*** Runit started as PID 80
*** Running ls...
bin  boot  dev  etc  home  image  lib  lib64  media  mnt  opt  proc  root  run  sbin  selinux  srv  sys  tmp  usr  var
*** ls exited with exit code 0.
*** Shutting down runit daemon (PID 80)...
*** Killing all processes...

You may find that the default invocation is too noisy. Or perhaps you don't want to run the startup files. You can customize all this by passing arguments to my_init. Invoke docker run YOUR_IMAGE /sbin/my_init --help for more information.

The following example runs ls without running the startup files and with less messages, while running all runit services:

$ docker run phusion/baseimage:<VERSION> /sbin/my_init --skip-startup-files --quiet -- ls
bin  boot  dev  etc  home  image  lib  lib64  media  mnt  opt  proc  root  run  sbin  selinux  srv  sys  tmp  usr  var

Running a command in an existing, running container

There are two ways to run a command inside an existing, running container.

Both way have their own pros and cons, which you can learn in their respective subsections.

Login to the container, or running a command inside it, via SSH

You can use SSH to login to any container that is based on baseimage-docker. You can also use it to run a command inside a running container.

Here's how it compares to using docker exec to login to the container or to run a command inside it:

  • Pros
    • Does not require root privileges on the Docker host.
    • Allows you to let users login to the container, without letting them login to the Docker host. However, this is not enabled by default because baseimage-docker does not expose the SSH server to the public Internet by default.
  • Cons
    • Requires setting up SSH keys. However, baseimage-docker makes this easy for many cases through a pregenerated, insecure key. Read on to learn more.

Enabling SSH

Baseimage-docker disables the SSH server by default. Add the following to your Dockerfile to enable it:

RUN rm -f /etc/service/sshd/down

# Regenerate SSH host keys. baseimage-docker does not contain any, so you
# have to do that yourself. You may also comment out this instruction; the
# init system will auto-generate one during boot.
RUN /etc/my_init.d/00_regen_ssh_host_keys.sh

Alternatively, to enable sshd only for a single instance of your container, create a folder with a startup script. The contents of that should be

### In myfolder/enable_ssh.sh (make sure this file is chmod +x):
#!/bin/sh
rm -f /etc/service/sshd/down
ssh-keygen -P "" -t dsa -f /etc/ssh/ssh_host_dsa_key

Then, you can start your container with

docker run -d -v `pwd`/myfolder:/etc/my_init.d my/dockerimage

This will initialize sshd on container boot. You can then access it with the insecure key as below, or using the methods to add a secure key. Further, you can publish the port to your machine with -p 2222:22 allowing you to ssh to 127.0.0.1:2222 instead of looking up the ip address of the container.

About SSH keys

First, you must ensure that you have the right SSH keys installed inside the container. By default, no keys are installed, so nobody can login. For convenience reasons, we provide a pregenerated, insecure key (PuTTY format) that you can easily enable. However, please be aware that using this key is for convenience only. It does not provide any security because this key (both the public and the private side) is publicly available. In production environments, you should use your own keys.

Using the insecure key for one container only

You can temporarily enable the insecure key for one container only. This means that the insecure key is installed at container boot. If you docker stop and docker start the container, the insecure key will still be there, but if you use docker run to start a new container then that container will not contain the insecure key.

Start a container with --enable-insecure-key:

docker run YOUR_IMAGE /sbin/my_init --enable-insecure-key

Find out the ID of the container that you just ran:

docker ps

Once you have the ID, look for its IP address with:

docker inspect -f "{{ .NetworkSettings.IPAddress }}" <ID>

Now that you have the IP address, you can use SSH to login to the container, or to execute a command inside it:

# Download the insecure private key
curl -o insecure_key -fSL https://github.com/phusion/baseimage-docker/raw/master/image/services/sshd/keys/insecure_key
chmod 600 insecure_key

# Login to the container
ssh -i insecure_key root@<IP address>

# Running a command inside the container
ssh -i insecure_key root@<IP address> echo hello world

Enabling the insecure key permanently

It is also possible to enable the insecure key in the image permanently. This is not generally recommended, but is suitable for e.g. temporary development or demo environments where security does not matter.

Edit your Dockerfile to install the insecure key permanently:

RUN /usr/sbin/enable_insecure_key

Instructions for logging into the container is the same as in section Using the insecure key for one container only.

Using your own key

Edit your Dockerfile to install an SSH public key:

## Install an SSH of your choice.
COPY your_key.pub /tmp/your_key.pub
RUN cat /tmp/your_key.pub >> /root/.ssh/authorized_keys && rm -f /tmp/your_key.pub

Then rebuild your image. Once you have that, start a container based on that image:

docker run your-image-name

Find out the ID of the container that you just ran:

docker ps

Once you have the ID, look for its IP address with:

docker inspect -f "{{ .NetworkSettings.IPAddress }}" <ID>

Now that you have the IP address, you can use SSH to login to the container, or to execute a command inside it:

# Login to the container
ssh -i /path-to/your_key root@<IP address>

# Running a command inside the container
ssh -i /path-to/your_key root@<IP address> echo hello world

What are the problems with the stock Ubuntu base image?

Ubuntu is not designed to be run inside Docker. Its init system, Upstart, assumes that it's running on either real hardware or virtualized hardware, but not inside a Docker container. But inside a container you don't want a full system anyway, you want a minimal system. But configuring that minimal system for use within a container has many strange corner cases that are hard to get right if you are not intimately familiar with the Unix system model. This can cause a lot of strange problems.

Baseimage-docker gets everything right. The "Contents" section describes all the things that it modifies.

Why use baseimage-docker?

You can configure the stock ubuntu image yourself from your Dockerfile, so why bother using baseimage-docker?

Configuring the base system for Docker-friendliness is no easy task. As stated before, there are many corner cases. By the time that you've gotten all that right, you've reinvented baseimage-docker. Using baseimage-docker will save you from this effort.

  • It sets up the base system correctly. Many people may not think so, but Unix has many corner cases caused by decades of cruft. Getting them wrong can result in very strange problems. This image does everything correctly. Learn more.⁠
  • It reduces the time needed to run docker build, allowing you to iterate your Dockerfile more quickly.
  • It reduces download time during redeploys. Docker only needs to download the base image once: during the first deploy. On every subsequent deploys, only the changes you make on top of the base image are downloaded.

Contents

Baseimage-docker only contains essential components. Learn more about the rationale.⁠

Ubuntu 22.04 LTS as base system.

  • A correct init process learn more.
  • Fixes APT incompatibilities with Docker.
  • syslog-ng.
  • The cron daemon.
    • An optional SSH server (disabled by default), for those use cases where docker exec is inappropriate. Password and challenge-response authentication are disabled by default. Only key authentication is allowed.
    • It allows an predefined key by default to make debugging easy. You should replace this ASAP. See instructions.
    • Runit for service supervision and management.

Learn more

References: