Automatiser Ansible avec Semaphore

J’ai toujours voulu configurer Gitlab pour mettre à jour mes machines virtuelles, mais je n’ai jamais vraiment pris le temps de le faire… je ne sais pas trop pourquoi en fait. Ce que je fais à la place est de rouler une commande Ansible manuellement chaque samedi matin. Pas super efficace!

Un nouveau meilleur ami pour ansible

La découverte d'un outil permettant de faire exactement ceci avec une interface beaucoup plus intuitive pour y parvenir est apparu dans mon fil de nouvelles technologiques. Son nom, Semaphore. L'outil permet de gérer les inventaires, les tâches et les paramètres de connexion super facilement et de voir l’historique des exécutions du même coup. Super bien fait, et ça fonctionne du tonnerre.

À quoi ça ressemble

Voici donc visuellement à quoi on peut s'attendre de Sémaphore.

Liste des tâches exécutées

semaphore_screen4.png

Configuration des tâches

semaphore_screen2.png

Gestion de l'inventaire

semaphore_screen3.png

Détais d'exécution

semaphore_screen5.png

Ansible semaphore sur kubernetes

Installation

La documentation de Semaphore indique seulement comment installer avec snap, deb/rpm, fichiers binaires ou docker. Ceci dit, si ça roule dans docker, ça roule sur kubernetes aussi!

Fichiers YAML de configuration pour kubernetes

Vous pouvez copier-coller ces fichiers ici bas si vous voulez avoir Semaphore qui roule sur K8S. Vous aurez besoin de cert-manager pour le certificat SSL pour le dernier ficher, sinon il vous faudra exposer l'application à votre guise.

# Output all yaml files in semaphore folder
→
→ for f in semaphore/*; do echo -e "$f\n---"; cat $f; echo -e "\n---\n\n"; done

semaphore/00-namespace.yml
---
apiVersion: v1
kind: Namespace
metadata:
  name: semaphore
---


semaphore/01-configs.yml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-json
  namespace: semaphore
data:
  config.json: |-
    {
        "mysql": {
                "host": "mysql:3306",
                "user": "semaphore",
                "pass": "semaphore",
                "name": "semaphore",
                "options": null
        },
        "bolt": {
                "host": "",
                "user": "",
                "pass": "",
                "name": "",
                "options": null
        },
        "postgres": {
                "host": "",
                "user": "",
                "pass": "",
                "name": "",
                "options": null
        },
        "dialect": "mysql",
        "port": "",
        "interface": "",
        "tmp_path": "/tmp/semaphore",
        "cookie_hash": "0000000000000000123456789",
        "cookie_encryption": "0000000000000000123456789",
        "access_key_encryption": "0000000000000000123456789",
        "email_sender": "",
        "email_host": "",
        "email_port": "",
        "email_username": "",
        "email_password": "",
        "web_host": "",
        "ldap_binddn": "",
        "ldap_bindpassword": "",
        "ldap_server": "",
        "ldap_searchdn": "",
        "ldap_searchfilter": "",
        "ldap_mappings": {
                "dn": "",
                "mail": "",
                "uid": "",
                "cn": ""
        },
        "telegram_chat": "",
        "telegram_token": "123456789:00000000000000001234567890",
        "slack_url": "",
        "max_parallel_tasks": 0,
        "email_alert": false,
        "email_secure": false,
        "telegram_alert": true,
        "slack_alert": false,
        "ldap_enable": false,
        "ldap_needtls": false,
        "ssh_config_path": "",
        "demo_mode": false,
        "git_client": ""
    }
---


semaphore/02-deployment-mysql.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: mysql
  name: mysql
  namespace: semaphore
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - env:
            - name: MYSQL_DATABASE
              value: semaphore
            - name: MYSQL_PASSWORD
              value: semaphore
            - name: MYSQL_RANDOM_ROOT_PASSWORD
              value: "yes"
            - name: MYSQL_USER
              value: semaphore
          image: mysql:8.0
          name: mysql
          ports:
            - containerPort: 3306
          resources:
            requests:
              memory: "256Mi"
              cpu: "250m"
            limits:
              memory: "500Mi"
              cpu: "500m"
          volumeMounts:
            - mountPath: /var/lib/mysql
              name: semaphore-mysql
      hostname: mysql
      restartPolicy: Always
      volumes:
        - name: semaphore-mysql
          persistentVolumeClaim:
            claimName: semaphore-mysql-pv-claim
---


semaphore/03-static-volume.yml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: semaphore-mysql-pv-claim
  namespace: semaphore
spec:
  resources:
    requests:
      storage: 100Mi
  accessModes:
    - ReadWriteOnce
---


semaphore/04-deployment-semaphore.yml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: semaphore
  name: semaphore
  namespace: semaphore
spec:
  replicas: 1
  selector:
    matchLabels:
      app: semaphore
  template:
    metadata:
      labels:
        app: semaphore
    spec:
      containers:
        - env:
            - name: SEMAPHORE_ACCESS_KEY_ENCRYPTION
              value: 00000000000000001234567890
            - name: SEMAPHORE_ADMIN
              value: admin
            - name: SEMAPHORE_ADMIN_EMAIL
              value: email@your.domain.com
            - name: SEMAPHORE_ADMIN_NAME
              value: admin
            - name: SEMAPHORE_ADMIN_PASSWORD
              value: p4ssw0rd
            - name: SEMAPHORE_DB
              value: semaphore
            - name: SEMAPHORE_DB_DIALECT
              value: mysql
            - name: SEMAPHORE_DB_HOST
              value: mysql
            - name: SEMAPHORE_DB_PASS
              value: semaphore
            - name: SEMAPHORE_DB_PORT
              value: "3306"
            - name: SEMAPHORE_DB_USER
              value: semaphore
            - name: SEMAPHORE_LDAP_ACTIVATED
              value: "no"
            - name: SEMAPHORE_PLAYBOOK_PATH
              value: /tmp/semaphore/
          image: semaphoreui/semaphore:latest
          name: semaphore
          ports:
            - containerPort: 3000
          resources: 
            requests:
              memory: "256Mi"
              cpu: "250m"
            limits:
              memory: "500Mi"
              cpu: "500m"
          volumeMounts:
            - name: config-json
              mountPath: /etc/semaphore
      restartPolicy: Always
      volumes:
        - name: config-json
          configMap:
            name: config-json
---


semaphore/05-service-mysql.yml
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: mysql
  name: mysql
  namespace: semaphore
spec:
  ports:
    - name: "3306"
      port: 3306
      targetPort: 3306
  selector:
    app: mysql
status:
  loadBalancer: {}
---


semaphore/06-service-semaphore.yml
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: semaphore
  name: semaphore
  namespace: semaphore
spec:
  ports:
    - name: "3000"
      port: 3000
      targetPort: 3000
  selector:
    app: semaphore
---

semaphore/07-semaphore-ingress.yml
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: semaphore
  namespace: semaphore
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  rules:
  - host: your.domain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: semaphore
            port: 
              number: 3000
  ingressClassName: public
  tls:
  - hosts:
    - your.domain.com
    secretName: ssl-nginx-static
---