Running systemd in docker container causes host crash - docker

I'm trying to create a systemd based docker container, but when I try running the built container my system crashes. I think running init in the container might be causing the conflict, and is somehow conflicting with systemd on my host.
When I try to run the docker container I am logged out of my account and briefly see what looks like my system going through a boot process. My host is running Arch Linux, with linux 4.20.7.
It is only when I attempt to "boot" the container by running systemd via /sbin/init, that the problem occurs.
docker run -it \
--volume=/sys/fs/cgroup:/sys/fs/cgroup:rw \
--privileged 66304e3bc48
Dockerfile (adapted from solita/ubuntu-systemd):
FROM ubuntu:18.04
# Don't start any optional services.
RUN find /etc/systemd/system \
/lib/systemd/system \
-path '*.wants/*' \
-not -name '*journald*' \
-not -name '*systemd-tmpfiles*' \
-not -name '*systemd-user-sessions*' \
-exec rm \{} \;
RUN apt-get update && \
apt-get install --yes \
python sudo bash ca-certificates dbus systemd && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN systemctl set-default multi-user.target
RUN systemctl mask dev-hugepages.mount sys-fs-fuse-connections.mount
STOPSIGNAL SIGRTMIN+3
# Workaround for docker/docker#27202, technique based on comments from docker/docker#9212
CMD ["/bin/bash", "-c", "exec /sbin/init --log-target=journal 3>&1"]
I would expect the container to just boot up running systemd, and I'm not your what I might be doing wrong.

Docker do not want to include by default Systemd inside docker because it publish itself as an application container (which means one application per container). There is an other type of containers called system containers. the most known are OpenVZ , LXC/LXD and Systemd-nspawn. all those will run a full OS with systemd as if it were a virtual machine.
and using systemd inside docker is so dangerous when compared to running systemd inside LXD
there is even a new baby called Podman which is a clone of docker but it uses by default systemd inside when you install it or when you use an image which contain systemd already like those of ubuntu cloud images http://uec-images.ubuntu.com/releases/server/bionic/release/
so my advice is to test LXD and systemd-nspawn ; and keep an eye on Podman it solves what docker do not want to solve; read this to understand https://lwn.net/Articles/676831/
references:
https://coreos.com/rkt/docs/latest/rkt-vs-other-projects.html
https://podman.io/slides/2018_10_01_Replacing_Docker_With_Podman.pdf
https://containerjournal.com/features/system-containers-vs-application-containers-difference-matter
Runtimes And the Curse of the Privileged Container
https://brauner.github.io/2019/02/12/privileged-containers.html

I ended up using the paulfantom/ubuntu-molecule Docker image.
Currently it looks like they're just installing systemd, setting some environment variables, and using the systemd binary directly as the entry point. It seems to work without the issues I mentioned in the original post.
Dockerfile
FROM ubuntu:18.04
ENV container docker
ENV LC_ALL C
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/# deb/deb/g' /etc/apt/sources.list
# hadolint ignore=DL3008
RUN apt-get update \
&& apt-get install -y --no-install-recommends systemd python sudo bash iproute2 net-tools \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# hadolint ignore=SC2010,SC2086
RUN cd /lib/systemd/system/sysinit.target.wants/ \
&& ls | grep -v systemd-tmpfiles-setup | xargs rm -f $1
RUN rm -f /lib/systemd/system/multi-user.target.wants/* \
/etc/systemd/system/*.wants/* \
/lib/systemd/system/local-fs.target.wants/* \
/lib/systemd/system/sockets.target.wants/*udev* \
/lib/systemd/system/sockets.target.wants/*initctl* \
/lib/systemd/system/basic.target.wants/* \
/lib/systemd/system/anaconda.target.wants/* \
/lib/systemd/system/plymouth* \
/lib/systemd/system/systemd-update-utmp*
RUN systemctl set-default multi-user.target
ENV init /lib/systemd/systemd
VOLUME [ "/sys/fs/cgroup" ]
ENTRYPOINT ["/lib/systemd/systemd"]

To "match the host as close as possible" was the original goal of the docker-systemctl-replacement script. You can test drive scripts in a container that may be run later on a virtual machine. It allows to do some systemctl commands without an active systemd daemon.
It can also serve as an init daemon if you wish to. A systemd-enabled operating system will feel quite similar inside a container with it.

Related

Issues running a docker container with a GUI application with host network mode

I am trying to create a docker container with a ROS install and a simulation setup to streamline the process for people joining the project later.
When I run rviz this way, I get the rviz window showing up on my host just fine, as expected following this ros tutorial:
sudo docker run -it --env="DISPLAY" --env="QT_X11_NO_MITSHM=1" --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" xrf-robot-repo rviz
ROS Master isn't running so this output is expected
Now my issue is that I want to run my container in the host network mode (--net=host) the rviz dialogue does not show up anymore. Here's what I run this:
sudo docker run -it --env="DISPLAY" --env="QT_X11_NO_MITSHM=1" --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" --net=host xrf-robot-repo rviz I don't think these errors have anything to do with the gui window not showing up
I have no idea why the GUI window does not show up. I was hoping for some guidance here. I would guess this would have something to do with the different network mode affecting how the x11 forwarding may work, but I am not sure how to further look into this.
Here's what my Dockerfile looks like that I used to build the image in case it may be helpful:
FROM osrf/ros:melodic-desktop-full
SHELL ["/bin/bash", "-c"]
RUN apt-get update && apt-get install -y --no-install-recommends \
git apt-utils python3-catkin-tools\
&& rm -rf /var/lib/apt/lists/*
RUN source ./ros_entrypoint.sh && git clone https://github.com/RumailM/xrf-robot-stack
RUN source ./ros_entrypoint.sh && cd xrf-robot-stack && catkin_init_workspace
RUN apt-get update
ARG DEBIAN_FRONTEND=noninteractive
RUN source ./ros_entrypoint.sh && cd xrf-robot-stack && rosdep install
--from-paths src --ignore-src -r -y
RUN source ./ros_entrypoint.sh && cd xrf-robot-stack && catkin build
The reason I need to use network mode is that I would like the host to be able to communicate with the rosmaster node and any other nodes within the container. I also do not know before hand what nodes may exist outside the container and at what ports they may communicate on, so the obvious answer of forwarding only the ports that I will use will not work (the ports may change at runtime). Forwarding large ranges of ports does not seem viable either.
Any guidance is appreciated!
You should add --privileged option to the docker run command. This is related to this issue Qt applications and network host .
I ran into a similar issue and was able to resolve by following this question on ROS Answers.
Also to be able to run rviz properly, I needed the docker container to access my graphics card drivers(NVIDIA) in my case. So I needed to add -e NVIDIA_VISIBLE_DEVICES=all and -e NVIDIA_DRIVER_CAPABILITIES=all and --runtime nvidia to the docker run command.
This was the final run command
docker run -it --rm \
--privileged \
--network host \
-e NVIDIA_VISIBLE_DEVICES=all \
-e NVIDIA_DRIVER_CAPABILITIES=all \
--env="DISPLAY" \
--env="QT_X11_NO_MITSHM=1" \
--volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \
--name "$CONTAINER_NAME" \
--runtime nvidia \
xrf-robot-repo \
/bin/bash
Hope this helps

Installing Kubernetes in Docker container

I want to use Kubeflow to check it out and see if it fits my projects. I want to deploy it locally as a development server so I can check it out, but I have Windows on my computer and Kubeflow only works on Linux. I'm not allowed to dual boot this computer, I could install a virtual machine, but I thought it would be easier to use docker, and oh boy was I wrong. So, the problem is, I want to install Kubernetes in a docker container, right now this is the Dockerfile I've written:
# Docker file with local deployment of Kubeflow
FROM ubuntu:18.04
ENV USER=Joao
ENV PASSWORD=Password
ENV WK_DIR=/home/${USER}
# Setup Ubuntu
RUN apt-get update -y
RUN apt-get install -y conntrack sudo wget
RUN useradd -rm -d /home/${USER} -s /bin/bash -g root -G sudo -u 1001 -p ${PASSWORD} ${USER}
WORKDIR ${WK_DIR}
# Installing Docker CE
RUN apt-get install -y apt-transport-https ca-certificates curl software-properties-common
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
RUN add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
RUN apt-get update -y
RUN apt-get install -y docker-ce docker-ce-cli containerd.io
# Installing Kubectl
RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.15.0/bin/linux/amd64/kubectl
RUN chmod +x ./kubectl
RUN mv ./kubectl /usr/local/bin/kubectl
# Installing Minikube
RUN curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
RUN install minikube-linux-amd64 /usr/local/bin/minikube
ENV PATH="${PATH}:${WK_DIR}"
COPY start.sh start.sh
CMD sh start.sh
With this, just to make the deployment easier, I also have a docker-compose.yaml that looks like this:
services:
kf-local:
build: .
volumes:
- path/to/folder:/usr/kubeflow
privileged: true
And start.sh looks like this:
service docker start
minikube start \
--extra-config=apiserver.service-account-issuer=api \
--extra-config=apiserver.service-account-signing-key-file=/var/lib/minikube/certs/apiserver.key \
--extra-config=apiserver.service-account-api-audiences=api \
--driver=docker
The problem is, whenever I try running this I get the error:
X Exiting due to DRV_AS_ROOT: The "docker" driver should not be used with root privileges.
I've tried creating a user and running it from there also but then I'm not being able to run sudo, any idea how I could install Kubernetes on a Docker container?
As you thought you are right in case of using VM and that be easy to test it out.
Instead of setting up Kubernetes on docker you can use Linux base container for development testing.
There is linux container available name as LXC container. Docker is kind of application container while in simple words LXC is like VM for local development testing. you can install the stuff into rather than docker setting up application inside image.
read some details about lxc : https://medium.com/#harsh.manvar111/lxc-vs-docker-lxc-101-bd49db95933a
you can also run it on windows and try it out at : https://linuxcontainers.org/
If you have read the documentation of Kubeflow there is also one option multipass
Multipass creates a Linux virtual machine on Windows, Mac or Linux
systems. The VM contains a complete Ubuntu operating system which can
then be used to deploy Kubernetes and Kubeflow.
Learn more about Multipass : https://multipass.run/#install
Insufficient user permissions on the docker groups and minikube directory cause this error ("X Exiting due to DRV_AS_ROOT: The "docker" driver should not be used with root privileges.").
You can fix that error by adding your user to the docker group and setting permissions to the minikube profile directory (change the $USER with your username in the two commands below):
sudo usermod -aG docker $USER && newgrp docker
sudo chown -R $USER $HOME/.minikube; chmod -R u+wrx $HOME/.minikube

How To Start MariaDB And Keep it Running Centos Based Docker Image

I'm trying to create a docker file (base os must be Centos) that will install mariadb, start mariadb, and keep mariadb running. So that I can use the container in gitlab to run my integration tests (Java). This is what I have so far
FROM centos:7
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
# Install epel and java
RUN yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel wget
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk/
EXPOSE 8080
EXPOSE 3306
# install mariadb
RUN yum -y install mariadb
RUN yum -y install mariadb-server
RUN systemctl start mariadb
ENTRYPOINT tail -f /dev/null
The error I'm getting is
Failed to get D-Bus connection: Operation not permitted
You can do something like this:
FROM centos/mariadb-102-centos7
USER root
# Install epel and java
RUN yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel wget
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk/
You can mount your code folder into this container and execute it with docker exec.
It is recommended however you use two different containers: one for the db and one for your code. You can then pass the code container the env vars required to connect to the db container.
nothing is running by default in containers including systemd so you cannot use systemd to start mariadb
if we reference the official mariadb dockerfile, we can find that you can start mariadb by adding CMD ["mysqld"] to our dockerfile.
you must also make sure to install mariadb in your container with RUN yum -y mariadb-server mariadb-client as it is not installed by default either

AEM 6.0 on docker - Dbus connection error

I'm trying to dockerize an AEM 6.0 installation, and this is the Dockerfile for my author.
from centos:latest
COPY aem6.0-author-p4502.jar /AEM/aem/author/aem6.0-author-p4502.jar
COPY license.properties /AEM/aem/author/license.properties
RUN yum install dnsmasq -y
RUN systemctl enable dnsmasq
RUN yum install initscripts -y
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*;\
rm -f /lib/systemd/system/sockets.target.wants/*initctl*;\
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
WORKDIR /AEM/aem/author
RUN yum install wget -y
RUN wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u151-b12/e758a0de34e24606bca991d704f6dcbf/jdk-8u151-linux-x64.rpm"
RUN yum localinstall jdk-8u151-linux-x64.rpm -y
RUN java -XX:MaxPermSize=256m -Xmx512M -jar aem6.0-author-p4502.jar -unpack
COPY aem6 /etc/init.d/aem6
RUN chkconfig --add aem6
RUN yum -y install initscripts && yum update -y & yum clean all
RUN chown -R $USER:$(id -G) /etc/init.d
RUN chmod 777 -R /etc/init.d/aem6
RUN systemctl enable aem6.service
RUN service aem6 start
VOLUME /sys/fs/cgroup
CMD /usr/sbin/init
The build fails on starting the service, with the error - failed to get Dbus connection error. I haven't been able to figure out how to fix it.
I've tried these
- https://github.com/CentOS/sig-cloud-instance-images/issues/45
- https://hub.docker.com/_/centos/
Here, the problem is that you're trying to start the aem service during the "build" phase, with this statement:
RUN service aem6 start
This is problematic for a number of reasons. First, you're building an image. Starting a service at this stage is pointless...when the build process completes, nothing is running. An image is just a collection of files. You don't have any processes until you boot a container, at which point your CMD and ENTRYPOINT influence what is running.
Another problem is that at this stage, nothing else is running inside the container environment. The service command in this case is trying to communicate with systemd using the dbus api, but neither of those services are running.
There is a third slightly more subtle problem: the solution you've chosen relies on systemd, the standard CentOS process manager, and as far as things go you've configured things correctly (by both enabling the service with systemctl enable ... and by starting /sbin/init in your CMD statement). However, running systemd in a container can be tricky, although it is possible. In the past, systemd required the container to run with the --privileged flag; I'm not sure if this is necessary any more.
If you weren't running multiple processes (dnsmasq and aem) inside the container, the simplest solution would be to start the aem service directly, rather than relying on a process manager. This would reduce your Dockerfile to something like:
FROM centos:latest
COPY aem6.0-author-p4502.jar /AEM/aem/author/aem6.0-author-p4502.jar
COPY license.properties /AEM/aem/author/license.properties
WORKDIR /AEM/aem/author
RUN yum install wget -y
RUN wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u151-b12/e758a0de34e24606bca991d704f6dcbf/jdk-8u151-linux-x64.rpm"
RUN yum localinstall jdk-8u151-linux-x64.rpm -y
RUN java -XX:MaxPermSize=256m -Xmx512M -jar aem6.0-author-p4502.jar -unpack
CMD some commandline to start aem
If you actually require dnsmasq, you could run it in a second container (potentially sharing the same network environment as the aem container).

Starting Gunicorn Service in Dockerfile : Failed to get D-Bus connection: Operation not permitted

I m trying to start services(gunicorn, nginx) with my dockerfile but I got that error.
This is my dockerfile
FROM centos:centos7
RUN yum -y install epel-release
RUN yum -y --enablerepo=base clean metadata
RUN yum -y install nginx
RUN yum -y install python-pip
RUN pip install --upgrade pip
RUN yum -y install systemd;
RUN yum clean all;
COPY . /
RUN pip install --no-cache-dir -r requirements.txt
RUN ./manage.py makemigrations
RUN ./manage.py migrate
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
#Gunicorn
RUN cp gunicorn_systemd /etc/systemd/system/gunicorn.service
RUN systemctl start gunicorn
RUN systemctl enable gunicorn
And this is my build command
docker build -t guni ./
Any help please ?
You are trying to interact with systemd in your build script:
RUN systemctl start gunicorn
There are a number of problems here. First, trying to "start" a service as part of the build process doesn't make any sense: you're building an image, not starting a container.
Secondly, you're trying to interact with systemd, but you're never starting systemd, and it is unlikely that you want to [1]. Since a docker container is typically a "single process" environment, you don't need any init-like process supervisor to start things for you. You just need to arrange to run the necessary command yourself.
Taking Apache httpd as an example, rather than running:
systemctl start httpd
You would run:
httpd -DFOREGROUND
This runs the webserver and ensures that it stays in the foreground (the Docker container will exit when the foreground process exits). You can surely do something similar with gunicorn.
Your container is also missing a CMD or ENTRYPOINT directive, so it's not going to do anything when you run it unless you provide an explicit command, and that's probably not the behavior you want.
[1] If you really think you need systemd, you would need to arrange to start it when the container starts (e.g, CMD /sbin/init), but systemd is not something that runs well in an unprivileged container environment. It's possible but I wouldn't recommend it.

Resources