3
\$\begingroup\$

What's up? this is a small project to teach myself Docker. This Docker setup works, healthchecks pass for both app and mysql, app is initialized and is listening as expected, what I'm looking is a feedback on the docker-compose and the Dockerfile parts.

FROM python:3-alpine3.16
ENV FLASK_APP=app
ENV FLASK_ENV=development
# The EXPOSE instruction indicates the ports on which a container 
# will listen for connections
EXPOSE 8080
# Sets the working directory for following COPY and CMD instructions
# Notice we haven’t created a directory by this name - this instruction 
# creates a directory with this name if it doesn’t exist
WORKDIR /app
# Update Python
RUN python3 -m pip install --upgrade pip setuptools wheel; \
 apk add --no-cache curl
# Install any needed packages specified in requirements.txt
COPY ./app/requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r /app/requirements.txt
COPY ./app/app.py /app/app.py
# the INTERNAL port of the app, inside the container
ENV INTERNAL_APP_PORT=8080
HEALTHCHECK --timeout=2s CMD curl --fail http://localhost:${INTERNAL_APP_PORT}/health || exit 1
ENTRYPOINT [ "python3", "app.py" ]
version: "3.7"
services:
 app:
 platform: linux/amd64
 build: .
 links:
 - db
 ports:
 - "${EXTERNAL_APP_PORT:-8080}:8080"
 depends_on:
 db:
 condition: service_healthy
 volumes:
 - /usr/share/billing_app/:/app/in
 db:
 platform: linux/amd64
 image: mysql:8
 environment:
 MYSQL_ROOT_PASSWORD: password
 MYSQL_DATABASE: billdb
 MYSQL_USER: billdb_owner
 MYSQL_PASSWORD: password
 volumes:
 - ./db:/docker-entrypoint-initdb.d/
 healthcheck:
 test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
 timeout: 20s
 retries: 10

Thank you

asked Jun 21, 2022 at 22:53
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

This is not a full review, just the things I know about.

Databases and containers

Your project is for learning how to use Docker. I would never put a production database into a container for any other reason. Containers are ephemeral, if they cease to exist your application should not be impacted. Databases are not ephemeral and need to exist continually, otherwise the application (probably) stops working. In some very specific scenarios a database in a container might make sense, but usually only if the data is stored on a separate partition that another database can use when your container, inevitably, stops working.

Database health checks

healthcheck:
 test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
 timeout: 20s
 retries: 10

This checks to see whether the database server has started, not whether the database on the database server is accessible. It's possible that the database will not be accessible when your app starts as a result.

I'd prefer to check whether or not the database is working as sylhare does in Docker-compose check if mysql connection is ready.

healthcheck:
 test: "/usr/bin/mysql --user=root --password=rootpasswd --execute \"SHOW DATABASES;\""
 timeout: 20s
 retries: 10

Dependencies

You're using the long syntax for dependency management

depends_on:
 db:
 condition: service_healthy

There's a shorter syntax, that does less, but is sufficient in this situation:

depends_on:
 - db

Secrets

Your secrets are in plain text, which makes it easier for them to be accessed. The files should be stored on version control, another method of plain text secrets to leak.

environment:
 MYSQL_ROOT_PASSWORD: password
 MYSQL_DATABASE: billdb
 MYSQL_USER: billdb_owner
 MYSQL_PASSWORD: password

Always store secrets encrypted to prevent unauthorised access. Docker has a syntax for accessing secrets that you should prefer. Better would be to make use of a secret management service and not deploying secrets along with the container, but that might be a bit much for a learning exercise.

answered Jun 22, 2022 at 15:52
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Did you mean that secrets files should not be stored in version control, as that creates a risk of data leaks? \$\endgroup\$ Commented Jun 22, 2022 at 17:44
  • 1
    \$\begingroup\$ I meant that files should definitely be stored on version control, but that's just another reason to not put plaintext secrets in the file @TomG. Preferentially I'd store secrets in a specific store that's accessible to the container, but for a learning exercise using the secrets functionality in Compose is sensible. \$\endgroup\$ Commented Jun 22, 2022 at 18:22
  • 1
    \$\begingroup\$ Secrets tend to be environment specific: eg. test database has different credentials than production, so the secrets can be provided via . environment variables or .env files. And these should not be checked in. Of course this doesn't get around the issue of storing secrets in plaintext. But it keeps them isolated to the relevant host. \$\endgroup\$ Commented Jun 22, 2022 at 18:56
  • \$\begingroup\$ Thanks @TomG and Ben, I think storing them in an .env file is kinda the same as keeping them in the YML - if both files are source controlled, I was suggested however that git has the option to ignore some lines in a file - stage the file but not specific lines in it, this will allow the files to be tracked without exposing the passwords. Actually, for that use case - an .env file is better because you know that your variables will be kept on the same line - while in the YML file, the secrets position in the YML are more likely to change because it's a more dynamic file. \$\endgroup\$ Commented Jun 23, 2022 at 17:59
  • \$\begingroup\$ Thanks @Ben - About the DB healthcheck - good point, about data integrity - with this MySQL Docker hub image, the data is stored on a volume, volumes outlive their containers, unless specifically deleted with docker volume prune or docker system prune --volumes (these commands delete volumes not linked to any container) \$\endgroup\$ Commented Jun 23, 2022 at 18:06

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.