how to run all Butler tools with a single command
The beauty of Docker — how to run all Butler tools with a single command
Docker is great.
Docker is one of those tools that have the potential to fundamentally transform how you develop and run software — once you have tried Docker it is hard to imagine going back to something else.
In previous posts we have seen how
Setting this up is incredibly easy — a single docker-compose file tells Docker what containers to use, and some config files tells the Butler tools where to find things.
Let’s get started!
Setting things up
Docker containers can be started and managed in different ways. We will use the docker-compose command to create and start the containers, as it uses an use easy to understand YAML syntax to define what containers to create, and what parameters to send to them.
The scaffolding
First, let’s create some directories where we can store configuration files for the different Butler tools.
If you just want to try this out, these directories can be on your local computer.
If doing this in a real Qlik Sense environment, you should of course place these directories on a suitable server. The interesting thing is that you have a lot of freedom here: if you have an existing Docker infrastructure the Butler tools can happily run there.
In the examples below I have used my regular 3-year old Apple laptop that sits on the same network as the Qlik Sense server.
Directories
Let’s create some directories first:
proton:code goran$ mkdir butler-dockerproton:code goran$ cd butler-docker/proton:butler-docker goran$ mkdir certificate config_butler config_butler-cw config_butler-sos log_butler-cwproton:butler-docker goran$ tree.├── certificate├── config_butler├── config_butler-cw├── config_butler-sos└── log_butler-cw5 directories, 0 filesproton:butler-docker goran$
Next, copy the config files from each Butler tool into their respective directories above. Also place the certificates exported from the QMC in the certificate directory.
Now we have something like this:
proton:butler-docker goran$ tree.├── certificate│ ├── client.pem│ ├── client_key.pem│ └── root.pem├── config_butler│ └── production.yaml├── config_butler-cw│ ├── apps.yaml│ └── production.yaml├── config_butler-sos│ └── production.yaml└── log_butler-cw5 directories, 7 filesproton:butler-docker goran$
Config files
The YAML config files above are the same ones that were used in the various standalone Butler tools (see previous posts [1], [2], [3]). This is the beauty of Docker — the container contains everything that the software inside needs, and the configuration is the same no matter if used on a laptop, on a server or in the cloud.
The docker-compose file
The docker-compose.yml file is where we tell Docker what containers should be created and how to configure them.
The file should be created in the main directory (one level up from the config directories) and is basically just a combination of the docker-compose files used in previous blog posts:
proton:butler-docker goran$ cat docker-compose.yml# docker-compose.ymlversion: '2.2'services: butler-sos: image: ptarmiganlabs/butler-sos:latest init: true container_name: butler-sos restart: always volumes: # Make config file accessible outside of container - "./config_butler-sos:/nodeapp/config" - "./certificate:/nodeapp/config/certificate" environment: - "NODE_ENV=production" logging: driver: json-file butler-cw: image: ptarmiganlabs/butler-cw:latest init: true container_name: butler-cw restart: always volumes: # Make config file accessible outside of container - "./config_butler-cw:/nodeapp/config" - "./log_butler-cw:/nodeapp/log" - "./certificate:/nodeapp/config/certificate" environment: - "NODE_ENV=production" logging: driver: json-file butler: image: ptarmiganlabs/butler:latest container_name: butler restart: always ports: - "8180:8080" # REST API available on port 8180 to services outside the container - "9997:9997" # UDP port for session connection events - "9998:9998" # UDP port for task failure events volumes: # Make config file accessible outside of container - "./config_butler:/nodeapp/config" - "./certificate:/nodeapp/config/certificate" environment: - "NODE_ENV=production" logging: driver: json-fileproton:butler-docker goran$
The only difference compared to the docker-compose.yml file used for running the tools stand-alone is how the certificate folder is mapped.
In the file above there is an extra volume mapping for each service, this is just so we get a single/shared certificate directory where the QMC certificates can be placed.
Start things up
Now comes the magic. A single command, and everything starts.
It’s even better than that, as Docker will also pull the latest versions of the Butler images from Docker Hub. No need to manually download anything.
Docker then creates containers based on these images and finally start the containers.
The whole thing looks like this:
That’s pretty neat…
Adding MQTT, Influxdb and Grafana
We can do even better though.
Let’s also start some other tools from the docker-compose file:
- Mosquitto (which is a very good MQTT broker used by most of the Butler tools)
- Influxdb (time series database used by Butler SOS)
- Grafana (real-time charts used by Butler SOS)
The docker.compose.yml file now looks like this:
# docker-compose.ymlversion: '2.2'services: butler-sos: image: ptarmiganlabs/butler-sos:latest depends_on: - mqtt - influxdb - grafana init: true container_name: butler-sos restart: always volumes: # Make config file accessible outside of container - "./config_butler-sos:/nodeapp/config" - "./certificate:/nodeapp/config/certificate" environment: - "NODE_ENV=production" networks: - senseops logging: driver: json-file butler-cw: image: ptarmiganlabs/butler-cw:latest init: true container_name: butler-cw restart: always volumes: # Make config file accessible outside of container - "./config_butler-cw:/nodeapp/config" - "./log_butler-cw:/nodeapp/log" - "./certificate:/nodeapp/config/certificate" environment: - "NODE_ENV=production" networks: - senseops logging: driver: json-file butler: image: ptarmiganlabs/butler:latest depends_on: - mqtt container_name: butler restart: always ports: - "8180:8080" # REST API available on port 8180 to services outside the container - "9997:9997" # UDP port for session connection events - "9998:9998" # UDP port for task failure events volumes: # Make config file accessible outside of container - "./config_butler:/nodeapp/config" - "./certificate:/nodeapp/config/certificate" environment: - "NODE_ENV=production" networks: - senseops logging: driver: json-file mqtt: image: eclipse-mosquitto:latest container_name: mosquitto restart: always ports: - "1884:1883" - "9002:9001" volumes: - "./mosquitto/data:/mosquitto/data" - "./mosquitto/config:/mosquitto/config" - "./mosquitto/log:/mosquitto/log" networks: - senseops logging: driver: json-file influxdb: image: influxdb:latest container_name: influxdb restart: always ports: - "8086:8086" volumes: - "./influxdb/datastore:/var/lib/influxdb" networks: - senseops logging: driver: json-file grafana: image: grafana/grafana:latest container_name: grafana restart: always ports: - "3001:3000" volumes: - "./grafana/datastore:/var/lib/grafana" networks: - senseops logging: driver: json-filenetworks: senseops: driver: bridge
Note that the config files for the different Butler tools must also be modified to point to the local instances of Mosquitto, Influxdb and Grafana. For example, the Butler SOS production.yaml file should now use your local computer’s IP as the host IP for Influxdb, MQTT and Grafana.
The complete directory structure needed for the docker-compose file above looks like this:
proton:butler-docker goran$ tree.├── certificate│ ├── client.pem│ ├── client_key.pem│ └── root.pem├── config_butler│ ├── certificate│ └── production.yaml├── config_butler-cw│ ├── apps.yaml│ ├── certificate│ └── production.yaml├── config_butler-sos│ ├── certificate│ └── production.yaml├── docker-compose.yml├── grafana│ └── datastore├── influxdb│ └── datastore├── log_butler-cw│ ├── debug.log│ ├── error.log│ ├── info.log│ └── verbose.log└── mosquitto ├── config ├── data └── log16 directories, 12 filesproton:butler-docker goran$
Running “docker-compose up” starts all 6 services. Nice.
We now have a complete SenseOps environment running locally on our own computer, while at the same time interacting with one or more Qlik Sense servers on the network. This is a really good way to try out the various Butler tools without having to install any software on the servers.
Wrapping up
The mini series of blog posts about running Butler tools as Docker containers is now complete.
There is one tool — the Butler App Duplicator — that has not been discussed so far. There is no reason why this tool cannot be run from a Docker container too, it just hasn’t been a focus so far. Maybe that will change in the future — or you are very welcome to fork the Github repository and contribute to the code!