systemd service not works in docker - docker

my environment is under docker image(ubuntu 20.04), and i want to use systemd to start my service after every time i start mydocker, i have my own .service file here:
/etc/systemd/system/my.service:
[Unit]
Description=my test
Documentation=man:test auto(8) man:test_config(5)
[Service]
ExecStart=/root/test.sh
Type=oneshot
[Install]
WantedBy=multi-user.target
/root/test.sh have been chmod 777:
#!/bin/bash
echo "hello~" > /usr/local/test.log
exit 0
and I did follows operation:
systemctl enable my.service
docker stop mydocker
docker start mydocker
docker exec -it mydocker bash
but after I start mydocker, I didn't see /root/test.sh executed, and i check service status like this:
my.service - my test auto
Loaded: loaded (/etc/systemd/system/my.service, enabled)
Active: inactive (dead)
manually trigger service is okay:
root#:/# systemctl start my.service
root#:/# cat /usr/local/test.log
hello~
did I omit something? or systemd could not work well in docker?
thanks.

suggestion #1
Docker images are expected to run an initial command/program specified in the docker image generation dockerfile properties:
ENTRYPOINT
CMD
See here: https://blog.knoldus.com/a-look-at-cmd-and-entrypoint-in-dockerfile/
suggestion #2
In your /etc/systemd/system/my.service: [unit] section add Requires=Network.target and After=Network.target:
Like this:
[Unit]
Description=my test
Documentation=man:test auto(8) man:test_config(5)
Requires=Network.target
After=Network.target
[Service]
ExecStart=/root/test.sh
Type=oneshot
[Install]
WantedBy=multi-user.target
suggestion #3
Do not use systemd services in docker image.
Use crontab job at boot time.
https://www.linode.com/docs/guides/run-jobs-or-scripts-using-crontab-on-boot/
crontab job
#boot /root/test.sh

Related

How to convert a systemd service to docker container?

I have an existing custom service at /lib/systemd/system/custom.service with:
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=simple
User=customuser
ExecStart=/opt/customservice /opt/custom.config
[Install]
WantedBy=multi-user.target
With:
systemctl enable custom.service
systemctl start custom.service
How can I convert this service to a docker container, keeping in in foreground and always up and running?
I started with a Dockerfile as follows:
FROM ubuntu:20
COPY /custom.service /opt/app/
COPY /custom.config /opt/app/
ENTRYPOINT [ "/opt/custom.service", "/opt/custom.config" ]
But how can I now achieve the same configuration as I had in the native systemd service?

Is there a way to command Docker to start containers to start on next boot instead of now?

I am using Packer to build an EC2 AMI containing Docker images. I want a few services (restart policy set to unless-stopped to be downloaded and ready to run on first boot without actually running during build time.
At the moment I docker-compose up -d, wait an arbitrary amount of time, then finish the packer build (which probably ungracefully stops the running containers).
What I am planning is to docker-compose pull && docker-compose build and create some kind of init script that issues the docker compose run command.
Is there a better way to do this?
You can just do docker pull and add and enable a systemd unit file for each docker container. Something like this:
[Unit]
Description=Redis Container
After=docker.service
Requires=docker.service
[Service]
TimeoutStartSec=0
Restart=always
ExecStartPre=-/usr/bin/docker stop %n
ExecStartPre=-/usr/bin/docker rm %n
ExecStartPre=/usr/bin/docker pull redis
ExecStart=/usr/bin/docker run --rm --name %n redis
[Install]
WantedBy=multi-user.target
Read more in this blog post.

systemctl command doesn't work inside docker-container

I've made a Docker image for my spring boot application. I'm unable to run systemctl command inside the Docker container. This is what I get when I execute
systemctl daemon reload :-
Failed to connect to bus: No such file or directory
Steps I followed to build the Docker image :-
1) docker build --rm -t <IMAGE_NAME> .
2) docker-compose up
3) docker exec -it <CONTAINER_NAME> bash
When I start a service using :-
service <SERVICE_NAME> start
I get unrecognised service. How do I execute a service inside docker?
If you want to reuse your existing systemd service descriptors then you either need to run systemd as the entrypoint, or you can use a wrapper script like the docker-systemctl-replacement which is both a service manager and an init daemon.
As David commented, you generally don't use process managers like systemctl in a docker environment. Instead, you can make your application the primary entry point of the image. See more in the Spring documentation about using it with docker at https://spring.io/guides/gs/spring-boot-docker/#_containerize_it.
Key is having something like this in your dockerfile, instead of systemctl daemon reload
ENTRYPOINT ["java","-jar","/app.jar"]

How to "reset" a docker-compose systemd service?

I have created a systemd service that starts a set of Docker containers using Docker-Compose, as outlined in this answer:
# /etc/systemd/system/docker-compose-app.service
[Unit]
Description=Docker Compose Application Service
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/srv/docker
ExecStart=/usr/local/bin/docker-compose up -d
ExecStop=/usr/local/bin/docker-compose down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
This allows me to start the Docker-Compose services using
sudo systemctl start docker-compose-app
which uses docker-compose up -d under the hood, and shutting them down using
sudo systemctl stop docker-compose-app
which uses docker-compose down. Please note that the down command is run without the -v flag, which means that volumes will remain in place, preserving the data of my containers across restarts/recreation. This is pretty much what I want in the majority of cases.
There are situations where I want to erase all data in the services, basically running the down -v command instead of just down.
Is there a way to extend the above systemd service definition to allow for an additional command (or using one of the existing systemctl commands) that would allow me to run the occasional down -v if needed. I want to do this ad-hoc if needed, not scheduled or anything like that.
How can I run
docker-compose down -v
occasionally if needed through the same systemd setup, while keeping the standard functionality of maintaining the containers' data across restarts?
You may try to use ExecReload definition:
ExecReload=/usr/local/bin/docker-compose down -v && /usr/local/bin/docker-compose up -d
And then you can use:
sudo systemctl reload docker-compose-app
So "reload" command will be used for "reset" in this case.

running a docker container with systemd

I have a service definition that starts a docker container using systemd on CentOS 7:
[Unit]
Description=MappingService
After=portal.service
Requires=docker.service
[Service]
TimeoutStartSec=3000
Type=forking
WorkingDirectory=/home/user/Downloads/MS_0.3.4_artifact
ExecStartPre=-/bin/docker rm -f eb-mapping-service-container
ExecStartPre=/home/user/Downloads/MS_0.3.4_artifact/deploy.sh /home/user/Downloads/MS_0.3.4_artifact/eb-mapping-service.tgz
ExecStartPre=/bin/docker run -v /dev/log:/dev/log -d -ti --log-driver=journald --network=bridge -p 9090:9090 --name eb-mapping-service-container eb-mapping-service /bin/bash -c "cd /build/MappingService; ./start_multiple_clients_mapping_service.sh"
ExecStart=/bin/docker start -a eb-mapping-service-container
ExecStop=/bin/docker stop eb-mapping-service-container
[Install]
WantedBy=multi-user.target
This service works. The Docker container it launches is up.
Whenever I boot the computer it is running. My problem with this service is that it's never reaching the Active(Running) status. Instead, it is stuck in 'Activating(start)' status.
The 'start_multiple_clients_mapping_service.sh' script starts a node.js server and it starts listening, so it isn't exiting directly.
I've searched everywhere and scoured Docker's documentation about this and couldn't find an answer.
Also, if I remove the '-a' from the docker start command, then the status will be Inactive(dead) even though the container will be up and running.
Update:
After a while, I don't have an exact number, the service fails with the timeout reason. This isn't after 3000 seconds but way earlier. Although the service failed, the docker is still on the air and can be used.
I've verified with docker container ls
Question:
How do I change my service definition to reflect the Active(Running) status for the docker?
I understood the problem. There were a couple of things wrong:
the docker run command should not be used with the flags -d and -ti.
the Type should be set to exec instead of forking.
After doing these two changes, I got the much sought after Active(Running) status with the Docker successfully launched.

Resources