Docker et docker-compose avec ansible sur une Debian 11

April 25, 2023 - Reading time: 98 minutes

A force d'automatiser j'ai maintenant des squelettes de playbooks , de rôles voir même de collections ansible.

Le plus souvent j'utilise le rôle Docker (avec docker-compose ) dés l'installation d'une nouvelle machine , je vous propose ici de suivre l'installation de ce serveur avec OVH avec sa première customisation.

1. Création du serveur avec OVH

On pourrait ici utiliser Terraform pour le faire , mais vu que c'est un usage personnel , je ne m'amuse pas à installer/supprimer mes serveurs très souvent , du coup je passe par une installation via le manager d'OVH.

Je vous laisse le soin de créér votre serveur, l'important ici c'est de récupérer les infos de première connexion. Si tout se passe bien vous devriez recevoir un mail d'OVH avec vos identifiants de connexion

Votre VPS vient d'être installé sous le système d'exploitation / distribution
Debian 11


PARAMETRES D'ACCES:
L'adresse IPv4 du VPS est : <ip>

Le nom du VPS est : <nom vps>

Le compte administrateur suivant a été configuré sur le VPS :
Nom d'utilisateur : <user>
Mot de passe :      <passwd>

c'est bon on a tout ce qu'il faut pour se connecter au serveur

2. Configuration de Ansible

On part du principe qu'Ansible est déjà installé et que vous avez au moins une configuration de base qui vous permette de lancer un playbook ou une commande Ad-hoc

Dans la configuration de mon ficher Ansible j'ai au moins ces keys définies:

roles_path       = /path-to-ansible-project/ansible_skeleton/roles/
host_key_checking = False
ansible_python_interpreter = /usr/bin/python3
remote_user = kairel
  • roles_path: chemin des rôles : par défaut ansible utilise d'autres chemins , perso j'aime bien mettre les playbooks dans un répertoire playbooks et mes roles dans un répertoire roles
  • host_key_checking; ne vérifier pas l'intégrité de la key : ne pas utiliser quand on sait faire autrement
  • remote_user: l'utilisateur par défaut avec lequel ansible va se connecter au serveur distant

On le verra peut-être dans un autre article mais j'utilise souvent les surcharges dans Ansible, et notemment ici pour la configuration, Ansible prendra en priorité la configuration du fichier du répertoire courant :)

Dans mon projet j'ai donc cette structure:

et si on regarde plus en détail :

Comme on peut le voir tout le code et donc les tâches sont dans les rôles.

On créera le rôle tout à l'heure , ici c'est juste pour montrer l'arborescence cible .

On va maintenant ajouter notre serveur à l'inventaire de ansible .

On édite le fichier production à la racine de notre projet ( on l'appel comme on veut ,je donne des noms d'environnements exprès pour isoler les serveurs)

[new_server]

<IP> ansible_user=<user> ansible_password=<passwd>

[kairel]

kairel.fr

Ici vous reprenez les informations reçues dans votre mail OVH de création de serveur

Par défaut on évite de configurer ansible pour qu'il se connecte via un user/password mais pour débuter et pour une 1ère connexion ça ira très bien

On peut déja tester si notre configuration est opérationnelle via une commande Ad hoc :

Si vous avez une erreur , il est possible que ce soit parce que le programme sshpass n'est pas installé  .

Ici on a finis la configuration d'ansible

3. Les rôles docker & customisation

Le but de ce post n'étant pas de vous expliquer comment fonctionne Ansible , je vais juste vous mettre mon playbook et mon rôle docker avec un peu d'explications

1. Le playbook: new_server.yml (dans playbooks/common)

---
- hosts: new_server
  vars:
    install: true
  tasks:
    - name: Info debug
      ansible.builtin.debug:
        msg: "Install new server"

    - name: Include customize server
      include_role:
        name: common

    - name: Include docker
      include_role:
        name: docker

Explications:

Ici j'appelle le host défini plus haut (new_server) sur lequel je viens appliquer des roles (dans ces roles se trouvent les tâches à éxécuter)

Je set la variable (en vrai on fera plutôt ça avec des tags) install à true on verra aprés pourquoi

Je ne mets pas tous les roles que j'utilise , je laisse uniquement ceux qui nous intéressent

2. Le rôle common

On va dans le répertoire roles/, on crée un répertoire common et 3 sous-répertoires templates, tasks et vars , de façon a avoir cette structure:

pas la peine de reprendre tous les fichiers on va se concentrer sur celui des tâches

Le fichier main.yml

---
- name: include intall tasks
  include_tasks:
    file: customize_new_server.yml
  when: install is defined
       

On retrouve ici la variable install , elle va nous permettre d'appeler un fichier différent en fonction de l'action que l'on veut faire, par exemple dans ce rôle je mets aussi à jour les clés ssh , j'ai donc une variable update etc ...

Le fichier customize_new_server.yml

---

- name: Install package
  apt:
    pkg:
      - sudo
      - htop
    update_cache: yes
  become: yes

- name: Create group
  group:
    name: '{{ group }}'
    state: present
  become: yes

- name: Create user if not exist
  user:
    name: '{{ user }}'
    shell: /bin/bash
    home: '/home/{{ user }}'
    comment: user
    generate_ssh_key: yes
    group: '{{ group }}'
    groups: '{{ sudo_group }}'
    password: "{{ password | password_hash('sha512') }}"
  become: yes

- name: Set authorized keys for app user
  template:
    src: 'authorized_keys.j2'
    dest: '/home/{{ user }}/.ssh/authorized_keys'
    owner: '{{ user }}'
    group: '{{ group }}'
  become: yes

- name: Insert/Update alias and history
  blockinfile:
    path: '/home/{{ user }}/.bashrc'
    block: |
      alias ll='ls -ailh'
      export HISTTIMEFORMAT='%x %T '
  become: yes

- name: ssh with passwd auth
  lineinfile:
    path: '/etc/ssh/sshd_config'
    regexp: '^(.*)PasswordAuthentication(.*)$'
    line: 'PasswordAuthentication no'
  become: yes

- name: Set user sudo without password
  template:
    src: 'user.sudoers.j2'
    dest: '/etc/sudoers.d/{{ user }}'
  become: yes

- name: Set a hostname
  hostname:
    name: '{{ hostname }}'
  when: hostname is defined
  become: true

# Package + RVM----------------------------

- name: Install package
  apt:
    pkg:
      - curl
      - rsync
      - git
      - ca-certificates
      - gnupg
      - lsb-release
      - vlan
      - telnet
    update_cache: yes
  become: yes

Je vous passe tout ce que cela fait , mais je customise mon serveur en :

  • ajoutant les clés SSH pour une connexion plus sécure
  • suppression de la connexion par password
  • installation de packages utiles
  • ajouter des sudoers
  • création d'un user générique

Dans le repertoire vars un fichier main avec la définition des variables (j'utilise ansible vault je ne peux donc pas vous donnez le ficher exact, il faudra l'adapter)

---
user:                 user
group:                user
sudo_group:           sudo

Dans le répertoire Templates , ce sont les fichiers .j2 comme par exemple le fichier user.sudoers.j2

# User rules for debian
{{ user }} ALL=(ALL) NOPASSWD:ALL

3. Le rôle docker

dans le répertoire roles , créer la structure comme ci-dessous

Le fichier main.yml (dans tasks)

---

- name: Install package
  apt:
    pkg:
      - ca-certificates
      - curl
      - lsb-release
      - apt-transport-https
      - software-properties-common
      - gnupg2
      - python3-pip
    update_cache: yes
  become: yes

- name: add key for debian os
  shell: 'curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add '

- name: add repo key for debian os
  shell: 'add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"'
  become: yes

- name: Install docker
  apt:
    pkg:
      - docker-ce
    update_cache: yes
  become: yes
 
- name: Add user to docker group
  user:
    name: '{{ user }}'
    groups: docker
    append: yes
  become: yes

- name: Add logrotate for docker log
  template:
    src: 'logrotate/docker.j2'
    dest: '/etc/logrotate.d/docker'
    owner: 'root'
    group: 'root'
  become: yes

#Install docker-compose
- name: Download docker-compose binary
  get_url:
    url: 'https://github.com/docker/compose/releases/download/v2.5.1/docker-compose-linux-x86_64'
    dest: '/tmp/'
    mode: '0755'
  become: true

- name: move binary
  shell: 'mv /tmp/docker-compose-linux-x86_64 /usr/local/bin/docker-compose'
  become: yes

- name: change permission
  shell: 'chmod +x /usr/local/bin/docker-compose'
  become: yes


Le fichier main.yml dans vars

---
user:                 user
group:                user
sudo_group:           sudo

Le fichier docker.j2 dans templates/logrotate

/var/lib/docker/containers/*/*.log {
  rotate 7
  daily
  compress
  missingok
  delaycompress
  copytruncate
}

Une fois le rôle prêt , il suffit de lancer le playbook, d'abord avec un "--check", pour valider que tout est ok

 ansible-playbook -i production playbooks/common/new_server.yml --check

Si tout est ok la même sans le "--check"

et logiquement votre nouveau serveur docker est installé , enjoy

Currently there are no comments, so be the first!