Traefik Proxy e Amazon ECS
Tags: traefik, devops, ecs
Published: 2023-10-22 15:59:23

Vediamo insieme come effettuare il deploy di **Traefik Proxy** su Amazon ECS e come definire un task gestito da quest'ultimo.

Diamo per scontato di avere a disposizione un cluster di ECS ( Ec2 o Fargate ) su cui poter distribuire nuovi service..

## Creazione della Task Definition per Traefik Proxy

Il fulcro di tutto è la task definition da applicare al nuovo service ..

Ecco un esempio di task definition che andremo ad analizzare:

```
{
    "family": "Proxy",
    "containerDefinitions": [
        {
            "name": "Proxy",
            "image": "traefik:latest",
            "cpu": 0,
            "memory": 512,
            "portMappings": [
                {
                    "containerPort": 80,
                    "hostPort": 80,
                    "protocol": "tcp"
                },
                {
                    "containerPort": 443,
                    "hostPort": 443,
                    "protocol": "tcp"
                }
            ],
            "essential": true,
            "entryPoint": [],
            "command": [
                "--api.dashboard=true",
                "--api.insecure=false",
                "--accesslog=true",
                "--accesslog.filepath=/var/log/traefik/access.log",
                "--providers.ecs.ecsAnywhere=true",
                "--providers.ecs.region=eu-west-1",
                "--providers.ecs.autoDiscoverClusters=false",
                "--providers.ecs.exposedByDefault=true",
                "--providers.ecs.clusters=Cluster",
                "--entrypoints.web.address=:80",
                "--entrypoints.websecure.address=:443",
                "--certificatesresolvers.myresolver.acme.httpchallenge=true",
                "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web",
                "--certificatesresolvers.myresolver.acme.email=email@email.it",
                "--certificatesresolvers.myresolver.acme.storage=/var/letsandcrypt/acme.json",
                "--log.level=DEBUG",
                "--certificatesresolvers.myresolver.acme.caserver=https://acme-v02.api.letsencrypt.org/directory",
                "--entrypoints.web.http.redirections.entrypoint.to=websecure",
                "--entrypoints.web.http.redirections.entrypoint.scheme=https"
            ],
            "environment": [],
            "mountPoints": [
                {
                    "sourceVolume": "letsandcrypt",
                    "containerPath": "/var/letsandcrypt"
                },
                {
                    "sourceVolume": "log",
                    "containerPath": "/var/log/traefik"
                }
            ],
            "volumesFrom": [],
            "dockerLabels": {
                "traefik.enable": "true",
                "traefik.http.middlewares.traefik-dashboard-auth.basicauth.users": "test:xxxxxxxxx",
                "traefik.http.routers.api.entrypoints": "websecure",
                "traefik.http.routers.api.middlewares": "traefik-dashboard-auth",
                "traefik.http.routers.api.rule": "Host(`proxy.test.it`)",
                "traefik.http.routers.api.service": "api@internal",
                "traefik.http.routers.api.tls": "true",
                "traefik.http.routers.api.tls.certresolver": "myresolver"
            }
        }
    ],
    "taskRoleArn": "arn:aws:iam::000000000000:role/ecsTaskExecutionRole",
    "executionRoleArn": "arn:aws:iam::000000000000:role/ecsTaskExecutionRole",
    "volumes": [
        {
            "name": "letsandcrypt",
            "host": {
                "sourcePath": "/var/letsandcrypt"
            }
        },
        {
            "name": "log",
            "host": {
                "sourcePath": "/var/log/traefik"
            }
        }
    ],
    "placementConstraints": [
        {
            "type": "memberOf",
            "expression": "attribute:role == loadbalancer"
        }
    ],
    "requiresCompatibilities": [
        "EXTERNAL"
    ],
    "cpu": "512",
    "memory": "1024"
}
```

Da un primo sguardo vediamo subito che si tratta di una normalissima Task Definition il cui compito è deployare l'immagine traefik:latest da docker hub.. niente di più.

Tutto il lavoro di configurazione è fatto dai **command** e dai **dockerLabels** .. analizziamo la task definition pezzo pezzo...

---

### Mapping delle porte

Nella prima parte della **containerDefinition** abbiamo:

```
 "name": "Proxy",
 "image": "traefik:latest",
 "cpu": 0,
 "memory": 512,
 "portMappings": [
     {
       "containerPort": 80,
       "hostPort": 80,
       "protocol": "tcp"
     },
     {
       "containerPort": 443,
       "hostPort": 443,
       "protocol": "tcp"
     }
],
```

Dove abbiamo semplicemente definito il nome della Task definition, la memoria e il mapping delle porte.. apriamo semplicemente la **80** e la **443** per l'SSL.

Subito dopo abbiamo la parte dei command, dove inseriamo le direttive di configurazione per il container di traefik proxy; facciamo sempre e in ogni caso riferimento alla [documentazione ufficiale di Traefik](https://doc.traefik.io/traefik/)

Iniziamo con l'abilitare la dashboard di controllo e col disabilitare la porta **80** per l'accesso alla dashboard e alle api di traefik.. faremo tutto sulla **443** con **letsandcrypt**

```
  "--api.dashboard=true",
  "--api.insecure=false",
```
---
### Access log

abilitiamo i log e configuriamo la cartella su cui salvarli:

```
 "--accesslog=true",
 "--accesslog.filepath=/var/log/traefik/access.log",
```
---
### ECS Provider

Configuriamo il provider di ECS che permetterà a traefik di sincronizzarsi; in questo esempio specifichiamo un singolo cluster, ma possiamo anche sincronizzare tutto il servizio...

```
 "--providers.ecs.ecsAnywhere=true",
 "--providers.ecs.region=eu-west-1",
 "--providers.ecs.autoDiscoverClusters=false",
 "--providers.ecs.exposedByDefault=true",
 "--providers.ecs.clusters=Cluster",
```
---
Abilitiamo gli entrypoint per l'**http** e l'**https**:

```
  "--entrypoints.web.address=:80",
  "--entrypoints.websecure.address=:443",
```
---
### Certificati Letsandcrypt

Per la configurazione della **443** dobbiamo settare **Letsandcrypt**:

```
"--certificatesresolvers.myresolver.acme.httpchallenge=true",
"--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web",
"--certificatesresolvers.myresolver.acme.email=email@email.it",
"--certificatesresolvers.myresolver.acme.storage=/var/letsandcrypt/acme.json",
```

E' necessario fare un paio di precisazioni su **Letsandcrypt**:

* Per eseguire i test è necessario settare l'endpoint sullo stage

**#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"**

questo perchè letsandcrypt ha alcuni rate limit sulle registrazioni di nuovi certificati che non è bene superare.. tra le quali un limit settimanale.

* Inoltre è importante ricordare di storare il file acme.json su un volume "persistente" altrimenti verrà effettuata una nuova richiesta di certificazione ad ogni avvio del task e questo porterà in poco tempo al limite del rate.

Questo è direttamente collegato ai due volumi che trovate montati nella task definition:

```
"mountPoints": [
      {
          "sourceVolume": "letsandcrypt",
          "containerPath": "/var/letsandcrypt"
      },
      {
          "sourceVolume": "log",
          "containerPath": "/var/log/traefik"
      }
 ],
```

Il primo è per l'acme.json e l'altro è per i logs.

---
### Docker Labels

I docker labels necessari sono:

```
"dockerLabels": {
                "traefik.enable": "true",
                "traefik.http.middlewares.traefik-dashboard-auth.basicauth.users": "test:xxxxxxxxxx",
                "traefik.http.routers.api.entrypoints": "websecure",
                "traefik.http.routers.api.middlewares": "traefik-dashboard-auth",
                "traefik.http.routers.api.rule": "Host(`proxy.test.it`)",
                "traefik.http.routers.api.service": "api@internal",
                "traefik.http.routers.api.tls": "true",
                "traefik.http.routers.api.tls.certresolver": "myresolver"
            }
```
e fondamentalmente hanno il compito di accendere una Basic Auth per accedere alla dashboard e per reindirizzare il traffico delle api sulla 443.

---
### Middleware di Redirect

L'ultima parte ma non meno importante della configurazine è il middleware di redirect per l'http:

```
"--entrypoints.web.http.redirections.entrypoint.to=websecure",
"--entrypoints.web.http.redirections.entrypoint.scheme=https"
```
quest'ultimo si occupa di reindirizzare tutte le richieste in arrivo sulla porta 80 direttamente sulla 443.

-----

# Creazione della Task Definition per il service

Per quanto riguarda la Task definition per il singolo servizio da eseguire dietro a **Traefik Proxy** le uniche *dockerLabel* da configurare sono:

```
"dockerLabels": {
        "traefik.enable": "true",
        "traefik.http.routers.service-test.entrypoints": "websecure",
        "traefik.http.routers.service-test.rule": "Host(`www.dominio.it`)",
        "traefik.http.routers.service-test.tls.certresolver": "myresolver"
},
```

Grazie per la lettura!
F.