Development Environment Setup

Docker is utilized extensively in the development environment of Screenly Anthias. The following provides a detailed description of the configuration process for development.

Docker Compose

The docker-compose.yml file orchestrates the services required during development. Below is an example configuration:

version: '3'
services:
  anthias-server:
    build:
      context: .
      dockerfile: docker/Dockerfile.server
    environment:
      - HOME=/data
      - LISTEN=0.0.0.0
      - CELERY_BROKER_URL=redis://redis:6379/0
      - CELERY_RESULT_BACKEND=redis://redis:6379/0
      - ENVIRONMENT=development
    restart: always
    volumes:
      - anthias-data:/data
      - ./:/usr/src/app/

  anthias-websocket:
    build:
      context: .
      dockerfile: docker/Dockerfile.websocket
    depends_on:
      - anthias-server
    environment:
      - HOME=/data
      - LISTEN=0.0.0.0
    restart: always
    volumes:
      - anthias-data:/data

  redis:
    image: redis:alpine
    platform: "linux/amd64"
    restart: always
    volumes:
      - redis-data:/var/lib/redis

  anthias-nginx:
    build:
      context: .
      dockerfile: docker/Dockerfile.nginx
    ports:
      - 8000:80
    environment:
      - HOME=/data
    depends_on:
      - anthias-server
      - anthias-websocket
    restart: always
    volumes:
      - anthias-data:/data:ro

volumes:
  anthias-data:
  redis-data:

Dockerfile

The main Dockerfile for the server in development is defined as follows:

FROM debian:bookworm

# Install required libraries and tools
RUN apt-get update && \
    apt-get -y install \
        build-essential \
        curl \
        git \
        python3-pip && \
    apt-get clean

# Set working directory
WORKDIR /usr/src/app

# Install Python requirements
COPY requirements/requirements.txt /tmp/requirements.txt
RUN pip3 install -r /tmp/requirements.txt

# Copy application source code
COPY . .

Development Commands

Common commands used in development involve setting up and running Docker containers. Below is an example command for building and running containers:

docker compose -f docker-compose.dev.yml up --build

This command builds images as specified in docker-compose.dev.yml and starts the defined services.

Dependencies Handling

To ensure that dependencies are managed properly within Docker, the .dockerignore file is used to exclude unnecessary files from the Docker context:

*.py[co]
*.git
*.github
*.egg
*.egg-info
dist
build
node_modules
venv

These entries ensure that the build context remains small and improves build efficiency.

Upgrading and Managing Containers

To manage containers, the bin/upgrade_containers.sh script is employed to rename containers and pull the latest images:

#!/bin/bash

if [[ -n $(docker ps | grep srly-ose) ]]; then
    set +e
    docker container rename srly-ose-wifi-connect anthias-wifi-connect
    # Additional renaming commands...
    set -e
fi

cat /home/${USER}/screenly/docker-compose.yml.tmpl | envsubst > /home/${USER}/screenly/docker-compose.yml

sudo -E docker compose -f /home/${USER}/screenly/docker-compose.yml pull

Testing with Docker

Docker compose can also be utilized to run tests within the defined development environment. The following segment showcases commands commonly used in CI frameworks:

- name: Build Containers
  run: |
    poetry run python tools/image_builder --dockerfiles-only --disable-cache-mounts --service celery --service redis --service test

- name: Start the test container
  run: |
    docker compose -f docker-compose.test.yml up -d --build

- name: Run the unit tests inside the container
  run: |
    docker compose -f docker-compose.test.yml exec anthias-test ./manage.py test --noinput --parallel --exclude-tag=integration

This snippet illustrates a structured approach to building, starting, and executing tests within a containerized environment.

Utility Functions

Certain utility functions can be defined in Python to assist with Docker checks, such as determining if the code is running within a Docker container:

import os

def is_docker():
    return os.path.isfile('/.dockerenv')

This function can be employed to conditionally run code based on the environment.

Sources:
- docker-compose.yml
- Dockerfile
- .dockerignore
- bin/upgrade_containers.sh
- .github/workflows/docker-test.yaml
- lib/utils.py