Dockerfile example

# Load container base image
FROM python:alpine

# Create and set variables
ARG ENVIR="DEV"
ARG VENV_PATH=/opt/.venv
ARG APP_DIR=/usr/src/app/docker_python_template

# Set where shell commands will run from
WORKDIR /usr/src/app

# Below libraries may be required depending on pip requirements
#RUN apk update && apk add --no-cache gcc musl-dev linux-headers

# Set environment variables and createa Python venv
ENV VIRTUAL_ENV=$VENV_PATH
RUN python3 -m venv $VIRTUAL_ENV
ENV PATH="$VIRTUAL_ENV/bin:$PATH"

# Update pip ready for requirements
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools
RUN pip install wheel

# Copy just requirements and pip install them, this reduces the amount of container changes in the future, as the requirements file may stay static, while the rest of the project files change
COPY requirements.txt .
COPY requirements.dev.txt .
RUN if [ "$ENVIR" = "PROD" ] ; then pip install -r requirements.txt ; else pip install -r requirements.dev.txt ; fi

# Copy all files that exist where you ran this Dockerfile into the WORKDIR
COPY . .

# Move into the application subdirectory
WORKDIR $APP_DIR

# What runtime to execute
ENTRYPOINT ["python"]

# Commands attached to executable
CMD ["main.py"]

Docker Commands

# search for Docker containers on Docker Hub
docker search container_name

# download container from Docker Hub
docker pull container_name

# show all running containers
docker ps

# show all existing containers
docker ps -a

# start docker container
docker start container_id_or_tag

# stop docker container
docker stop container_id_or_tag

# delete a stopped container
docker rm container_id_or_tag

# stop and remove container in one command
docker rm -f container_id_or_tag

# remove all docker containers
docker rm $(docker ps -aq)

# list all images on computer
docker images

# check file size of container items for troubleshooting size issues
docker image history container_id

# delete a specific image
docker rmi image_id

# delete all images
docker rmi $(docker images -q)

# monitor container logs
docker logs -f container_id_or_tag

# execute a command in a running docker container
# -i - interactive command
# -t - run in terminal
docker exec -it container_id_or_tag command

# update an image
#   build new container with Dockerfile in current dir
docker build -t container_name .
#   stop and remove old container
#   use docker run or docker-compose to start updated container

# create new container from other container
docker commit -m "change comment" -a "author_name" docker_image_number dockerhub_user/docker_image_name

# scan for security vulnerabilities
docker scan ContainerID

Docker run

# docker-compose.yml files remove the need for these as the command can get quite complex
docker run --rm -d -p --name container_name 1000:1000 -w /folder/name -v volume_name:/path/in/container --network network_name --network-alias container_network_name sh -c "echo 'hello world'"

# automatically remove the container image once closed
--rm

# detach/daemon mode, run container in background
-d

# expose network ports, first item is container port, second is hosts port
-p 1000:1000

# set a name for the running container, otherwise it will be given a random phrase name
--name container_name

# sets working directory in container
-w /folder

# sets volume mount in container
-v volume_name:/path/in/container

# attach network to container
--network network_name

# give an network alias to container network, similar to dns name
--network-alias container_network_name

# you can run additional commands at the end of a docker run command, this will run a command in the default shell
sh -c "echo 'hello world'"

# interactive and terminal options to type in commands after container starts
-it

Docker networks

# create docker network
docker network create network_name

# list docker networks
docker network list

# delete docker network
docker network remove network_name

# attach a container to a network and give network alias
docker run -d --network todo-app --network-alias mysql -v todo-mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=todos mysql:5.7
--network todo-app - network to use
--network-alias mysql - alias name for connection, a dns name

# troubleshoot docker networks
#   install and run a network troubleshooting container in your docker network
docker run -it --network network_name nicolaka/netshoot
#   run the dig command against other containers network alias to report ip address and other settings
dig network_alias

Docker volumes

# create named volume for persistant data
docker volume create volume_name

# find location of volume
docker volume inspect volume_name

# create mount point in container for persistant volume
docker run -v volume_name:/path/in/container container_name

# create a mount point that is an already existing folder, useful for dev work, $(pwd) is current working dir
docker run -v "$(pwd):/path/in/container"

# list docker volumes
docker volume list

# delete docker volume
docker volume remove volume_name

Docker-compose example

# docker-compose specification version
version: "3.8"

# list each distinct container to run
services:
  # name of container
  app:
    image: node:12-alpine
    # commands to run at build
    command: sh -c "yarn install && yarn run dev"
    # pull pass from secrets file below
    secrets:
      - db-password
    restart: always
    ports:
      - 3000:3000
    # change working dir
    working_dir: /app
    # link an existing dir to a folder in the container
    volumes:
      - ./:/app
    environment:
      MYSQL_HOST: mysql
      MYSQL_USER: root
      MYSQL_PASSWORD_FILE=/run/secrets/db-password
      MYSQL_DB: todos

  mysql:
    image: mysql:5.7
    restart: always
    secrets:
      - db-password
    # link to stored Docker container volume
    volumes:
      - todo-mysql-data:/var/lib/mysql
    environment: 
      MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db-password
      MYSQL_DATABASE: todos

volumes:
  todo-mysql-data:

# store sensitive data without it being exposed in docker-compose file
secrets:
  db-password:
    file: db/password.txt

Docker-compose commands

# run command to start from a compose file and run in background
docker-compose up -d

# kill a compose setup
docker-compose down

# kill a compose setup AND wipe volumes
docker-compose down --volumes

# secrets in env variables
#   you can prepend FILE__ to many env variables to then load from a file, instead of putting secret in the command
#   eg. -e PASSWORD=Toast becomes -e FILE__PASSWORD=/some/secret.txt

# run the app via compose, removing container once complete
docker-compose run --rm app

# run another python item inside the container via compose
docker-compose run --rm app somefile.py

# rebuild the image to pull in new data
docker-compose build
docker-compose -f docker-compose.dev.yml build

# dev environment example
docker-compose -f docker-compose.dev.yml run --rm app-dev other.py