-1

In a docker image I want to avoid installing netcat in order to ping for db connectivity at my entrypoint script:

/bin/sh

MOODLE_DB_HOST="xxxx"
MOODLE_DB_PORT=80

function pingdb {
    OK=0
    for count in {1..100}; do
      echo "Pinging database attempt ${count} into ${MOODLE_DB_HOST}:${MOODLE_DB_PORT}" 
      if  $(nc -z ${MOODLE_DB_HOST} ${MOODLE_DB_PORT}) ; then
        echo "Can connect into database"
        OK=1
        break
      fi
      sleep 5
    done

    echo "Is ok? "$OK

    if [ $OK -eq 1 ]; then
      echo "Database type: "${MOODLE_DB_TYPE}
      echo "DB Type: "${MOODLE_DB_TYPE}
    else
      echo >&2 "Can't connect into database"
      exit 1
    fi
}

But instead, I want to use a nc replacement for entrypoint script running upon docker images utilising php.

Is there an alternative?

The reason why I want to do this is because I have 2 Dockerfiles, one debian-based and one alpine based:

debian-based php image:

ARG PHP_VERSION="7.4"
FROM  php:${PHP_VERSION}-fpm as base

RUN --mount=type=bind,from=mlocati/php-extension-installer:latest,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \
    /usr/local/bin/install-php-extensions xmlrpc mbstring zip xml intl soap gd opcache &&\
    echo "PHP_EXTENTION_DIR="$(php -i | grep extension_dir  | cut -d " " -f 5) >> /etc/environment &&\
    cat /etc/environment &&\
    apt-get update &&\
    apt-get install -y netcat &&\
    apt-get autopurge -y &&\
    apt-get autoremove -y &&\
    apt-get autoclean &&\
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* cache/* /var/lib/log/* &&\
    echo "max_input_vars=5000" > ${PHP_INI_DIR}/conf.d/moodle.ini

COPY ./scripts/entrypoint.sh /usr/local/bin/entrypoint.sh

RUN chown root:root /usr/local/bin/entrypoint.sh &&\
    chmod +x /usr/local/bin/entrypoint.sh

ENTRYPOINT ["/bin/sh","/usr/local/bin/entrypoint.sh"]
CMD ["php-fpm"]

And alpine-based:


ARG PHP_VERSION="7.4"
FROM  php:${PHP_VERSION}-fpm-alpine as base

RUN --mount=type=bind,from=mlocati/php-extension-installer:latest,source=/usr/bin/install-php-extensions,target=/usr/local/bin/install-php-extensions \
    /usr/local/bin/install-php-extensions xmlrpc mbstring zip xml intl soap gd opcache &&\
    apk update &&\
    apk add netcat-openbsd &&\
     rm -rf /var/cache/apk/* /var/tmp/* cache/* /var/lib/log/* &&\
    echo "max_input_vars=5000" > ${PHP_INI_DIR}/conf.d/moodle.ini

COPY ./scripts/entrypoint.sh /usr/local/bin/entrypoint.sh

RUN chown root:root /usr/local/bin/entrypoint.sh &&\
    chmod +x /usr/local/bin/entrypoint.sh

ENTRYPOINT ["/bin/sh","/usr/local/bin/entrypoint.sh"]
CMD ["php-fpm"]

And sometimes depending the argument of PHP_VERSION may or may not the package for installing netcat do exist (or exist with different names). Also apk add and apt-get increases the build times significally as well.

So is there an alternative approach?

4
  • 2
    "I want to avoid installing netcat" - do you have perl, python, php, telnet, socat, timeout, and/or bash? Please tell us (in your question) Commented Jan 3, 2024 at 21:21
  • The reason why is because in my case I will add extra layer or the netcat package name is named differently in different images. By doing so I slighly reduce the size and docker build time. Commented Jan 4, 2024 at 7:59
  • Also tese options may not shipped with a Docker image so using the existing lang is prefferable compared to normal linux distro. Commented Jan 4, 2024 at 8:07
  • 2
    Please put updates in your question. Not here in the comments Commented Jan 4, 2024 at 9:35

2 Answers 2

1

You could try reaching a port you know should work from the container --> X machine (ICMP has no concept of ports as TCP/UDP do) with a one-liner like:

timeout 2 bash -c "</dev/tcp/moodledb.example.com/80"; echo $?

A result of 0 means it is reachable.

Otherwise you would get something like this:

connect: Connection refused
line 1: /dev/tcp/moodledb.example.com/80: Connection refused

Note that you can replace the hostname with an IP and change tcp/udp depending on your scenario.

You can also run it outside your container, ie on the docker host machine with

docker exec -ti container_name timeout 2 bash -c "</dev/tcp/moodledb.example.com/80"; echo $?

Embed that in a script running every x seconds/minutes and you're golden :)

This is a true life-saver hack when working with containers that are missing packages like netcat and other network goodies

-1

Yes there is:

function pingdb {
    OK=0
    for i in $(seq 1 100); do
      echo "Pinging database attempt ${count} into ${MOODLE_DB_HOST}:${MOODLE_DB_PORT}" 
      if  $(php -r "is_resource(@fsockopen(\"${MOODLE_DB_HOST}\",intval(\"${MOODLE_DB_PORT}\")))?exit(0):exit(1);") ; then
        echo "Can connect into database"
        OK=1
        break
      fi
      sleep 5
    done


    if [ $OK -eq 1 ]; then
      echo "Database type: "${MOODLE_DB_TYPE}
      echo "DB Type: "${MOODLE_DB_TYPE}
    else
      echo >&2 "Can't connect into database"
      exit 1
    fi
}

As you can see the nc is replaced like this:

php -r "is_resource(@fsockopen(\"${MOODLE_DB_HOST}\",intval(\"${MOODLE_DB_PORT}\")))?exit(0):exit(1);"

The fsockopen takes 2 params:

  • host
  • port

What I do is try to open a socket in php and check if socket is oppened. If yes then I exit with 0 status code else I exit with 1. Each param is passed using a string that comes from shell script thus I encode the " characters using \ in order to convert the values into php strings.

Without using vars you can do it:

php -r "is_resource(@fsockopen(\"google.com",80)))?exit(0):exit(1);"

But in order to b safe I used intval at version using bash params.

5
  • 3
    Wouldn't this require you to have php installed though? What's the point of avoiding installing a standard tool like nc if you still need to install php? Wouldn't it make more sense to use things that are commonly found on *nix systems like bash itself, or perl or python etc? Commented Jan 3, 2024 at 21:56
  • In my case, I already have installed php in my docker image (I use docker php images) but I do not have netcat and installing it increases build time (because of package cache cleanups at docker build after I install netcat in my Dockerfile) Commented Jan 4, 2024 at 8:35
  • OK. Might be worth adding that to the question then since using php for something like this is just weird unless you absolutely have to. Commented Jan 4, 2024 at 9:44
  • 1
    @terdon, not sure I'd call netcat "standard"... Not just because it's not POSIX, but because there are multiple implementations of it with slightly different options. PHP might actually be better in that sense, since (AFAIK?) there's only one implementation, so if you have it, you know what you have. Of course Perl or just Bash might be even more likely to be available. Commented Jan 4, 2024 at 14:08
  • @ilkkachu fair, by "standard" I just meant "likely to be present on a nix system". Commented Jan 4, 2024 at 14:28

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.