diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..12fde7d --- /dev/null +++ b/.env.example @@ -0,0 +1,22 @@ +# Copy this file to .env before running Docker Compose: +# cp .env.example .env + +# Published image to run. Use a different repository or tag if you are testing +# a fork or a specific release. +PYMC_REPEATER_IMAGE=pymcdev/pymc-repeater:dev +# PYMC_REPEATER_IMAGE=yellowcooln/pymc-repeater:dev + +# SPI/GPIO access uses the host's numeric group IDs. Check your host with: +# getent group gpio +# getent group spi +# Example output: +# gpio:x:997: +# spi:x:999: +# Put the third field from each output line below. +GPIO_GID=986 +SPI_GID=989 + +# Local build only. These are used by docker-compose.build.yml if you build the +# image yourself instead of pulling PYMC_REPEATER_IMAGE. +PUID=15888 +PGID=15888 diff --git a/.gitignore b/.gitignore index 03a1ce0..3942f65 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ htmlcov/ *~ # Config +.env config.yaml config.yaml.backup identity.json diff --git a/README.md b/README.md index 9c028b2..69e1669 100644 --- a/README.md +++ b/README.md @@ -349,7 +349,13 @@ You can now run pyMC Repeater from within a [Docker Container](https://www.docke Here is what you'll need to do in order to get the container running: -1. Create the bind mount directories and copy the example config into the +1. Copy the Docker environment example and adjust it for your host if needed. + +```bash +cp .env.example .env +``` + +2. Create the bind mount directories and copy the example config into the Docker config directory. ```bash @@ -357,26 +363,30 @@ mkdir -p ./config ./data cp ./config.yaml.example ./config/config.yaml ``` -2. Run the configuration script and follow the prompts. +Do not bind mount `./config.yaml` directly. The supported Docker layout mounts +the whole `./config` directory to `/etc/pymc_repeater`, with the config file at +`./config/config.yaml`. + +3. Run the configuration script and follow the prompts. ```bash sudo bash ./setup-radio-config.sh ./config ``` -3. Review `./config/config.yaml` before first start. You can preconfigure the +4. Review `./config/config.yaml` before first start. You can preconfigure the radio, location, and web UI password there, or leave first-run setup to the web interface. -4. Configure the [docker compose](./docker-compose.yml) to your specific hardware and file paths. Be sure to comment-out or delete lines that aren't required for your hardware. Please note that your hardware devices might be at a different path than those listed in the docker compose file. By default, the compose file pulls the published `pymcdev/pymc-repeater:dev` image. If you need a different image tag or repository, set `PYMC_REPEATER_IMAGE` in a `.env` file. +5. Configure the [docker compose](./docker-compose.yml) to your specific hardware and file paths. Be sure to comment-out or delete lines that aren't required for your hardware. Please note that your hardware devices might be at a different path than those listed in the docker compose file. By default, the compose file pulls the published `pymcdev/pymc-repeater:dev` image. If you need a different image tag or repository, set `PYMC_REPEATER_IMAGE` in `.env`. -5. Make the bind mount directories writable by the container user. The image +6. Make the bind mount directories writable by the container user. The image runs as UID/GID `15888` by default. ```bash sudo chown -R 15888:15888 ./config ./data ``` -6. If you are using SPI/GPIO hardware, make sure the `GPIO_GID` and `SPI_GID` +7. If you are using SPI/GPIO hardware, make sure the `GPIO_GID` and `SPI_GID` values match the numeric group IDs on your host. These IDs can vary by OS image, so check the host before starting the container. If the values do not match your host, put the correct numeric IDs in `.env`. @@ -393,14 +403,14 @@ gpio:x:997: spi:x:999: ``` -Example `.env`: +Example `.env` values: ```bash GPIO_GID=997 SPI_GID=999 ``` -7. Pull and start the container. +8. Pull and start the container. ```bash docker compose pull @@ -408,8 +418,11 @@ docker compose up -d ``` If you are developing locally and want Docker Compose to build the image from -this checkout instead, uncomment the `build:` block in `docker-compose.yml` and -run `docker compose up -d --build`. +this checkout instead, use the local build override: + +```bash +docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build +``` ## Roadmap / Planned Features diff --git a/docker-compose.build.yml b/docker-compose.build.yml new file mode 100644 index 0000000..8933b8d --- /dev/null +++ b/docker-compose.build.yml @@ -0,0 +1,10 @@ +services: + pymc-repeater: + build: + context: . + dockerfile: dockerfile + args: + PUID: ${PUID:-15888} + PGID: ${PGID:-15888} + GPIO_GID: ${GPIO_GID:-986} + SPI_GID: ${SPI_GID:-989} diff --git a/docker-compose.yml b/docker-compose.yml index 78633bd..eda6d96 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,16 +1,6 @@ services: pymc-repeater: image: ${PYMC_REPEATER_IMAGE:-pymcdev/pymc-repeater:dev} - # Uncomment this block to build from a local checkout instead of pulling - # the published Docker image. - # build: - # context: . - # dockerfile: dockerfile - # args: - # PUID: ${PUID:-15888} - # PGID: ${PGID:-15888} - # GPIO_GID: ${GPIO_GID:-986} - # SPI_GID: ${SPI_GID:-989} container_name: pymc-repeater restart: unless-stopped ports: @@ -24,7 +14,7 @@ services: # SPI DEVICES PERMISSIONS cap_add: - SYS_RAWIO - # USB DEVICSE PERMISSIONS + # USB DEVICE PERMISSIONS group_add: - "${GPIO_GID:-986}" - "${SPI_GID:-989}" diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 518b1da..eb17104 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -18,6 +18,16 @@ print_permission_help() { echo "For the default image user, run: sudo chown -R ${RUNTIME_UID}:${RUNTIME_GID} ./config ./data" >&2 } +fail_bad_config_mount() { + echo "Invalid Docker config mount: ${CONFIG_PATH} is a directory, but it must be the config file." >&2 + echo "This usually happens when ./config.yaml is bind-mounted before that host file exists." >&2 + echo "Use the supported folder mount instead:" >&2 + echo " - ./config:/etc/pymc_repeater" >&2 + echo "Then place the config at ./config/config.yaml." >&2 + print_permission_help + exit 1 +} + copy_or_die() { src="$1" dest="$2" @@ -94,6 +104,10 @@ merge_config_from_example() { trap - EXIT HUP INT TERM } +if [ -d "${CONFIG_PATH}" ] && [ "$(basename "${CONFIG_PATH}")" = "config.yaml" ]; then + fail_bad_config_mount +fi + if [ ! -f "${EXAMPLE_PATH}" ] && [ -f "${BUNDLED_EXAMPLE_PATH}" ]; then if ! cp "${BUNDLED_EXAMPLE_PATH}" "${EXAMPLE_PATH}"; then echo "Could not copy bundled example config to ${EXAMPLE_PATH}; using bundled example for config merge only." >&2