diff --git a/.env.example b/.env.example index 98cfe7b..61f5795 100644 --- a/.env.example +++ b/.env.example @@ -6,11 +6,11 @@ # - configure the Docker external port mapping for the postgres container # # Procedure: -# - Set a value for POSTGRES_PASSWORD, and LEARNDEV_DB_PASSWORD. +# - Set a value for POSTGRES_PASSWORD, LEARNDEV_DB_PASSWORD, MONGO_ROOT_PASSWORD # - Leave other variables unchanged because defaults are fine. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# ~~~ Postgres Docker container port mapping ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# ~~~ External port mapping for the postgres Docker container ~~~~~~~~~~~~~~~~~~~~~ # Host port mapped to the internal Postgres container's port 5432. # Only the host side is configurable here. 5432 is fixed inside the container. @@ -22,7 +22,7 @@ POSTGRES_PORT=5433 # Exposed postgres host network interface. # Docker accepts incoming requests on this interface and routes them # to Postgres running in the Docker container. -# Default value is 0.0.0.0 (IP v4)) and :: (IP V6), +# Default value (if unset) is 0.0.0.0 (IP v4) and :: (IP V6), # meaning all network interfaces. # See: https://docs.docker.com/engine/reference/commandline/run/#publish # @@ -55,13 +55,13 @@ POSTGRES_HOST_AUTH_METHOD=scram-sha-256 POSTGRES_PASSWORD=TODO_SET_A_VALUE_HERE -# ~~~ Application database and user ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# ~~~ Postgres application database and user ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Created by docker/init/01-create-app-db-user.sh **on first** container start. # These variables are also referenced in Spring Boot's application.yaml # configuration file to configure the datasource. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Name of the application database. +# Name of the (Postgres) application database, # LEARNDEV_DB_NAME=learndev @@ -75,6 +75,39 @@ LEARNDEV_DB_USER=learndev LEARNDEV_DB_PASSWORD=TODO_SET_A_VALUE_HERE +# ~~~~ MongoDB ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Name of the MongoDB admin user +# +MONGO_ROOT_USERNAME=mongoadmin + +# Password for the MongoDB admin user +# +MONGO_ROOT_PASSWORD=TODO_SET_A_VALUE_HERE + +# Name of the MongoDB application database +# +LEARNDEV_MONGO_DB_NAME=learndev + + +# ~~~ External port mapping for the mongo Docker Compose service ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Exposed MongoDB host network interface. +# Docker accepts incoming requests on this interface and routes them +# to MongoDB running in the Docker container. +# Default value (**if unset**) is 0.0.0.0 (IP v4) and :: (IP V6), +# meaning all network interfaces. +# See: https://docs.docker.com/engine/reference/commandline/run/#publish +# +MONGO_HOST=127.0.0.1 + +# MongoDB port mapped to the internal mongo container's port 27017. +# Only the host side is configurable here. 27017 is fixed inside the container. +# Use a non-standard port (e.g. 27018) to avoid clashing with a local MongoDB install. +# +MONGO_PORT=27018 + + # ~~~~ Spring Boot ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Default Spring Boot active profile: dev diff --git a/README.md b/README.md index beccd4b..070824a 100644 --- a/README.md +++ b/README.md @@ -69,27 +69,158 @@ See the [Tech Stack](#tech-stack) section. ### Installation -TODO +- Clone the `ebouchut/learn-dev` Git Repository +- Install Docker, Docker Desktop, and Docker Compose + +#### Clone the Git repository + +```shell +# +git clone git@github.com:ebouchut/learn-dev.git +# git clone https://github.com/ebouchut/learn-dev.git + +cd learn-dev +``` #### Docker Setup From the project root folder. +Install _Docker_ and _Docker Compose_: + +- on macOS (read [this for Windows or Linux install](https://docs.docker.com/get-started/get-docker/)): + ```shell + brew install docker docker-compose docker-desktop + ``` +- on [Windows and Linux](https://docs.docker.com/get-started/get-docker/) + + +## Configuration + +- Edit `.env` + - [ ] Set a value for the variables `POSTGRES_PASSWORD`, `LEARNDEV_DB_PASSWORD`, `MONGO_ROOT_PASSWORD` + + +## Run the application + +This starts all the Docker services for the application: -- Install Docker - - on macOS (read [this for Windows or Linux install](https://docs.docker.com/get-started/get-docker/)): - ```shell - brew install docker docker-compose docker-desktop - ``` - - on [Windows and Linux](https://docs.docker.com/get-started/get-docker/) -- Downloads the Docker images for this application, - then runs the containers configured in the `docker-compose.yaml` configuration file: ```shell docker compose up -d - docker compose logs ``` - A Docker init script creates the application database and user when the `learn-dev-postgres` container - is run for the first time. -- Run the application: TODO + +**For each service** (`postgres`, `mongo`) +declared in the *Docker Compose* configuration file +(`docker-compose.yaml`), *Docker Compose*: + +1. downloads the Docker image (if not cached yet) from the Docker Hub registry, +2. stores the downloaded image in the local Docker image cache, +3. starts a Docker container based on this image (if it is not already running). + +## Stop the Application + +This stops all the Docker services for the application: + + ```shell + docker compose down + ``` + + +### Docker Terminology + +I use ** Docker Compose** (a CLI tool) to describe and handle the lifecycle of services that comprise my application. + +A **service** is basically a component of the application packaged as a Docker container. +It specifies the Docker image and version, configuration, and the network and Docker volume(s) if any. + +A Docker image is pre-packaged piece of software that can work as a standalone on Linux. +**Docker Hub** is a public registry that hosts and serves public Docker images. + + +### Postgres Service + +#### Start Postgres + +Running the app using `docker compose up -d` +starts **all** the application services, including `postgres`. + +To only start the `postgres` service: + +```shell +docker compose start -d postgres +docker compose logs postgres +``` +> [!NOTE] +> +> The above command downloads, installs the `postgres` Docker image +> specified by the `postgres` service in `docker-compose.yaml`. +> Then it runs a Docker container with this image. + +> [!NOTE] +> A Docker init script automatically **creates the database user and the application database** +> when the **`postgres`** service is run **for the first time**. + +Now, check that `postgres` is running: + +```shell +docker compose ps | grep postgres +``` + +> To recreate the database, and start from scratch you need to stop the `postgres` container +> and remove the (data) volumes. +> See the `Remove all Posgres Databases` section for details. + +#### Stop Postgres + +```shell +docker compose stop postgres +``` + +#### Remove all Postgres Databases + +Stops and remove the `postgres` container and its data volume. + +> [!CAUTION] +> This is a **destructive command** that will **remove all the databases +> (structure and content)** created by Postgres running in the container. + +```shell +docker compose stop postgres # Stop the container +docker rm postgres # Remove the container +docker volume rm pg_data # Remove the named volume +``` + + +### Mongo Service + +#### Start MongoDB + +```shell +docker compose start mongo +``` + +Now, check that `mongo` is running: + +```shell +docker compose ps | grep mongo +``` + +#### Stop MongoDB + +```shell +docker compose stop mongo +``` + +#### Remove MongoDB and its Databases + +> [!CAUTION] +> This **destructive command** will stop and remove the container, then **remove** its data **volume** +> (all the databases created by MongoDB running in the container). + +```shell +docker compose stop mongo # Stop container +docker rm mongo # Remove the stopped container +docker volume rm learn-dev_mongo_data # Remove the named volume +``` ## Project Status diff --git a/docker-compose.yaml b/docker-compose.yaml index 15be136..634038c 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,24 +1,52 @@ services: - db: + postgres: image: postgres:17 - container_name: learn-dev-postgres - - # Inject database credentials and config (db name, db user, - # and host port mapping) into the container. - # Reads from the same .env file passed to `docker compose --env-file ...`. + # Inject into the container the database credentials and configuration variables defined in the .env file + # (database names , database user, host and port mappings) + # as environment variables. + # This is required for the docker init script in ./docker/init/. env_file: - .env - + networks: + - net volumes: # Init scripts: run once on first container start (empty data dir). - ./docker/init:/docker-entrypoint-initdb.d # Named volume: preserves data across container stop/start cycles. - - pgdata:/var/lib/postgresql/data - + - pg_data:/var/lib/postgresql/data ports: # See src/main/resources/.env.example for details - "${POSTGRES_HOST}:${POSTGRES_PORT}:5432" + mongo: + image: mongo:8.0 + restart: unless-stopped + ports: + - "${MONGO_HOST}:${MONGO_PORT}:27017" + environment: + MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USERNAME} + MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD} + MONGO_INITDB_DATABASE: ${LEARNDEV_MONGO_DB_NAME} + volumes: + - mongo_data:/data/db + - ./docker/mongo/init:/docker-entrypoint-initdb.d:ro + networks: + - net + healthcheck: + test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 20s + +networks: + net: + # A bridge network connects your services together + # on an isolated Virtual LAN managed by Docker. + driver: bridge + +# Named volumes used to preserve data across container stop/start cycles. volumes: - pgdata: + pg_data: + mongo_data: diff --git a/docker/mongo/init/.gitkeep b/docker/mongo/init/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index bc4f532..905dfb2 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -2,6 +2,11 @@ spring: application: name: learn-dev + data: + mongodb: + # uri: mongodb://admin:admin_password@127.0.0.1:27018/learndev?authSource=admin + uri: mongodb://${MONGO_ROOT_USERNAME}:${MONGO_ROOT_PASSWORD}@${MONGO_HOST}:${MONGO_PORT}/${LEARNDEV_MONGO_DB_NAME}?authSource=admin + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Database Connection Configuration # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~