From 5766c57ecc077a1f0780c3ed3a7ae1fd44033475 Mon Sep 17 00:00:00 2001 From: Phill Kelley Date: Fri, 17 Sep 2021 10:11:35 +1000 Subject: [PATCH 1/3] 20210917 Mosquitto - old-menu branch - PR 2 of 3 A problem affecting the build of the Mosquitto container keeps showing up in Discord questions. Examples: * [2021-09-17](https://discord.com/channels/638610460567928832/638610461109256194/888096248761045022) * [2021-09-09](https://discord.com/channels/638610460567928832/638610461109256194/885494986710335498) The problem is discussed in [alpinelinux/docker-alpine issues/98](https://github.com/alpinelinux/docker-alpine/issues/98). It is not clear whether: 1. The problem is transient (ie those reporting it are able to get past the problem on a retry); 2. Only affects Mosquitto or potentially affects other Alpine-based IOTstack containers using `apk` to add packages (eg Node-RED); or 3. Environmental (eg if there is a proxy system between the Raspberry Pi and dl-cdn.alpinelinux.org). This Pull Request is implementing the patch suggested by Issue 98 of reverting `apk` requests to use HTTP. Given the march towards HTTPS-everywhere, reverting to HTTP might seem inadvisable but: * Issue 98 was opened in July 2020. * There seems to have been no significant progress towards its resolution since January 2021. * The Discord traffic suggests it is an ongoing and present issue for IOTstack users. --- .templates/mosquitto/Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.templates/mosquitto/Dockerfile b/.templates/mosquitto/Dockerfile index 8eb6c900..f65ba51c 100644 --- a/.templates/mosquitto/Dockerfile +++ b/.templates/mosquitto/Dockerfile @@ -1,6 +1,9 @@ # Download base image FROM eclipse-mosquitto:latest +# see https://github.com/alpinelinux/docker-alpine/issues/98 +RUN sed -i 's/https/http/' /etc/apk/repositories + # Add support tools RUN apk update && apk add --no-cache rsync tzdata From bd7d0724d1d77f0c571508448bcfdc711b5211ed Mon Sep 17 00:00:00 2001 From: Phill Kelley Date: Thu, 30 Sep 2021 15:37:21 +1000 Subject: [PATCH 2/3] Adds health-check functionality to local image Adds health-check script to template. Alters Dockerfile to import health-check script and adds `HEALTHCHECK` directive. All container documentation is in master branch. --- .templates/mosquitto/Dockerfile | 12 ++++ .templates/mosquitto/iotstack_healthcheck.sh | 64 ++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100755 .templates/mosquitto/iotstack_healthcheck.sh diff --git a/.templates/mosquitto/Dockerfile b/.templates/mosquitto/Dockerfile index f65ba51c..7285e065 100644 --- a/.templates/mosquitto/Dockerfile +++ b/.templates/mosquitto/Dockerfile @@ -13,6 +13,18 @@ ENV IOTSTACK_DEFAULTS_DIR="iotstack_defaults" # copy template files to image COPY --chown=mosquitto:mosquitto ${IOTSTACK_DEFAULTS_DIR} /${IOTSTACK_DEFAULTS_DIR} +# copy the health-check script into place +ENV HEALTHCHECK_SCRIPT "iotstack_healthcheck.sh" +COPY ${HEALTHCHECK_SCRIPT} /usr/local/bin/${HEALTHCHECK_SCRIPT} + +# define the health check +HEALTHCHECK \ + --start-period=30s \ + --interval=30s \ + --timeout=10s \ + --retries=3 \ + CMD ${HEALTHCHECK_SCRIPT} || exit 1 + # replace the docker entry-point script ENV IOTSTACK_ENTRY_POINT="docker-entrypoint.sh" COPY ${IOTSTACK_ENTRY_POINT} /${IOTSTACK_ENTRY_POINT} diff --git a/.templates/mosquitto/iotstack_healthcheck.sh b/.templates/mosquitto/iotstack_healthcheck.sh new file mode 100755 index 00000000..8f4d5130 --- /dev/null +++ b/.templates/mosquitto/iotstack_healthcheck.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env sh + +# assume the following environment variables, all of which may be null +# HEALTHCHECK_PORT +# HEALTHCHECK_USER +# HEALTHCHECK_PASSWORD +# HEALTHCHECK_TOPIC + +# set a default for the port +HEALTHCHECK_PORT="${HEALTHCHECK_PORT:-1883}" + +# strip any quotes from username and password +HEALTHCHECK_USER="$(eval echo $HEALTHCHECK_USER)" +HEALTHCHECK_PASSWORD="$(eval echo $HEALTHCHECK_PASSWORD)" + +# set a default for the topic +HEALTHCHECK_TOPIC="${HEALTHCHECK_TOPIC:-iotstack/mosquitto/healthcheck}" +HEALTHCHECK_TOPIC="$(eval echo $HEALTHCHECK_TOPIC)" + +# record the current date and time for the test payload +PUBLISH=$(date) + +# publish a retained message containing the timestamp +mosquitto_pub \ + -h localhost \ + -p "$HEALTHCHECK_PORT" \ + -t "$HEALTHCHECK_TOPIC" \ + -m "$PUBLISH" \ + -u "$HEALTHCHECK_USER" \ + -P "$HEALTHCHECK_PASSWORD" \ + -r + +# did that succeed? +if [ $? -eq 0 ] ; then + + # yes! now, subscribe to that same topic with a 2-second timeout + # plus returning on the first message + SUBSCRIBE=$(mosquitto_sub \ + -h localhost \ + -p "$HEALTHCHECK_PORT" \ + -t "$HEALTHCHECK_TOPIC" \ + -u "$HEALTHCHECK_USER" \ + -P "$HEALTHCHECK_PASSWORD" \ + -W 2 \ + -C 1 \ + ) + + # did the subscribe succeed? + if [ $? -eq 0 ] ; then + + # yes! do the publish and subscribe payloads compare equal? + if [ "$PUBLISH" = "$SUBSCRIBE" ] ; then + + # yes! return success + exit 0 + + fi + + fi + +fi + +# otherwise, return failure +exit 1 From cd9446122baf9c8046d2010af3d37884121df9c6 Mon Sep 17 00:00:00 2001 From: Phill Kelley Date: Sat, 2 Oct 2021 11:29:49 +1000 Subject: [PATCH 3/3] Reduce old-menu mosquitto documentation to a link to new-menu --- docs/Containers/Mosquitto.md | 211 +---------------------------------- 1 file changed, 1 insertion(+), 210 deletions(-) diff --git a/docs/Containers/Mosquitto.md b/docs/Containers/Mosquitto.md index e9794abf..ec39cb5a 100644 --- a/docs/Containers/Mosquitto.md +++ b/docs/Containers/Mosquitto.md @@ -1,212 +1,3 @@ # Mosquitto -## References -- [Docker](https://hub.docker.com/_/eclipse-mosquitto) -- [Website](https://mosquitto.org/) -- [mosquitto.conf](https://mosquitto.org/man/mosquitto-conf-5.html) documentation -- [Setting up passwords](https://www.youtube.com/watch?v=1msiFQT_flo) video - -## Definitions - -- `docker-compose.yml` ⇒ ~/IOTstack/docker-compose.yml -- `mosquitto.conf` ⇒ ~/IOTstack/services/mosquitto/mosquitto.conf -- `mosquitto.log` ⇒ ~/IOTstack/volumes/mosquitto/log/mosquitto.log -- `service.yml` ⇒ ~/IOTstack/.templates/mosquitto/service.yml -- `volumes/mosquitto` ⇒ ~/IOTstack/volumes/mosquitto/ - -## Logging - -Mosquitto logging is controlled by `mosquitto.conf`. This is the default configuration: - -``` -#log_dest file /mosquitto/log/mosquitto.log -# To avoid flash wearing -log_dest stdout -``` - -When `log_dest` is set to `stdout`, you inspect Mosquitto's logs like this: - -``` -$ docker logs mosquitto -``` - -Logs written to `stdout` are ephemeral and will disappear when your IOTstack is restarted but this configuration reduces wear and tear on your SD card. - -The alternative, which *may* be more appropriate if you are running on an SSD or HD, is to change `mosquitto.conf` to be like this: - -``` -log_dest file /mosquitto/log/mosquitto.log -# To avoid flash wearing -#log_dest stdout -``` - -and then restart Mosquitto: - -``` -$ cd ~/IOTstack -$ docker-compose restart mosquitto -``` - -With this configuration, you inspect Mosquitto's logs like this: - -``` -$ tail ~/IOTstack/volumes/mosquitto/log/mosquitto.log -``` - -Logs written to `mosquitto.log` do not disappear when your IOTstack is restarted. They persist until you take action to prune the file. - -## Security - -By default, the Mosquitto container has no password. You can leave it that way if you like but it's always a good idea to secure your services. - -Assuming your IOTstack is running: - -1. Open a shell in the mosquitto container: - - ``` - $ docker exec -it mosquitto sh - ``` - -2. In the following, replace «MYUSER» with the username you want to use for controlling access to Mosquitto and then run these commands: - - ``` - $ mosquitto_passwd -c /mosquitto/pwfile/pwfile «MYUSER» - $ exit - ``` - - `mosquitto_passwd` will ask you to type a password and confirm it. - - The path on the right hand side of: - - ``` - -c /mosquitto/pwfile/pwfile - ``` - - is **inside** the container. **Outside** the container, it maps to: - - ``` - ~/IOTstack/volumes/mosquitto/pwfile/pwfile - ``` - - You should be able to see the result of setting a username and password like this: - - ``` - $ cat ~/IOTstack/volumes/mosquitto/pwfile/pwfile - MYUSER:$6$lBYlxjWtLON0fm96$3qgcEyr/nKvxk3C2Jk36kkILJK7nLdIeLhuywVOVkVbJUjBeqUmCLOA/T6qAq2+hyyJdZ52ALTi+onMEEaM0qQ== - $ - ``` - -3. Open `mosquitto.conf` in a text editor. Find this line: - - ``` - #password_file /mosquitto/pwfile/pwfile - ``` - - Remove the # in front of password_file. Save. - -4. Restart Mosquitto: - - ``` - $ cd ~/IOTstack - $ docker-compose restart mosquitto - ``` - -5. Use the new credentials where necessary (eg Node-Red). - -Notes: - -* You can revert to password-disabled state by going back to step 3, re-inserting the "#", then restarting Mosquitto as per step 4. -* If mosquitto keeps restarting after you implement password checking, the most likely explanation will be something wrong with the password file. Implement the advice in the previous note. - -## Running as root - -By default, the Mosquitto container is launched as root but then downgrades its privileges to run as user ID 1883. - -Mosquitto is unusual because most containers just accept the privileges they were launched with. In most cases, that means containers run as root. - -> Don't make the mistake of thinking this means that processes running **inside** containers can do whatever they like to your host system. A process inside a container is **contained**. What a process can affect **outside** its container is governed by the port, device and volume mappings you see in the `docker-compose.yml`. - -You can check how mosquitto has been launched like this: - -``` -$ ps -eo euser,ruser,suser,fuser,comm | grep mosquitto -EUSER RUSER SUSER FUSER COMMAND -1883 1883 1883 1883 mosquitto -``` - -If you have a use-case that needs Mosquitto to run with root privileges: - -1. Open `docker-compose.yml` in a text editor and find this: - - ``` - mosquitto: - … [snip] … - user: "1883" - ``` - - change it to: - - ``` - mosquitto: - … [snip] … - user: "0" - ``` - -2. Edit `mosquitto.conf` to add this line: - - ``` - user root - ``` - -3. Apply the change: - - ``` - $ cd ~/IOTstack - $ docker-compose stop mosquitto - $ docker-compose up -d - ``` - -> A clean install of Mosquitto via the IOTstack menu sets everything in `volumes/mosquitto` to user and group 1883. That permission structure will still work if you change Mosquitto to run with root privileges. However, running as root **may** have the side effect of changing privilege levels within `volumes/mosquitto`. Keep this in mind if you decide to switch back to running Mosquitto as user 1883 because it is less likely to work. - -## Port 9001 - -In earlier versions of IOTstack, `service.yml` included two port mappings which were included in `docker-compose.yml` when Mosquitto was chosen in the menu: - -``` - ports: - - "1883:1883" - - "9001:9001" -``` - -[Issue 67](https://github.com/SensorsIot/IOTstack/issues/67) explored the topic of port 9001 and showed that: - -* The base image for mosquitto did not expose port 9001; and -* The running container was not listening to port 9001. - -On that basis, the mapping for port 9001 was removed from `service.yml`. - -If you have a use-case that needs port 9001, you can re-enable support by: - -1. Inserting the port mapping under the `mosquitto` definition in `docker-compose.yml`: - - ``` - - "9001:9001" - ``` - -2. Inserting the following lines in `mosquitto.conf`: - - ``` - listener 1883 - listener 9001 - ``` - - You need **both** lines. If you omit 1883 then mosquitto will stop listening to port 1883 and will only listen to port 9001. - -3. Restarting the container: - - ``` - $ cd ~/IOTstack - $ docker-compose up -d - ``` - -Please consider raising an issue to document your use-case. If you think your use-case has general application then please also consider creating a pull request to make the changes permanent. +Please refer to the [documentation on the master branch](https://sensorsiot.github.io/IOTstack/Containers/Mosquitto/).