Dockerfile Endpoint which conflicts with docker-compose command?

Hi,

I’m new to docker and to learn a little more I have moved my Pihole full server to a container.
I have got the majority working bar one part - the cron job script that enables and disables blocklists.

Looking at the Pihole Dockerfile

it has an ENTRYPOINT and SHELL.

If I run docker-compose with no commands things work fine. If I add a command as follows into docker-compose.yml things fail. why

command: bash -c 'chmod +x /opt/script/enabledisable_domainlist.sh && crontab /opt/script/cron.txt'

Notice the command column - without the compose command I get.

/opt/docker$ docker container ls
CONTAINER ID   IMAGE                             COMMAND                  CREATED          STATUS                            PORTS                                                                                                                                                    NAMES
5a025c019741   pihole/pihole:latest              "/s6-init"               51 seconds ago   Up 48 seconds (healthy)           0.0.0.0:53->53/tcp, :::53->53/tcp, 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:53->53/udp, :::443->443/tcp, :::53->53/udp, 67/udp   pihole
26b7ea02cb98   klutchell/dnscrypt-proxy:latest   "dnscrypt-proxy -con…"   53 seconds ago   Restarting (255) 15 seconds ago                                                                                                                                                            dnscrypt-proxy

with the compose command I get.

CONTAINER ID                                                       IMAGE                             COMMAND                                                                                                 CREATED       STATUS                            PORTS     NAMES
6342c0aed9d6ad12459b58ab5b1c43a208b71275a0e25ae9ff413e1cad13ea85   pihole/pihole:latest              "/s6-init bash -c 'chmod +x /opt/script/enabledisable_domainlist.sh && crontab /opt/script/cron.txt'"   2 hours ago   Restarting (0) 34 seconds ago               pihole
f1acfe9fed43b5fd16ec17d54c50bc99f676d4fc75a2cf7381af2479aa1c8395   klutchell/dnscrypt-proxy:latest   "dnscrypt-proxy -config /config/dnscrypt-proxy.toml"                                                    2 hours ago   Restarting (255) 30 seconds ago             dnscrypt-proxy

Is command meant to look like this?

Kind Regards

Can you share your docker compose file? The command column indeed should contain the command from docker compose unless docker hides the end of the command in the terminal. But even then it should be a little longer. What does docker logs containername say?

Hi rimelek,

This is the docker-compose

version: "3"

services:
  dnscrypt:
    container_name: dnscrypt-proxy
    image: klutchell/dnscrypt-proxy:latest
    hostname: dns-crypt
    networks:
      pihole_net:
        ipv4_address: 172.16.255.2
    expose:
      - "5300/udp"
      - "5300/tcp"
    environment:
      TZ: 'Australia/Victoria'
    volumes:
      - './etc-dnscrypt-proxy:/config'
    restart: unless-stopped

  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    hostname: pihole
    networks:
      pihole_net:
        ipv4_address: 172.16.255.3
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80/tcp"
      - "443:443/tcp"
    environment:
      TZ: 'Australia/Victoria'
      WEBPASSWORD: 'TopSecret'
      REV_SERVER: 'true'
      REV_SERVER_DOMAIN: 'mydomain.lan'
      REV_SERVER_CIDR: '192.168.99.0/24'
      REV_SERVER_TARGET: '192.168.99.1'
      PIHOLE_DNS_1: '172.16.255.2#5300'
    volumes:
      - './etc-pihole:/etc/pihole'
      - './etc-dnsmasq.d:/etc/dnsmasq.d'
      - './opt-script/:/opt/script'
    command: bash -c "chmod +x /opt/script/enabledisable_domainlist.sh && crontab /opt/script/cron.txt"
    restart: unless-stopped
    depends_on:
      - dnscrypt

networks:
  pihole_net:
    driver: bridge
    ipam:
      config:
        - subnet: 172.16.255.0/24


docker logs pihole

[s6-init] making user provided files available at /var/run/s6/etc...exited 0.
[s6-init] ensuring user provided files have correct perms...exited 0.
[fix-attrs.d] applying ownership & permissions fixes...
[fix-attrs.d] 01-resolver-resolv: applying...
[fix-attrs.d] 01-resolver-resolv: exited 0.
[fix-attrs.d] done.
[cont-init.d] executing container initialization scripts...
[cont-init.d] 05-changer-uid-gid.sh: executing...
[cont-init.d] 05-changer-uid-gid.sh: exited 0.
[cont-init.d] 20-start.sh: executing...
 ::: Starting docker specific checks & setup for docker pihole/pihole

  [i] Installing configs from /etc/.pihole...
  [i] Existing dnsmasq.conf found... it is not a Pi-hole file, leaving alone!
  [✓] Installed /etc/dnsmasq.d/01-pihole.conf
  [✓] Installed /etc/dnsmasq.d/06-rfc6761.conf
Existing DNS servers detected in setupVars.conf. Leaving them alone
::: Pre existing WEBPASSWORD found
DNSMasq binding to default interface: eth0
Added ENV to php:
                        "TZ" => "Australia/Victoria",
                        "PIHOLE_DOCKER_TAG" => "2022.02.1",
                        "PHP_ERROR_LOG" => "/var/log/lighttpd/error.log",
                        "ServerIP" => "0.0.0.0",
                        "CORS_HOSTS" => "",
                        "VIRTUAL_HOST" => "0.0.0.0",
Using IPv4 and IPv6
::: Preexisting ad list /etc/pihole/adlists.list detected ((exiting setup_blocklists early))
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
::: Testing lighttpd config: Syntax OK
::: All config checks passed, cleared for startup ...
::: Enabling Query Logging
  [i] Enabling logging...
  [✓] Logging has been enabled!
 ::: Docker start setup complete
  Checking if custom gravity.db is set in /etc/pihole/pihole-FTL.conf
  Pi-hole version is v5.9 (Latest: v5.9)
  AdminLTE version is v5.11 (Latest: v5.11)
  FTL version is v5.14 (Latest: v5.14)
  Container tag is: 2022.02.1
[cont-init.d] 20-start.sh: exited 0.
[cont-init.d] done.
[services.d] starting services
Starting pihole-FTL (no-daemon) as pihole
Starting lighttpd
Starting crond
[services.d] done.
[cmd] bash exited 0
Stopping lighttpd
Stopping pihole-FTL
Stopping cron
s6-svc: fatal: unable to control /var/run/s6/services/lighttpd-access-log: supervisor not listening
s6-svc: fatal: unable to control /var/run/s6/services/lighttpd-error-log: supervisor not listening
[cont-finish.d] executing container finish scripts...
[cont-finish.d] done.
[s6-finish] waiting for services.
[s6-finish] sending all processes the TERM signal.
[s6-finish] sending all processes the KILL signal and exiting.
[s6-init] making user provided files available at /var/run/s6/etc...exited 0.
[s6-init] ensuring user provided files have correct perms...exited 0.
[fix-attrs.d] applying ownership & permissions fixes...
[fix-attrs.d] 01-resolver-resolv: applying...
[fix-attrs.d] 01-resolver-resolv: exited 0.
[fix-attrs.d] done.
[cont-init.d] executing container initialization scripts...
[cont-init.d] 05-changer-uid-gid.sh: executing...
[cont-init.d] 05-changer-uid-gid.sh: exited 0.
[cont-init.d] 20-start.sh: executing...
 ::: Starting docker specific checks & setup for docker pihole/pihole

  [i] Installing configs from /etc/.pihole...
  [i] Existing dnsmasq.conf found... it is not a Pi-hole file, leaving alone!
  [✓] Installed /etc/dnsmasq.d/01-pihole.conf
  [✓] Installed /etc/dnsmasq.d/06-rfc6761.conf
Existing DNS servers detected in setupVars.conf. Leaving them alone
::: Pre existing WEBPASSWORD found
DNSMasq binding to default interface: eth0
Added ENV to php:
                        "TZ" => "Australia/Victoria",
                        "PIHOLE_DOCKER_TAG" => "2022.02.1",
                        "PHP_ERROR_LOG" => "/var/log/lighttpd/error.log",
                        "ServerIP" => "0.0.0.0",
                        "CORS_HOSTS" => "",
                        "VIRTUAL_HOST" => "0.0.0.0",
Using IPv4 and IPv6
::: Preexisting ad list /etc/pihole/adlists.list detected ((exiting setup_blocklists early))
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
::: Testing lighttpd config: Syntax OK
::: All config checks passed, cleared for startup ...
::: Enabling Query Logging
  [i] Enabling logging...
  [✓] Logging has been enabled!
 ::: Docker start setup complete
  Checking if custom gravity.db is set in /etc/pihole/pihole-FTL.conf
  Pi-hole version is v5.9 (Latest: v5.9)
  AdminLTE version is v5.11 (Latest: v5.11)
  FTL version is v5.14 (Latest: v5.14)
  Container tag is: 2022.02.1
[cont-init.d] 20-start.sh: exited 0.

Status keeps flapping

Up 3 seconds (health: starting)
Restarting (0) 15 seconds ago 

docker exec pihole bash

Error response from daemon: Container 30983cf7b92f876f0d98f92e938f3a983562d30f22e09d6ac2bc5f4d1debaba9 is restarting, wait until the container is running

I had to sleep some hours to realize I totally misunderstood the issue. I thought one of the problems was that docker ps didn’t show the command after `/s6-init``, but that was just an example output to show how the container worked without setting a command.

So the problem is actually that you use bash as a command which will stop immediately since there is nothing to keep it alive. I don’t run multiple services in one container and when I did, I used supervisor which works differently, so I had to read about s6-init.

You can define your services in configuration files but when the services stop, s6-init will not keep the container running. You can pass a command to s6-init but that also should run in the foreground to keep the container alive. Bash will not do it.

When you run pihole without command, the services defined in /etc/s6/services willrun sos6-init` can’t stop either.

Since you don’t install s6-overlay in your Dockerfile, is it safe to asume it is already provided by the base image? I so, it should be safe to remove the ENV S6_OVERLAY_VERSION line and the ENTRYPOINT line, as it is already inherited by the base image.

You definitly want to integrate your own scripts into the s6 convention. If you place your scripts in /etc/cont-init.d they will get executed before the main service starts.

Are you sure s6-init processes the “command” as s6-init arguments? I worked a lot with s6-overlay in the past but never actualy tried to pass arguments to the entrypoint script. I am not sure s6-init does it’s job and simply runs exec "$@" at the end like most entrypoint scripts are designed to do, but somehow I have doubts it would do that.

The Dockerfile quoted by @anowak000 was the Dockerfile of pihole/pihole. There was no docker build in this case.

I tried. I usually don’t state something without testing unless I also state that is just a guess. :slight_smile: It works even with bash if you set the the compose file to use an interactive terminal. I also tried manually running the container changing the entrypoint to use bash. Then I ran /s6-init bash. After that I had to exit twice to actually exit the container. I tried again to show the process tree:

 »  docker run --rm -it --entrypoint bash pihole/pihole
root@d36133b55f15:/# /s6-init bash
root@d36133b55f15:/# pstree
bash---s6-svscan-+-foreground---foreground---bash---pstree
                 |-3*[s6-supervise]
                 |-s6-supervise---bash---pihole-FTL---5*[{pihole-FTL}]
                 |-s6-supervise---bash---lighttpd---php-cgi---4*[php-cgi]
                 `-s6-supervise---bash---cron

Then I exited once:

root@d36133b55f15:/# exit
exit
[cmd] bash exited 0
Stopping lighttpd
Stopping cron
Stopping pihole-FTL
s6-svc: fatal: unable to control /var/run/s6/services/lighttpd-access-log: supervisor not listening
[cont-finish.d] executing container finish scripts...
[cont-finish.d] done.
s6-svc: fatal: unable to control /var/run/s6/services/lighttpd-error-log: supervisor not listening
[s6-finish] waiting for services.
[s6-finish] sending all processes the TERM signal.
Hangup
root@d36133b55f15:/# pstree
bash-+-pstree
     `-s6-pause

When you run pihole without changing the entrypoint to use bash as a command (but with an interactive terminal)

 »  docker run --rm -it pihole/pihole bash

Then you can see a similar process tree:

root@60390c8ff3cf:/# pstree
s6-svscan-+-foreground---foreground---bash---pstree
          |-3*[s6-supervise]
          |-s6-supervise---bash---pihole-FTL---5*[{pihole-FTL}]
          |-s6-supervise---bash---lighttpd---php-cgi---4*[php-cgi]
          `-s6-supervise---bash---cron-+-cron---sh---bash---bash---curl---{curl}
                                       `-cron---sh---bash---bash---sleep

When you exit the bash, you can see how s6-init terminates the processes:

[cmd] bash exited 0
Stopping pihole-FTL
Stopping lighttpd
Stopping cron
s6-svc: fatal: unable to control /var/run/s6/services/lighttpd-access-log: supervisor not listening
[cont-finish.d] executing container finish scripts...
[cont-finish.d] done.
[s6-finish] waiting for services.
s6-svc: fatal: unable to control /var/run/s6/services/lighttpd-error-log: supervisor not listening
[s6-finish] sending all processes the TERM signal.
[s6-finish] sending all processes the KILL signal and exiting.

But if you don’t ask for an interactive terminal, bash exits immediately as it would exit without s6-init, and s6-init terminates the processes before the container stops.

I didn’t want to recommend using interactive terminal, because I didn’t think that would be the right way.

Then the installation of s6-overlay must happen in install.sh script. I am not used to see Dockerfiles where the whole magic is hidden in a .sh file.

Seems like it actualy did run the argument after /s6-init with something like exec $@ and therefore prevented s6 to function as a supervisor. The diagnostic is spot on! I am actualy surprised it is implemented that way…

@anowak000 I would suggest to use file-based volume-binds that mount each file in ./opt-script/ to /etc/cont-init.d/, so s6-init picks them up by itself without having to do anything particular. Or even better build your own image that copies the files from ./opt-script/ to /etc/cont-init.d and use your own image :slight_smile:

It worked as a supervisor s6 was not replaced by bash. s6 just started bash in the foreground and when bash exited, the next step was to send TERM signals to the services. It actually makes sence to me, since you can do some experiment and stop the container by exiting without having to run docker stop and docker rm. Maybe there are other reasons as well.

update: Oh… the other reason could be to be able to use s6-init as tini just for one process.

Hi rimelek,meyay,

This post has gone way over my head - will need time to digest what is being said as I am new to docker.
In basic terms I want to run dnscrypt + pihole as containers (learning purpose). I also wanted to be able to run custom scheduled scripts (as I did in a full install of pihole) that enabled and disabled the Pihole blacklists.

The idea was to bring up the containers and have the script created during the compose process - which clearly does not work using the command with bash.
I can do it if I use docker exec -it pihole bash -c “script stuff”
I could also create the schedules on the host and push to docker but that would defeat the purpose of the container being separate.

Really appreciate the responses.

Kind Regards

I think you should check what Metin wrote

Your bash script could work there. I didn’t try this one, but I believe Metin. I just tried to explain why your solution didn’t work but I didn’t know what the right solution was.

I don’t see a copy command in docker-compose yml. So I am guessing it needs to be done via volumes.

I created a new script called deploycron.sh

#!/bin/bash

chmod +x /opt/script/enabledisable_domainlist.sh
crontab /opt/script/cron.txt

and added it under volumes

 volumes:
      - './etc-pihole:/etc/pihole'
      - './etc-dnsmasq.d:/etc/dnsmasq.d'
      - './opt-script/:/opt/script'
      - './cron/deploycron.sh:/etc/cont-init.d/deploycron.sh'

Looks like it’d working as intended!!

Really appreciate the help.

Kind Regards