How to 'avahi-browse' from a docker container? - docker

I'm running a container based on ubuntu:14.04, and I need to be able to use avahi-browse inside it. However:
(.env)root#8faa2c44e53e:/opt/cluster-manager# avahi-browse -a
Failed to create client object: Daemon not running
(.env)root#8faa2c44e53e:/opt/cluster-manager# service avahi-daemon status
Avahi mDNS/DNS-SD Daemon is running
The actual problem I have is a pybonjour error; pybonjour.BonjourError: (-65537, 'unknown') but I've read that is linked to the problem with the avahi-daemon.
So; how do I connect to the avahi-daemon from the container ?
P.S. I have to switch dbus off in the avahi-daemon.conf fill to make it possible to start it, otherwise avahi-daemon won't start, with a dbus error like this:
(.env)root#8faa2c44e53e:/opt/cluster-manager# avahi-daemon
Found user 'avahi' (UID 103) and group 'avahi' (GID 107).
Successfully dropped root privileges.
avahi-daemon 0.6.31 starting up.
dbus_bus_get_private(): Failed to connect to socket /var/run/dbus/system_bus_socket: No such file or directory
WARNING: Failed to contact D-Bus daemon.
avahi-daemon 0.6.31 exiting.

As far I can test you can use host's avahi-daemon through Unix socket for mDNS to resolve and /var/run/dbus for avali-browse to work.
E.g.:
docker run -v /var/run/dbus:/var/run/dbus -v /var/run/avahi-daemon/socket:/var/run/avahi-daemon/socket -ti debian:10-slim bash
To test inside container:
apt-get update && apt-get install avahi-utils iputils-ping -y
ping whatever.local
avahi-browse -a

Avahi requires D-BUS in order to communicate with clients. Sounds like your docker container isn't starting the system D-BUS. If you do that, then Avahi should work.
You need D-BUS for most of Avahi's functionality (including avahi-browse) so disabling it won't really help.

There is a docker image supposedly supporting avahi from within the container. The trick seems to be to mount /var/run/dbus from the host into the container.
Note that I couldn't make it work to run this image on my 16.04. host.

I ran into the same problem getting avahi and dbus to operate correctly on Ubuntu 14.04 (specifically, I was trying to use ROS TurtleBot). I solved it by incorporating a modified version of the instructions in docker-systemd into my Dockerfile:
FROM ubuntu:14.04
RUN apt-get update &&\
apt-get install -y avahi-utils avahi-daemon libnss-mdns systemd
RUN cd /lib/systemd/system/sysinit.target.wants/;\
ls | grep -v systemd-tmpfiles-setup | xargs rm -f $1 \
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/*; \
rm -f /lib/systemd/system/plymouth*; \
rm -f /lib/systemd/system/systemd-update-utmp*
RUN mkdir -p /var/run/dbus
ENV init /lib/systemd/systemd
After modifying your Dockerfile to include these instructions, you should create a container using the following command:
docker run --rm --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro -it <DOCKER_IMAGE> /bin/bash
Finally, once you're inside the container, you must execute the following commands before attempting to use avahi-browse (directly or indirectly):
$ dbus-service --system
$ /etc/init.d/avahi-daemon start

Another solution is to use mdns-repeater on the host to forward mDNS packets to the Docker network
mdns-repeater eth1 docker0

I needed to add 2 parameters in my call to docker run command for avahi-browse -at command to run inside the container:
--privileged and -v /var/run/dbus:/var/run/dbus

Related

"systemctl" command doesn't work on centos with docker

I use docker with centos 8.
How can i use systemctl command in dockerfile please ?
When i install an app it needs systemctl.
I have an error:
System has not been booted with systemd as init system (PID 1). Can't
operate. Failed to connect to bus: Host is down
I build docker like this:
docker build -t myapp:11 .
Same when i try in container:
docker run -it --privileged app:11 /bin/bash
Thank you.
docker build -t nuance:11 .
docker run -it --cap-add=NET_ADMIN nuance:11 /bin/bash
# syntax=docker/dockerfile:1
FROM centos:latest
USER root
RUN cd /etc/yum.repos.d/
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
RUN yum -y update && \
yum clean all
RUN yum -y install \
java-11-openjdk-devel \
perl-Data-Dumper \
redhat-lsb-core.x86_64 \
glibc.x86_64 \
glibc.i686 \
libstdc++.x86_64 \
libstdc++.i686 \
openssl \
libgcc \
libgcc.i686 \
libaio.x86_64 \
libaio.i686 \
libnsl.i686 \
ncurses-libs \
httpd.x86_64 \
unzip \
-x postfix \
-x mariadb-libs \
zlib.i686 \
zlib.x86_64
WORKDIR /tmp
COPY Nuance_Speech_Suite-11.0.10-x86_64-linux.tgz ./Nuance_Speech_Suite-11.0.10-x86_64-linux.tgz
COPY NRec-fr-FR-10.0.0-10.1.0.i686-linux.tar.gz ./languages/NRec-fr-FR-10.0.0-10.1.0.i686-linux.tar.gz
COPY NVE_fr_FR_audrey-ml_xpremium-2.1.0_linux.zip ./languages/NVE_fr_FR_audrey-ml_xpremium-2.1.0_linux.zip
COPY NRec-fr-FR-10.0.0-10.1.0-CumulativePatch-1_linux.zip ./languages/NRec-fr-FR-10.0.0-10.1.0-CumulativePatch-1_linux.zip
COPY NRec-fr-FR-10.0.0-10.1.0-CumulativePatch-2_linux.zip ./languages/NRec-fr-FR-10.0.0-10.1.0-CumulativePatch-2_linux.zip
COPY nuance.lic ./nuance.lic
RUN tar -zxf Nuance_Speech_Suite-11.0.10-x86_64-linux.tgz
RUN tar -zxf languages/NRec-fr-FR-10.0.0-10.1.0.i686-linux.tar.gz
RUN unzip languages/NVE_fr_FR_audrey-ml_xpremium-2.1.0_linux.zip
RUN unzip languages/NRec-fr-FR-10.0.0-10.1.0-CumulativePatch-1_linux.zip
RUN unzip languages/NRec-fr-FR-10.0.0-10.1.0-CumulativePatch-2_linux.zip
WORKDIR /tmp/Nuance_Speech_Suite-11.0.10
RUN ./setup.sh -s -f "/tmp/nuance.lic" -j "/usr/lib/jvm/java-11-openjdk" -V "/tmp/languages" -I "NLM,NSS"
last lines of log
2022-12-16 09:22:11 setup.sh: info: Restarting the Nuance License Manager service
2022-12-16 09:22:11 setup.sh: info: starting command 'systemctl restart nuance-licmgr'; output sent to log
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
2022-12-16 09:22:11 setup.sh: info: Command 'systemctl restart nuance-licmgr' returned 1
2022-12-16 09:22:11 setup.sh: error: install_postprocessing_nlm_startservices() failed to start services
2022-12-16 09:22:11 setup.sh: info: skipping invocation of install_postprocessing_nms() due to previous post processing errors
2022-12-16 09:22:11 setup.sh: info: Skipping install_execute_installsuite due to previous errors
You can't run systemctl in a Dockerfile at all. More broadly, commands like systemctl or service don't work well in Docker, and you should restructure your container to avoid them.
For systemctl more specifically, it tries to connect to the systemd daemon. In a Dockerfile, each RUN step occurs in a new container, and like other containers, that container only runs the one RUN command; it does not run systemd or any other typical Linux daemons. Furthermore, at the end of the RUN line, the filesystem is persisted but any other changes are lost, so even if you systemctl start something successfully, the image won't contain a running process.
More generally I'd recommend avoiding systemd in Docker. A minimal init system like tini can be a good idea for some problems like reaping zombie processes; if you must run multiple processes in one container and really can't refactor it then supervisord can fill this need. A typical systemd installation will want to configure kernel parameters, start terminal logins, mount filesystems, and configure the network, all of which are basically impossible in Docker; it will capture the main process's stdout so docker logs doesn't work.
Aim for your container to only have one process. Don't run an init system at all if you don't need to. Don't try to "start a service", just run the program you're trying to build in the foreground as the one thing the container does.
FROM some-base-image
RUN a command to install the software
CMD the_program
# with no `systemctl` anywhere
if you are facing following error when running docker -
docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
See 'docker run --help'
or
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
Run following commands
$ sudo systemctl status docker
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
The reason is that you are trying to use systemd command to manage services on Linux but your system doesn't use systemd and (most likely) using the classic SysV init (sysvinit) system.
run following command to confirm if its above case
$ ps -p 1 -o comm=
init
so now you check again the status using
$ sudo service docker status
* Docker is not running
you can start docker using the following command
sudo service docker start
* Starting Docker: docker
for more detail pls refer following link
https://linuxhandbook.com/system-has-not-been-booted-with-systemd/
Systemd command
Sysvinit command
systemctl start service_name
service service_name start
systemctl stop service_name
service service_name stop
systemctl restart service_name
service service_name restart
systemctl status service_name
service service_name status
systemctl enable service_name
chkconfig service_name on
systemctl disable service_name
chkconfig service_name off

How to start and stop docker container with systemd

I am going to leave the question with answer to help anyone who has similar problem with configuring docker and systemd together.
How we can start and stop docker container with systemd?
First we will create docker image
FROM debian:stretch
RUN apt-get update \
&& apt-get install -y systemd \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
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/sysinit.target.wants/systemd-tmpfiles-setup* \
/lib/systemd/system/systemd-update-utmp*
# systemd should be started with PID 1
CMD [ "/lib/systemd/systemd" ]
Let's build our docker image
docker build -t test_image path_to_docker_file
Now we can create and start new container
docker run --name test_container -it -d --privileged --stop-signal RTMIN+3 test_image
Or you can start existing container
docker start test_image
Now you can attach to running container to execute some bash command for example
docker exec -it test_container bash
To stop container
docker stop test_container
IMPORTANT!!!
Do not specify ENTRYPOINT when you start container it should be always SYSTEMD, if you want to execute something do it by attaching to container
docker exec -it test_container bash (or other any commands)
You cannot start systemd during Docker image build.
Solution was tested for Docker version 2.0.0.3 on macOS

Unable to run systemd inside docker which is being run inside jenkins

I'm trying to get Jenkins to run Docker that runs SystemD.
So far I've been able to run systemd inside docker locally without Jenkins. Here are the steps to run it locally without jenkins:
# pull unop/fedora-systemd and create and run the container for it
sudo docker run --cap-add=SYS_ADMIN -e container=docker --tmpfs /run --tmpfs /tmp -v /sys/fs/cgroup:/sys/fs/cgroup:ro -t -i unop/fedora-systemd
# on a different terminal window, I can:
# get the container id of the "unop/fedora-systemd" image
sudo docker ps
# then exec bash on it
sudo docker container exec -t -i a98aa2bcd19e bash # where a98aa2bcd19e is the container id found above
# once inside the container, I can run systemd without any problems. examples:
systemctl status
systemctl start dbus.service
systemctl status dbus.service
The above works locally and I am able to run systemd inside the docker container.
The problem I get is when I try the same thing, but inside Jenkins.
I've tried to tweak Jenkinsfile several times, but not of my previous tries seemed to work. I always get an error when running under Jenkins similar to this:
+ systemctl status
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
This is my latest Jenkinsfile that I've tried
pipeline {
agent {
docker {
image 'unop/fedora-systemd'
args '--cap-add=SYS_ADMIN -e container=docker --tmpfs /run --tmpfs /tmp -v /sys/fs/cgroup:/sys/fs/cgroup:ro -t -i'
}
}
stages {
stage('test') {
steps {
sh "echo hello world"
sh "systemctl status"
sh "systemctl start dbus.service"
sh "systemctl dbus.service"
}
}
}
}
On previous iterations of the Jenkinsfile, I've tried to replace -cap-add=SYS_ADMIN -e container=docker for --privileged, but that didn't help, I still got the same errors
Anyone have an idea of how can I get this to work? Why does the above work locally, but not on Jenkins? what am I missing here?
Note: Jenkins version: 2.150.2 and this is the Dockerfile used by unop/fedora-systemd
FROM fedora:rawhide
MAINTAINER http://fedoraproject.org/wiki/Cloud
ENV container docker
RUN dnf -y update && dnf clean all
RUN dnf -y install systemd && dnf clean all && \
(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", "/tmp", "/run" ]
CMD ["/usr/sbin/init"]
PS: I've seen a related question, but what they were asking is different
I did not know about the related question. Let me point out again that you do not need to run a systemd daemon in a systemd controlled container if it is just about running multiple services in it. Simply overwrite /usr/bin/systemctl with the docker-systemctl-replacement script. Then go to register it with CMD ["/usr/bin/systemctl"] as the init process of the container.
That's it. Now you can run any systemctl-start process from the operating system. It works to the extent that even provisioning with ansible/puppet scripts have no problem at all. An specficially, I am using that to provision Jenkins images with the operating system that the developers like to have as a basis. No priviledged mode required.
You may try an image that has Fedora with System D already active with this command:
docker run -d --name systemd-fedora --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro jrei/systemd-fedora
Then you just need to run:
docker exec -it systemd-fedora /bin/bash
and there you can just install, start and restart any service you need.

Start ssh using systemctl inside the docker container

I' m a beginner in the Docker;
I have pulled a CentOS 7 image from Hub and ran it ;
I need to ssh in to the docker container(CentOS 7) from my host.
Got the docker container's IP using docker inspect container-id
I have installed the following using
initscripts
systemd.x86_64
systemd-libs.x86_64
open-ssh
firewalld
net-tools
when i tried to start the firewall to open the port for ssh(22)
[root#a6f3e3eb095c ~]# systemctl start firewall
Failed to get D-Bus connection: Operation not permitted
Also tried,
[root#a6f3e3eb095c ~]# /usr/lib/systemd/systemd --system &
[1] 353
[root#a6f3e3eb095c ~]# systemd 219 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ -LZ4 -SECCOMP +BLKID +ELFUTILS +KMOD +IDN)
Detected virtualization xen.
Detected architecture x86-64.
Welcome to CentOS Linux 7 (Core)!
Set hostname to <a6f3e3eb095c>.
Cannot determine cgroup we are running in: No such file or directory
Failed to allocate manager object: No such file or directory
[1]+ Exit 1 /usr/lib/systemd/systemd --system
How to start the firewall/ssh inside the docker container ?
inside docker container run following commands :
yum update -y glibc-common
yum install -y sudo passwd openssh-server openssh-clients tar screen crontabs strace telnet perl libpcap bc patch ntp dnsmasq unzip pax which
rpm -Uvh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
yum install -y hiera lsyncd sshpass rng-tools
service sshd start;
sed -i 's/UsePAM yes/#UsePAM yes/g' /etc/ssh/sshd_config;
sed -i 's/#UsePAM no/UsePAM no/g' /etc/ssh/sshd_config;
sed -i 's/#PermitRootLogin yes/PermitRootLogin yes/' /etc/ssh/sshd_config;
sed -i 's/enabled=0/enabled=1/' /etc/yum.repos.d/CentOS-Base.repo
mkdir -p /root/.ssh/;
rm -f /var/lib/rpm/.rpm.lock;
echo "StrictHostKeyChecking=no" > /root/.ssh/config;
echo "UserKnownHostsFile=/dev/null" >> /root/.ssh/config
echo "root:password" | chpasswd
( or )
Simply you can pull docker image of centos with ssh in docker hub
https://hub.docker.com/search/?isAutomated=0&isOfficial=0&page=1&pullCount=0&q=centos+ssh&starCount=0
https://hub.docker.com/r/kinogmt/centos-ssh/
https://hub.docker.com/r/jdeathe/centos-ssh/
You can avoid the "Failed to get D-Bus connection: Operation not permitted" / aka installing systemd inside a docker by using the https://github.com/gdraheim/docker-systemctl-replacement ... after that the docker-exec stuff should be all fine to do things inside a container.
If you really do need an ssh or sftp container, then you can use my Docker Image as a source image for your own or run it directly:
If using the official CentOS-7 Image and you require systemd, there are instructions on how to enable it under the section "Systemd integration".
However, based on the following:
I need to ssh in to the docker container(CentOS 7) from my host.
You can use docker exec to run commands in a running, (backgrounded), container so, for images that have bash available, you can access an interactive tty and run bash as follows from your host - where container can be either the name or id:
docker exec --tty --interactive <container> bash
OR
docker exec -ti <container> bash
Finally, it's unlikely to be necessary to install the firewall package in your image as the operator will decide what ports to publish from those which are exposed and you can make use of Docker Networking to only expose the necessary public facing services.
If you are using the Docker CLI, then you can get into the Docker container using the following command
docker exec -it containerId bash
I am not sure how to ssh into the docker container, but if you want to do basic operation inside the Docker container, you can make use of the above docker command.

docker inside docker container

I want to install docker inside a running docker container.
docker run -it centos:centos7
My base container is using centos, I can login to running container using docker exec. But when I try to install docker inside it using yum install -y docker it installs.
But somehow I can't start the docker service with docker -d &, it gives me error as:
INFO[0000] Option DefaultNetwork: bridge
WARN[0000] Running modprobe bridge nf_nat br_netfilter failed with message: , error: exit status 1
FATA[0000] Error starting daemon: Error initializing network controller: Error initializing bridge driver: Setup IP forwarding failed: open /proc/sys/net/ipv4/ip_forward: read-only file system
Is there a way I can install docker inside docker container or build image already having running docker? I have already seen these examples but none works for me.
The output of uname -r on the host machine:
[fedora# ~]$ uname -r
4.2.6-200.fc22.x86_64
Any help would be appreciated.
Thanks in advance
Update
Thanks to https://stackoverflow.com/a/38016704/372019 I want to show another approach.
Instead of mounting the host's docker binary, you should copy or install a container specific release of the docker binary. Since you're only using it in a client mode, you won't need to install it as a system service. You still need to mount the Docker socket into the container so that you can easily communicate with the host's Docker engine.
Assuming that you got a base image with a working Docker binary (e.g. the official docker image), the example now looks like this:
docker run\
-v /var/run/docker.sock:/var/run/docker.sock\
docker:1.12 docker info
Without actually answering your question I'd suggest you to read Using Docker-in-Docker for your CI or testing environment? Think twice.
It explains why running docker-in-docker should be replaced with a setup where Docker containers run as siblings of the "outer" or "base" container. The article also links to the original https://github.com/jpetazzo/dind project where you can find working examples how to run Docker in Docker - in case you still want to have docker-in-docker.
An example how to enable a container to access the host's Docker daemon look like this:
docker run\
-v /var/run/docker.sock:/var/run/docker.sock\
-v /usr/bin/docker:/usr/bin/docker\
busybox:latest /usr/bin/docker info
If you are on Mac with Docker toolbox.
The below command WON’T WORK
docker run\
-v /var/run/docker.sock:/var/run/docker.sock\
-v /usr/bin/docker:/usr/bin/docker\
busybox:latest /usr/bin/docker info
Because /var/run/docker.sock will not be on your OSX filesystem
the Docker daemon is running inside the boot2docker VM - and that's where the unix socket is.
So you have to run the container from boot2docker VM
$ docker-machine ssh default
$ docker run\
-v /var/run/docker.sock:/var/run/docker.sock\
-v $(which docker):/usr/bin/docker\
busybox:latest /usr/bin/docker info
$ exit
This looks like Docker-in-Docker, feels like Docker-in-Docker, but it’s not Docker-in-Docker, when this container will create more containers, those containers will be created in the top-level Docker.
You need the --privileged parameter.
By default, Docker containers are “unprivileged” and cannot, for
example, run a Docker daemon inside a Docker container.
Source
Run your base image with the command docker run --privileged -it centos:centos7 bash. Then you may install and run another docker container inside that container.
I`ve a similar problems in my vms.
I`ve solve the problem with change the storage file system from image to vfs(in daemon.json file)
like the image bellow
For image works first create a base image, in my case with centos7
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"]
with this image builded (in my case i called local/c7-systemd) create a second image, installing docker and moving daemon.json to inside.
FROM local/c7-systemd
RUN yum install -y yum-utils
RUN yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
RUN yum install -y docker-ce docker-ce-cli containerd.io
RUN curl -L "https://github.com/docker/compose/releases/download/1.28.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
RUN chmod +x /usr/local/bin/docker-compose
RUN ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
COPY daemon.json /etc/docker/daemon.json
RUN yum install -y nano
RUN systemctl enable docker
EXPOSE 80
EXPOSE 8080
EXPOSE 8161
EXPOSE 6379
EXPOSE 8761
CMD ["/usr/sbin/init"]
enjoy!

Resources