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

\$\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.

\$\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\$
    – TomG
    Jun 22 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\$
    – Ben
    Jun 22 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\$
    – TomG
    Jun 22 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\$
    – aTEdushu
    Jun 23 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\$
    – aTEdushu
    Jun 23 at 18:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.