Experimenting with Managing Containers with Portainer

Portainer is very well-known application that provides a web UI to manage containers. Before knowing more about it, I thought it was just a nice interface to manage Docker functionality graphically.

I'm not sure how it started, but Portainer is now a very comprehensive application that can be used to manage containers in Docker, Docker Swarm, Kubernetes and Azure ACI from one centralized interface.

In this article, I will do an overview of Portainer's functionality and try to manage a Kubernetes cluster in the local network with it.

# Requirements

The requirements to start using Portainer on top of Docker are very simple:

- Install the Docker Engine:

https://docs.docker.com/engine/install/ubuntu/

- Setup Docker management by a non-root user:

https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user

I did these steps on an Ubuntu Server installed on a PC in my local network.

# Install Portainer

https://docs.portainer.io/start/install-ce/server/docker/linux

Actually, there's not much in terms of installation since we are just starting the corresponding container:

```shell
$ docker volume create portainer_data # volume to hold Portainer's database
$ docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
```

Now, we have Portainer up and running:

```shell
$ docker ps
CONTAINER ID   IMAGE                           COMMAND        CREATED          STATUS          PORTS                                                                                            NAMES
fdfbdb5273a4   portainer/portainer-ce:latest   "/portainer"   27 seconds ago   Up 26 seconds   0.0.0.0:8000->8000/tcp, :::8000->8000/tcp, 0.0.0.0:9443->9443/tcp, :::9443->9443/tcp, 9000/tcp   portainer
```

# Access Portainer

With the installation complete, we can access it through the port `9443`:

```
https://${ip_address}:9443
```

You will be presented by a browser warning regarding Portainer's certificate, but it's safe to proceed. We first set the password for the `admin` user.

Because I left the `admin` user setup screen opened for a couple of minutes, I was shown the error below when trying to proceed:

`Your Portainer instance timed out for security purposes. To re-enable your Portainer instance, you will need to restart Portainer.`

So, I just did as per instructions:

```shell
$ docker restart portainer
```

And I was able to access the application:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509832/05d7e4f6-2835-fe0e-4c5c-ba96f681bc83.png)

I selected "Get Started" to start managing the Docker installation Portainer is running on, then selected the `local` environment to connect to it and I was presented with the screen below:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509832/47814675-84c4-0b7e-7c74-213276eeb30f.png)

From here, we can manage our Docker installation from Portainer's friendly interface. For example, we can use one of the built-in application templates to quickly start containers for commonly used projects. 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509832/e2e1e467-2a6c-db11-3f5a-111746b7c8d9.png)

# Manage a Kubernetes Cluster

In this step, we will try to manage a Kubernetes cluster in the local network with Portainer. I've created an Ubuntu virtual machine in my home server (separate from the PC Portainer is running on) and installed Minikube on it.

We have a couple of options for adding a Kubernetes cluster to be managed by Portainer as we can see in the following page:

https://docs.portainer.io/admin/environments/add/kubernetes

In this example, I will use the "Edge Agent Standard" option.

Portainer works through two elements. One is the Portainer Server we run in the previous step. We also need the Portainer Agent to be deployed to each environment we want to manage. These two components run as lightweight containers in our infrastructure.

Going back to the options we have to add a Kubernetes cluster to Portainer, the "Agent" option is used when we the server can access the environment we want to add. If it's not the case, we use one of the "Edge Agent" options as, in this case, it's the Agent that polls the Portainer Server periodically to see if there are any pending jobs to perform.

## Requirements

We just need the Agent to be able to access the UI port (`9443` by default) in the Portainer Server instance.

## Steps

We first go the "Environments" page and click the "+ Add environment` button:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509832/22573a2c-72a4-b137-f35f-d8cc1b51d2b1.png)

Select "Kubernetes" and click "Start Wizard". In the next screen, just select "Edge Agent Standard", type a name for the environment and click "Create". In the "More settings" option, we can change the poll frequency and assign metadata such as group and tags.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509832/286c1d0e-e34b-d339-4b06-2802df691900.png)

A Linux command will be generated so we can run it on our node. In my case, I will run it on the VM where Minikube is running on.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509832/7acd4d7d-c15b-6300-c688-0270993f0cb3.png)

The command failed to me with the following error:

`Unable to find kubectl binary. Please ensure kubectl is installed before running this script.`

The issue was the fact that I was using `kubectl` as an alias of the `minikube kubectl` command: `alias kubectl="minikube kubectl --"`. So, I disabled the alias and actually installed `kubectl` instead.

After that, the command run just fine:

```shell
$ curl https://downloads.portainer.io/ee2-19/portainer-edge-agent-setup.sh | bash -s -- "a3865105-0217-47ca-b55a-ba1c31180de4" "aHR0cHM6Ly8xOTIuMTY4LjAuMTI6OTQ0M3wxOTIuMTY4LjAuMTI6ODAwMHxVVUN1ck5NZDRFNVpXYWNTMEJub01wRXBTOE1rNVJGcXFIS045SWhsbk1ZPXwz" "1" "" ""
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  4160  100  4160    0     0  35406      0 --:--:-- --:--:-- --:--:-- 35254
Downloading agent manifest...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2306  100  2306    0     0   5178      0 --:--:-- --:--:-- --:--:--  5182
Creating Portainer namespace...
namespace/portainer created
Creating agent configuration...
kubectl create configmap -n portainer portainer-agent-edge --from-literal=EDGE_ID=a3865105-0217-47ca-b55a-ba1c31180de4 --from-literal=EDGE_INSECURE_POLL=1
configmap/portainer-agent-edge created
Creating agent secret...
secret/portainer-agent-edge-key created
Deploying agent...
Warning: resource namespaces/portainer is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
namespace/portainer configured
serviceaccount/portainer-sa-clusteradmin created
clusterrolebinding.rbac.authorization.k8s.io/portainer-crb-clusteradmin created
service/portainer-agent created
deployment.apps/portainer-agent created
Portainer Edge agent successfully deployed
```

## Managing the Cluster

The new environment was added to Portainer and I was able to check it:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509832/3f99488e-b9a2-3a0f-5d85-293539643dc6.png)

From here, we can start managing our cluster through Portainer. We can, for example, deploy an application from a Git repository and have Portainer update the application whenever the application manifests in the repository are updated.

We can also install Helm charts through the available screen:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509832/1a224f9e-fc0f-2b5d-8cde-73cdf12fdd2d.png)

# Conclusion

I won't go any further with exploring the functionality provided by Portainer in this article, but you can check the YouTube video below where the author does a much more comprehensive overview of Portainer.

https://www.youtube.com/watch?v=FC8pABzxZVU

I have to explore Portainer much more to understand all of its benefits but, for now, at least I had a very good impression on how user-friendly is its user interface. 

# References

- https://docs.portainer.io/start/architecture
- https://docs.portainer.io/start/install-ce/server/docker/linux
- https://docs.portainer.io/admin/environments/add/kubernetes
- https://docs.docker.com/engine/install/ubuntu/
- https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user