Install MatterMost with docker-compose behind Treafik
I expected that the instruction on mattermost github repository for docker-compose will be a simple docker-compose up -d
but turns out this is not the case. I have documented how I set this up along with a slight tweak of how I am going to make it work behind traefik.
Assumptions
- A Ubuntu 18.04.3 (LTS) x64 Server with minimum required configurations
- Docker installed on the host
- docker-compose installed on the host
- git installed on the host
- You already have traefik 2.1 setup on the host and configured to listen to docker provider.
Steps
Clone mattermost docker-compose repository
git clone https://github.com/mattermost/mattermost-docker.git
cd mattermost-docker
Make changes to use team edition rather than enterprise edition
The first part of the app server in the docker-compose.yml
file should look the following. The comment explains what was done.
app:
build: #app
# change `build:app` to `build:` and uncomment following lines for team edition or change UID/GID
context: app
args:
- edition=team
- PUID=1000
- PGID=1000
Build the custom image
docker-compose build
This can take a few minutes based on the resources on your host and your internet connection.
Setup the volumes and assign them the correct permissions
mkdir -pv ./volumes/app/mattermost/{data,logs,config,plugins,client-plugins}
chown -R 1000:1000 ./volumes/app/mattermost/
Note that you have to setup the uid
and gid
setup to match the ones you specifiy in your docker-compose.yml
file that was used for the build step.
Run docker-compose
docker-compose up -d
Edit: Usually the above works eventually, but I encountered some problems where the app
container became unhealthy over the weekend without any visible cause. I have reverted to a setup where I manually start the database service using docker-compose up -d db
and once that is fully up and accepting connections, docker-compose up -d app
. This is worked well so far but I will updated as required. See note below under healthcheck.
At this point you could just run this setup and things should work if you access your host by providing the IP or a hostname that is configured to point to that IP via DNS.
Making it runnable on a repeatable basis
Air-gapped environment considerations
In my situation, the machine I used to build these images is different from where I want to deploy due to air-gap. Hence, there's additional work steps I had to perform. This will also be useful for you to create a deploy docker-compose file when you have pre-built images.
Save the relevant built images as files for transport.
docker save -o <output_file_name>.docker <input_image_name>
If you're going to use traefik as the edge router/proxy, then there's no need to save the web image with nginx. You may also need to save the relevant alpine, postgres and nginx images. I took all of them just in case, but it may work without. If you have tested it out please let me know.
Transfer the images to your deployment host and run the following commands to load them in the local docker repository.
docker load < <input-file-name>.docker
Deployment docker-compose.yml file
There are certain key points to note in the file below:
- image is the name of the image that was generated in the build step and loaded on to the local repository or another repository that is accessible from the host
- There are two network in involved,
out
which is the docker network on which traefik is listening and thedefault
network that is only being used byapp
anddb
. Hence the database is isolated from the network that is visible to traefik. - There is a separate traefik instance running on the
out
network - The
tls=true
configuration for traefik assumes that you have configured the SSL certificates correctly on traefik. You can omit this line if you don't want to enable TLS. - Ensure there is no other traefik router name mattermost
version: "3"
services:
db:
image: mattermost-docker_db
read_only: true
restart: unless-stopped
volumes:
- ./volumes/db/var/lib/postgresql/data:/var/lib/postgresql/data
- /etc/localtime:/etc/localtime:ro
environment:
- POSTGRES_USER=redacted
- POSTGRES_PASSWORD=redacted
- POSTGRES_DB=redacted
app:
image: mattermost-docker_app
restart: unless-stopped
volumes:
- ./volumes/app/mattermost/config:/mattermost/config:rw
- ./volumes/app/mattermost/data:/mattermost/data:rw
- ./volumes/app/mattermost/logs:/mattermost/logs:rw
- ./volumes/app/mattermost/plugins:/mattermost/plugins:rw
- ./volumes/app/mattermost/client-plugins:/mattermost/client/plugins:rw
- /etc/localtime:/etc/localtime:ro
environment:
# set same as db credentials and dbname
- MM_USERNAME=redacted
- MM_PASSWORD=redacted
- MM_DBNAME=redacted
# use the credentials you've set above, in the format:
# MM_SQLSETTINGS_DATASOURCE=postgres://${MM_USERNAME}:${MM_PASSWORD}@db:5432/${MM_DBNAME}?sslmode=disable&connect_timeout=10
- MM_SQLSETTINGS_DATASOURCE=postgres://redacted:redacted@db:5432/redacted?sslmode=disable&connect_timeout=10
labels:
- "traefik.enable=true"
- "traefik.http.routers.mattermost.rule=Host(`your.domain.name`)"
- "traefik.http.routers.mattermost.tls=true"
networks:
- default
- out
networks:
default:
out:
external: true
Before you run docker-compose up -d
Run the setup volumes and persmission step above. Then run docker-compose up -d
.
Post setup
Now navigate to your.domain.name
and go into the setup console. Configure email setting in SMTP and ensure you get the email. Also important, setup the SiteURL parameter to point to your.domain.name
. The test live connection after this setup was unsuccessful for me and I don't know the implications of this yet. You will notice that all the configuration changes you make here will be reflected in the config file located at ./volumes/app/mattermost/config/config.json
. You can also manually change some configration here. For example, I had turned on the email verification feature but had not setup email correctly and was locked out. However, I located the right configuration in the config file and changed it and attempted to login again and it was effective immediately.
Notes: Health Check
Earlier in this post I have referenced that the app container went into an unhealthy state for no apparent reason but I suspect that it was because the app was not able to connect to the database when it was invoked as the database was not in ready state to accept connections. I modified the docker-compose file and added a depends_on
configuration as follows:
app:
depends_on:
- db
As per docker-compose 3 documentation, the depends_on
does not mean that docker will wait till the database is fully up. As per moderns best practices taking distributed cloud native container orchestration systems in to consideration, it is expected that applications will be resilient in handling situations where a dependent resource is not available.
I add some healthcheck code in the docker-compose file. One thing to remember when configuring this is that you can reference localhost
as the app container. For example you might do something like curl -k -f 'https://localhost:8000
where -k skips certificate verification and -f returns the status code (I may be wrong about this, but that's what I figured during my testing.
Conclusion
I had intended to describe setup of traefik 2 in this post as well but unfortunately I'm out of time. Some of this may be described elsewhere on the blog or my medium blog. There are also good posts elsewhere to describe traefik setup you can find out google.