Let’s break down what this script does in detail. The script is named new_docker_compose_file.sh, authored by GJS (homelab-alpha), and its purpose is to create a new Docker-Compose file along with configuration files based on user input. This can help streamline the setup of Docker containers with specific configurations.

Here’s a detailed explanation:

Script Metadata

  • Filename: new_docker_compose_file.sh
  • Author: GJS (homelab-alpha)
  • Date: May 18, 2024
  • Version: 1.0.1
  • Description: The script provides a function to create a new Docker-Compose file and configuration files based on user input.
  • RAW Script: new_docker_compose_file.sh

Command Validation

The script starts by validating the existence of required commands (mkdir, touch, chown). If any of these commands are not found, it exits with an error message.

for cmd in mkdir touch chown; do
  if ! command -v "$cmd" &>/dev/null; then
    echo "ERROR: $cmd command not found. Please install it and try again."
    exit 1
  fi
done

Message Display Function

A function display_message is defined to format and display messages to the user.

display_message() {
  echo -e "\n$1\n"
}

User Input for Container Name

The script prompts the user to input the name of the new Docker container. It reads the input and validates it to ensure it only contains letters, numbers, underscores, and hyphens.

display_message "What is the name of the new Docker container:"
read -r container_name

if [[ ! "$container_name" =~ ^[a-zA-Z0-9_-]+$ ]]; then
  display_message "Invalid container name. Use only letters, numbers, underscore (_), and hyphen (-)."
  exit 1
fi

Directory Setup

The base directory for Docker containers is specified, and the path for the new container is determined. The script checks if the directory already exists, and if so, it exits with an error message. Otherwise, it creates the necessary directories.

base_dir="$HOME/Docker"
dir_path="$base_dir/$container_name"

if [ -d "$dir_path" ]; then
  display_message "The directory already exists. Choose a different name for the container."
  exit 1
fi

if ! mkdir -p "$dir_path"; then
  display_message "Failed to create directory: $dir_path"
  exit 1
fi

Creating Configuration Files

The script creates .env and docker-compose.yml files in the specified directory. If it fails to create these files, it exits with an error message.

if ! touch "$dir_path/.env" "$dir_path/docker-compose.yml"; then
  display_message "Failed to create Docker startup files in $dir_path."
  exit 1
fi

Populating .env File

The .env file is populated with template content, including placeholders for API keys, secrets, and MySQL configuration.

cat <<EOL >"$dir_path/.env"
# API keys and secrets
API_KEY=
SECRET_KEY=

# App configuration
MYSQL_HOST_APP=${container_name}
MYSQL_PORT_APP=3306
MYSQL_NAME_APP=${container_name}
MYSQL_USER_APP=${container_name}
MYSQL_PASSWORD_APP=

# Database configuration
MYSQL_ROOT_PASSWORD_DB="
MYSQL_DATABASE_DB=${container_name}_db
MYSQL_USER_DB=${container_name}
MYSQL_PASSWORD_DB=
EOL

Populating docker-compose.yml File

The docker-compose.yml file is populated with a template configuration for the Docker services. This includes network settings, service definitions, and environment variables.

cat <<EOL >"$dir_path/docker-compose.yml"
version: "3.9"

networks:
  ${container_name}_net:
    attachable: false
    internal: false
    external: false
    name: ${container_name}
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.20.0.0/24
          ip_range: 172.20.0.0/24
          gateway: 172.20.0.1
    driver_opts:
      com.docker.network.bridge.default_bridge: "false"
      com.docker.network.bridge.enable_icc: "true"
      com.docker.network.bridge.enable_ip_masquerade: "true"
      com.docker.network.bridge.host_binding_ipv4: "0.0.0.0"
      com.docker.network.bridge.name: "${container_name}"
      com.docker.network.driver.mtu: "1500"
    labels:
      com.${container_name}.network.description: "is an isolated bridge network."

services:
  ${container_name}_db:
    restart: unless-stopped
    logging:
      driver: "json-file"
      options:
        max-size: "1M"
        max-file: "2"
    stop_grace_period: 1m
    container_name: ${container_name}_db
    image: change_me:latest
    init: false
    pull_policy: if_not_present
    volumes:
      - /docker/${container_name}/production/db:/change_me
    environment:
      PUID: "1000"
      PGID: "1000"
      TZ: Europe/Amsterdam
      MYSQL_RANDOM_ROOT_PASSWORD:
      MYSQL_ROOT_PASSWORD:
      MYSQL_DATABASE: "${container_name}_db"
      MYSQL_USER: "${container_name}"
      MYSQL_PASSWORD:
    command: ["--transaction-isolation=READ-COMMITTED", "--log-bin=binlog", "--binlog-format=ROW"]
    hostname: ${container_name}_db
    networks:
      ${container_name}_net:
        ipv4_address: 172.20.0.2
    security_opt:
      - no-new-privileges:true
    labels:
      com.${container_name}.db.description: "is a MySQL database."

  ${container_name}_app:
    restart: unless-stopped
    logging:
      driver: "json-file"
      options:
        max-size: "1M"
        max-file: "2"
    stop_grace_period: 1m
    container_name: ${container_name}
    image: change_me:latest
    init: false
    pull_policy: if_not_present
    volumes:
      - /docker/${container_name}/production/app:/change_me
    env_file:
      - .env
    environment:
      PUID: "1000"
      PGID: "1000"
      TZ: Europe/Amsterdam
      MYSQL_HOST: "${container_name}_db"
      MYSQL_PORT: 3306
      MYSQL_NAME: "${container_name}_db"
      MYSQL_USER: "${container_name}"
      MYSQL_PASSWORD:
    command: ["change_me"]
    entrypoint: ["change_me"]
    domainname: ${container_name}.my-lan.nl
    hostname: ${container_name}
    extra_hosts:
      ${container_name}: "0.0.0.0"
    networks:
      ${container_name}_net:
        ipv4_address: 172.20.0.3
    dns:
      - 8.8.8.8
      - 8.8.4.4
    dns_search:
      - dc1.example.com
      - dc2.example.com
    dns_opt:
      - use-vc
      - no-tld-query
    ports:
      - ":/tcp"
      - ":/udp"
    devices:
      - "/dev/ttyUSB0:/dev/ttyUSB0"
      - "/dev/ttyACMO"
      - "/dev/sda:/dev/xvda:rwm"
    security_opt:
      - no-new-privileges:true
      - label:user:USER
      - label:role:ROLE
    cap_add:
      - CHANGE_ME
    cap_drop:
      - CHANGE_ME
    labels:
      com.docker.compose.project: "${container_name}"
      com.${container_name}.description: "change_me."

volumes:
  ${container_name}_db:
    external: true
  ${container_name}_app:
    external: true

secrets:
  mysql_root_passwrd:
    file: change_my.txt
    external: true
  mysql_db:
    file: change_my.txt
    external: true
  mysql_user:
    file: change_my.txt
    external: true
  mysql_password:
    file: change_my.txt
    external: true
  ${container_name}_admin_user:
    file: change_my.txt
    external: true
  ${container_name}_db_admin_password:
    file: change_my.txt
    external: true
EOL

Completion Message

Finally, the script displays a message indicating that the Docker Compose file has been created in the specified directory.

display_message "Docker Compose File is created in $dir_path"

Conclusion

In summary, this script automates the creation of a Docker Compose setup for a new container, including the necessary directories and configuration files, based on user-provided input for the container name. It ensures required commands are available, validates user input, creates necessary files and directories, and populates the configuration files with appropriate template content.

Last updated 22 Sep 2024, 12:15 CEST . history