Reputation: 563
I wan't to check whether a server/device is reachable or not, by using a python script running inside docker.
I'm using python 3.7.
The script looks like the following snipped (scriped down)
import platform
import subprocess
import asyncio
from argparse import ArgumentParser
from time import sleep
from models.configuration import Configuration
parser = ArgumentParser()
# device ip or hostname
parser.add_argument(
'-d', '--device',
type=str,
required=True,
)
async def main():
args = parser.parse_args()
configuration = Configuration(args) # the configuration object stores the arguments
param = '-n' if platform.system().lower() == 'windows' else '-c'
while True:
result = subprocess.call(['ping', param, '1', configuration.device])
print(f'## {result}')
# TODO: result = 0 => success, result > 0 => failure
sleep(5)
if __name__ == '__main__':
asyncio.run(main())
My Dockerfile:
FROM python:3.7
WORKDIR /usr/src/app
COPY . .
RUN pip install --no-cache-dir -r requierments.txt
ENTRYPOINT [ "python3", "./main.py", "-d IP_OR_HOSTNAME" ]
I also tried CMD
instead of ENTRYPOINT
.
I build and start the container with the following commands
docker build -t my-app .
docker run -it --network host --name my-app my-app
Running the script by docker, the ping command exits with the exit code 2 (Name or Service not known
).
When I start the script from the shell inside the container (python3 /usr/src/app/main.py -d IP_OR_HOSTNAME
), the device is reachable (exit code 0).
As far as I know I have to use the network mode host
.
Any ideas why the script cannot reach the device when launched by docker, but from shell inside the container?
(I am open to suggestions for a better title)
Upvotes: 1
Views: 176
Reputation: 159697
The various Dockerfile commands that run commands have two forms. In shell form, without special punctuation, Docker internally runs a shell and the command is broken into words using that shell's normal rules. If you write the command as a JSON array, though, it uses an exec form and the command is executed with exactly the words you give it.
In your command:
ENTRYPOINT [ "python3", "./main.py", "-d IP_OR_HOSTNAME" ]
There are three words in the command: python3
, ./main.py
, and then as a single argument -d IP_OR_HOSTNAME
including an embedded space. When the Python argparse
module sees this, it interprets it as a single option with the -d
short option and text afterwards, and so the value of the "hostname" option is IP_OR_HOSTNAME
including a leading space.
There are various alternate ways to "spell" this that will have the effect you want:
# Split "-d" and the argument into separate words
ENTRYPOINT ["python3", "./main.py", "-d", "IP_OR_HOSTNAME"]
# Remove the space between "-d" and its option
ENTRYPOINT ["python3", "./main.py", "-dIP_OR_HOSTNAME"]
# Use the shell form to parse the command into words "normally"
ENTRYPOINT python3 ./main.py -d IP_OR_HOSTNAME
Upvotes: 2