I have a flask app that uses rabbitmq where both are docker containers (along with other components, such as a celery workers). I want to use a common .env
environment file for both dev and container use in my docker-compose
.
Example .env
RABBITMQ_DEFAULT_HOST=localhost
Now, if I use this with with flask run
it works fine as the container rabbitmq port is mapped to the host. If I run this inside the flask docker container, it fails because localhost
of the flask container is not the same as the host. If I change localhost to my container name, rabbitmq
.
RABBITMQ_DEFAULT_HOST=rabbitmq
It will resolve nice inside the flask container via docker to the dynamic ip of the rabbitmq container (local port map not even necessary), however, my flask run
during development has no knowledge of this name / ip mapping and will fail.
Is there any easy way to handle this so it’s easily portable to other devs and just "works" when either outside using flask run
or inside the container via docker-compose
?
I’d also like to limit the port exposure if possible, such as 127.0.0.1:5672:5672
.
Update
So far, this is the best I’ve come up with.. in the program, I use a socket to check if the name resolves, if not, then it looks to the env with a default to localhost.
import socket
def get_rabbitmq_host() -> str:
try:
return socket.gethostbyname("rabbitmq") # container name
except socket.gaierror:
return os.getenv("RABBITMQ_DEFAULT_HOST", "localhost")
Here is another method I tried that’s a lot faster (no dns timeout), but changes the order a bit.
def get_rabbitmq_host() -> str:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(1)
result = sock.connect_ex(("127.0.0.1", 5672))
sock.close()
if result == 0:
return "127.0.0.1"
elif (
os.getenv("RABBITMQ_DEFAULT_HOST") == "localhost"
or os.getenv("RABBITMQ_DEFAULT_HOST") == "127.0.0.1"
):
return "rabbitmq"
else:
return os.getenv("RABBITMQ_DEFAULT_HOST", "rabbitmq")
2
Answers
Well no, not really. Or yes, depending on how you view it.
Since now you find out that
localhost
does not mean the same in every context, nmaybe you should split up the variables, even though in some situations it maybe have the same value.So just something like
Well: that is the point of the
.env
files. You have to differentenvironments
there, so make two different.env
files. Or let everyone adjust the.env
file according to her/his preferred way of running the app.If you connect from container to container within a docker network, you do not need to publish the port at all. Only ports that have to be accessed from outside the network.
I am not sure if I completely understood your situation. I am assuming that you are developing the application and have environment which you would like to have it separated in accordance to the environment for example localhost, development, test etc …
With that assumption as above. I would suggest to have env’s in accordance to the environment like env_localhost, env_development where each key=value will be in accordance to the environment. Also, have an env.template file with empty key= so that if someone does not want a docker based runs then can setup that accordingly in a new file calling it the .env.
Once the above is created now you can modify your docker build for the app the
Dockerfile
I mean where you can utilise the following snippet. The important part is the environment variable called SETUP and the rename of the environment to .env during the build process:After the modification of the
Dockerfile
, now you can perform docker-compose build according to the environment by passing a SETUP as env to the build as follows:Additionally, once this process is stable you can create a Makefile and have
make build-local
,make build-dev
and so on.