# Docker Container Monitoring Using PRTG

Monitoring your IT infrastructure provides many benefits. Discovering bottlenecks and gaining insights for predictive measures are just the beginning.

[PRTG](https://www.paessler.com/prtg) is a solid monitoring solution already present and actively used in many IT departments. Because there are a lot of different monitoring solutions out there, this guide is targeted to be compatible with the way PRTG handles Docker container monitoring.

PRTG requires the Docker socket to be exposed to the network, which is not the case in a default setup. The reason for the port not being exposed by default is security.

An exposed and unsecured port could lead to a major security issue. Anyone able to connect to the Docker socket could easily gain full control of the system – meaning root access.

Therefore, it is important to handle these configurations with care. The measure we are going to take is to secure remote access by using TLS certificates. You can read more about this in the [Docker docs](https://docs.docker.com/engine/security/protect-access/#use-tls-https-to-protect-the-docker-daemon-socket).

A guide on the PRTG Docker Container Sensor can be found [here](https://www.paessler.com/manuals/prtg/docker_container_status_sensor).

## Prerequisites

To follow this guide, you will need the following:

* A running instance of Cybus Connectware.
* [Docker](https://docs.docker.com/get-docker/) installed on your system and a PRTG instance with access to that host.
* Access to the [Admin UI](https://docs.cybus.io/2-0-6/getting-started/admin-ui) with sufficient [user permissions](https://docs.cybus.io/2-0-6/documentation/user-management).
* Basic knowledge of MQTT, Docker, and Linux.

## Certificate Generation

First, we need to create a set of certificates. There are basically two options for doing this:

* Use your private company certificate authority.
* Create the certificates locally.

We are going to use the second option, which means all certificates will be self-signed, which is sufficient for the purpose of this guide.

All instructions for creating the certificates can be found in the [Docker docs](https://docs.docker.com/engine/security/protect-access/#use-tls-https-to-protect-the-docker-daemon-socket). To simplify this, we created a small script that executes all the commands for you.

All the steps below assume you are going to use the script. The script is non-interactive, meaning you do not have to enter anything during execution. The generated certificates won’t be password protected and are valid for 50 years.

Create a directory called `.docker` in your home directory. This directory is the default location where the Docker CLI stores all its information.

{% code lineNumbers="true" %}

```bash
mkdir -p ~/.docker
```

{% endcode %}

Clone the script into the previously created directory.

{% code lineNumbers="true" %}

```bash
git clone https://gist.github.com/6f6b9a85e136b37cd52983cb88596158.git ~/.docker/
```

{% endcode %}

Change into the directory.

{% code lineNumbers="true" %}

```bash
cd ~/.docker/
```

{% endcode %}

Make the script executable.

{% code lineNumbers="true" %}

```bash
chmod +x genCerts.sh
```

{% endcode %}

Next, we need to adjust a few things within the script.

{% code lineNumbers="true" %}

```bash
nano genCerts.sh
```

{% endcode %}

Adjust the `HOST` to match your hostname and the last IP of the `HOSTS` string to match your host IP address.

This is how it looks:

{% code lineNumbers="true" %}

```bash
HOST="cybus.io"
HOSTS="DNS:$HOST,IP:127.0.0.1,IP:172.16.0.131"
```

{% endcode %}

Now we are ready to execute the script.

{% code lineNumbers="true" %}

```bash
sh genCerts.sh
```

{% endcode %}

The output should look something like this:

{% code lineNumbers="true" %}

```bash
# Start

# Generate CA private and public keys
Generating RSA private key, 4096 bit long modulus (2 primes)
.................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................++++
...............++++
e is 65537 (0x010001)

Create a server key
Generating RSA private key, 4096 bit long modulus (2 primes)
.++++
..........................................................................++++
e is 65537 (0x010001)

Create certificate signing request

Sign the public key with CA
Signature ok
subject=CN = cybus.io
Getting CA Private Key

Create a client key and certificate signing request
Generating RSA private key, 4096 bit long modulus (2 primes)
.................................................................................................................................++++
...............................................................................................................................................................................................................................................................................................................++++
e is 65537 (0x010001)

Make the key suitable for client authentication

Generate the signed certificate
Signature ok
subject=CN = client
Getting CA Private Key

Remove the two certificate signing requests and extensions config
removed 'client.csr'
removed 'server.csr'
removed 'extfile.cnf'
removed 'extfile-client.cnf'
```

{% endcode %}

To verify all certificates have been generated successfully, inspect the contents of the directory.

{% code lineNumbers="true" %}

```bash
ls
```

{% endcode %}

These files should be present. If there are more files than this, that is not an issue.

{% code lineNumbers="true" %}

```bash
ca-key.pem  ca.pem  ca.srl  cert.pem  genCerts.sh  key.pem  server-cert.pem  server-key.pem
```

{% endcode %}

The last step is to locate the full path to where the certificates are stored.

{% code lineNumbers="true" %}

```bash
pwd
```

{% endcode %}

In this example, the output looks like this. Yours will look a little different.

{% code lineNumbers="true" %}

```bash
/home/jan/.docker
```

{% endcode %}

## Docker Service Configuration

With all the necessary certificates in place, we have to assign them to the Docker daemon. We can find the location of the configuration file by checking the status of the Docker service.

{% code lineNumbers="true" %}

```bash
sudo systemctl status docker.service
```

{% endcode %}

As stated in the output, the configuration file is located at `/lib/systemd/system/docker.service`:

{% code lineNumbers="true" %}

```bash
● docker.service - Docker Application Container Engine
       Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
       Active: active (running) since Mon 2022-05-02 10:26:56 EDT; 33s ago
  TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com   Main PID: 468 (dockerd)
        Tasks: 9
       Memory: 109.2M
          CPU: 307ms     CGroup: /system.slice/docker.service
               └─468 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
```

{% endcode %}

To adjust the configuration to our needs, open the configuration file using sudo privileges.

{% code lineNumbers="true" %}

```bash
sudo nano /lib/systemd/system/docker.service
```

{% endcode %}

Find the line starting with `ExecStart=/usr/bin/dockerd -H fd://` and add the following content to it. Be sure to use the correct path for your setup.

{% code lineNumbers="true" %}

```bash
-H tcp://0.0.0.0:2376 --tlsverify=true --tlscacert=/home/jan/.docker/ca.pem --tlscert=/home/jan/.docker/server-cert.pem --tlskey=/home/jan/.docker/server-key.pem
```

{% endcode %}

In this example, the complete line looks like this:

{% code lineNumbers="true" %}

```bash
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376 --tlsverify=true --tlscacert=/home/jan/.docker/ca.pem --tlscert=/home/jan/.docker/server-cert.pem --tlskey=/home/jan/.docker/server-key.pem --containerd=/run/containerd/containerd.sock
```

{% endcode %}

Save the changes and restart the Docker service.

{% code lineNumbers="true" %}

```bash
sudo systemctl daemon-reload
sudo systemctl restart docker
```

{% endcode %}

Now we can verify our changes took effect.

{% code lineNumbers="true" %}

```bash
sudo systemctl status docker.service
```

{% endcode %}

{% code lineNumbers="true" %}

```bash
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2022-05-03 04:56:12 EDT; 2min 32s ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 678 (dockerd)
      Tasks: 9
     Memory: 40.8M
        CPU: 236ms
     CGroup: /system.slice/docker.service
            └─678 /usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376 --tlsverify=true --tlscacert=/home/jan/.docker/ca.pem --tlscert=/home/jan/.docker/server-cert.pem --tlskey=/home/jan/.docker/server-key.pem --containerd=/run/containerd/containerd.sock
```

{% endcode %}

Now we can use the Docker CLI to connect to the Docker daemon using the specified port. The important part is to use `--tlsverify=true` as this tells the Docker CLI to use the generated certificates located in your home directory (`~/.docker`).

Remember to adjust the IP address in the second line to your individual one.

{% code lineNumbers="true" %}

```bash
docker -H 127.0.0.1:2376 --tlsverify=true version
docker -H 172.16.0.131:2376 --tlsverify=true version
```

{% endcode %}

This is the output of both commands:

{% code lineNumbers="true" %}

```bash
Client: Docker Engine - Community
Version:           20.10.14
API version:       1.41
Go version:        go1.16.15
Git commit:        a224086
Built:             Thu Mar 24 01:48:21 2022
OS/Arch:           linux/amd64
Context:           default
Experimental:      true

Server: Docker Engine - Community
Engine:
  Version:          20.10.14
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.15
  Git commit:       87a90dc
  Built:            Thu Mar 24 01:46:14 2022
  OS/Arch:          linux/amd64
  Experimental:     false
containerd:
  Version:          1.5.11
  GitCommit:        3df54a852345ae127d1fa3092b95168e4a88e2f8
runc:
  Version:          1.0.3
  GitCommit:        v1.0.3-0-gf46b6ba
docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
```

{% endcode %}

## PRTG

The last and final step is to install the Docker sensor inside PRTG. To do this, follow the provided instructions from <https://www.paessler.com/manuals/prtg/docker_container_status_sensor>.

<figure><img src="https://639096190-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfDpOJO2upcq5EpoSahvK%2Fuploads%2Fgit-blob-981ec713fe19b0afba5b27df4a603d5b4f602e03%2Fdocker-container-prtg-dashboard-cybus-connectware.png?alt=media" alt=""><figcaption><p>For the last step, Docker sensors are installed inside PRTG.</p></figcaption></figure>

<figure><img src="https://639096190-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfDpOJO2upcq5EpoSahvK%2Fuploads%2Fgit-blob-4aa5cac3c803d848ffabde79ec93206d4f07d1cd%2Fdocker-sensor-prtg-cybus-connectware.png?alt=media" alt=""><figcaption><p>Status field in PRTG gives information on the status of the Docker sensors.</p></figcaption></figure>
