TL;DR: For short answer please see the other author's Answer.
My question was wrong here because it doesn't align with the containerization philosophy IMO. As these kinds of questions would be asked by new user I am going to explain a few things that's indirectly related to this question.
What is a container?
From OCI's runtime Specification, approximately,
- A container contains the unit of a deliverable software.
- A container will encapsulate a software component and it's dependencies.
- A container should be portable and platform agnostic.
And one of the major component to achieve containerization is container runtime
or in general linux container
. Container runtime is a piece of software that is responsible for running containers.
Examples of a few container runtimes are, containerd
, docker-engine
, crio
, mcr
etc.
Why the question is wrong?
In general and by design, a linux container is an isolated process (these days virtual machines are also considered as containers). So in an ideal situation we should create a container just with one process which is our deliverable software.
In the question, I was thinking of using systemd
to manage the process inside the container because I was neither aware about difference between a virtual machine and a container nor the principles of OCI's specification.
Also, systemd
or systemV
is system management daemon that is required to manage systems with hundreds or thousands of process. As the desired number of process in a container is only one so we do not need a process management daemon or any other unnecessary tools like ssh
, htop
, net-tools
, firewalld
etc.
How do we run the deliverable software?
The ideal way to run an application inside the container is to use it as the container's Entrypoint
or CMD
. That means, when we run the container, it will try to initiate the Entrypoint and it will start it with default command defined in the CMD
. Either way, the first process (PID 1) should be our desired application/software.
So when we build the container image, we should define the entrypoint of that container. For example, I have an httpd
and a redis
container.
╰──➤ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
23789e2d0416 redis "docker-entrypoint.s…" 36 seconds ago Up 35 seconds 6379/tcp elegant_ganguly
9be725968ff3 httpd "httpd-foreground" 14 minutes ago Up 14 minutes 80/tcp app1
So let's check the first process of the both containers (cat /proc/1/cmdline
),
╰──➤ for i in $(docker ps -q); do docker inspect $i --format 'ImageName: {{.Config.Image}}'; printf "First PID: "; docker exec -i $i sh -c "cat /proc/1/cmdline";echo; done
ImageName: redis
First PID: redis-server *:6379
ImageName: httpd
First PID: httpd-DFOREGROUND
Let's try to see the same thing with ps
╰──➤ for i in $(docker ps -q); do docker inspect $i --format 'ImageName: {{.Config.Image}}'; docker run -i --rm --pid container:$i ubuntu sh -c "ps aux | head -n2"; done
ImageName: redis
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
999 1 0.4 0.0 56024 7760 ? Ssl 14:58 0:08 redis-server *:6379
ImageName: httpd
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 7300 4380 ? Ss 14:44 0:00 httpd -DFOREGROUND
So if we are using these images; majority of the time we do not need to start it separately because it's probably already invoked by the entrypoint.
But if we want to create our own container image for our own software we can do that just by mentioning the entrypoint like the both of the httpd
and redis
image did here and here. You can also use CMD
and Entrypoint
from the command line when you run the container with the help of --entrypoint
or provide the command after container name like the following (here I am using while true; do date; sleep 1; done
as the default CMD
),
╰──➤ docker run -d --rm ubuntu sh -c "while true; do date; sleep 1; done"
35c6352a55f25335e1bd0874493f2a31155ef752d008eb6718923d1f04ab2c14
Now let's check the first PID,
╰──➤ docker run -i --rm --pid container:35c6352a55f25 ubuntu sh -c "ps aux | head -n2"
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 2308 832 ? Ss 15:42 0:00 sh -c while true; do date; sleep 1; done