Ce script n’a presque pas pris une ride depuis ces premiers pas sur le chaine youtube. Eh oui c’était la première vidéo de la chaine xavki. Je l’ai légèrement toiletté et j’ai bien sûr mis à jour l’image docker avec une version plus récente de Debian (10).
Il m’est très utilise pour mes formations ansible.
Lorsque j’ai créé ce script, j’avais besoin de tester régulièrement les rôles que je développais. J’utilisais déjà un peu vagrant et je trouvais que lancer une machine virtuelle demandais du temps. Et comme pour bien développer du ansible, il me semble très important de tout casser pour tout refaire, je me suis réorienté vers des conteneurs docker. Après coup, LXD/LXC serait encore plus optimal, ces conteneurs étant des conteneurs systèmes.
Bref, à l’époque j’ai creusé et cherchais comment avoir des conteneurs avec SSH et systemD. Finalement cela n’est pas très compliqué après avoir installé systemd, il suffit de supprimer quelques répertoires et de monter ceux de la machine en dessous.
Cependant attention, cela signifie aussi de lancer ces conteneurs en privileged. Donc tout cela cumulé, rend ce concept très défaillant d’un point de vue sécurité et non sécurisable. Il faut donc l’utiliser et supprimer les conteneurs après utilisation. En tout cas c’est ce que je recommande fortement.
Le Dockerfile d’une Debian avec SSH et SystemD
Je vous propose donc le Dockerfile suivant :
FROM debian:10 ENV container docker ENV LC_ALL C ENV DEBIAN_FRONTEND noninteractive RUN echo 'deb http://deb.debian.org/debian stretch-backports main' >> /etc/apt/sources.list RUN apt-get update \ && apt-get install -y --no-install-recommends systemd python3 sudo bash net-tools openssh-server openssh-client vim git\ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config RUN sed -i 's/#PermitRootLogin/PermitRootLogin/' /etc/ssh/sshd_config RUN rm -f /lib/systemd/system/multi-user.target.wants/* \ /etc/systemd/system/*.wants/* \ /lib/systemd/system/local-fs.target.wants/* \ /lib/systemd/system/sockets.target.wants/*udev* \ /lib/systemd/system/sockets.target.wants/*initctl* \ /lib/systemd/system/sysinit.target.wants/systemd-tmpfiles-setup* \ /lib/systemd/system/systemd-update-utmp* RUN ln -s /lib/systemd/system /sbin/init RUN systemctl set-default multi-user.target RUN sed -i 's#root:\*#root:sa3tHJ3/KuYvI#' /etc/shadow ENV init /lib/systemd/systemd VOLUME [ "/sys/fs/cgroup" ] ENTRYPOINT ["/lib/systemd/systemd"]
Plusieurs remarques donc :
- on installe ssh et systemd
- on permet le root login avec ssh
- on supprime de nombreux liens systemd car notre conteneur ne dispose pas de son propre matériel
- on définit un passsowr pour root (“password” par défaut)
- on prévoit de monter /sysS
- on lance en entrypoint : systemd (donc ssh n’est pas lancé en l’état)
Lancer un conteneur avec SSH/SystemD
Voici comment lancer avec un simple docker run un conteneur avec cette image
Là encore rien de très compliqué :
docker run -d --cap-add NET_ADMIN --cap-add SYS_ADMIN --publish-all=true -v /srv/data:/srv/html -v /sys/fs/cgroup:/sys/fs/cgroup:ro --name <nom_contneeur> -h <nom_conteneur> priximmo/debian_systemd:v1.0
On permet une élévation de privilège de notre conteneur sur notre hosts sur les capabilities NET_ADMIN et SYS_ADMIN.
On publie tous les ports pour pouvoir utiliser les applicatifs sur l’ip du conteneur sans se poser de question.
On monte un répertoire d’échange entre le host et le conteneur pour /srv/data.
On monte en lecture seul /sys/fs/cgroup.
Maintenant on automatise le lancement des conteneurs avec un script bash
L’enjeu est tout de même de pouvoir créer à la volée des conteneurs. Et d’essayer de gagner du temps dans le développement ansible. Au passage, bien sûr, ce script est utilisable dans d’autres cas d’utilisation (testing, dev…).
Voici le script que je vous propose et que vous pourrez personnaliser et compléter à votre goût.
#!/bin/bash ############################################################ # # Description : déploiement à la volée de conteneur docker # # Auteur : Xavier # # Date : 28/12/2018 - V2.0 # ########################################################### # Functions ######################################################### help(){ echo " Options : - --create : lancer des conteneurs - --drop : supprimer les conteneurs créer par le deploy.sh - --infos : caractéristiques des conteneurs (ip, nom, user...) - --start : redémarrage des conteneurs - --ansible : déploiement arborescence ansible " } createNodes() { # définition du nombre de conteneur nb_machine=1 [ "$1" != "" ] && nb_machine=$1 # setting min/max min=1 max=0 # récupération de idmax idmax=`docker ps -a --format '{{ .Names}}' | awk -F "-" -v user="$USER" '$0 ~ user"-debian" {print $3}' | sort -r |head -1` # redéfinition de min et max min=$(($idmax + 1)) max=$(($idmax + $nb_machine)) # lancement des conteneurs for i in $(seq $min $max);do docker run -tid --privileged --publish-all=true -v /srv/data:/srv/html -v /sys/fs/cgroup:/sys/fs/cgroup:ro --name $USER-debian-$i -h $USER-debian-$i priximmo/buster-systemd-ssh docker exec -ti $USER-debian-$i /bin/sh -c "useradd -m -p sa3tHJ3/KuYvI $USER" docker exec -ti $USER-debian-$i /bin/sh -c "mkdir ${HOME}/.ssh && chmod 700 ${HOME}/.ssh && chown $USER:$USER $HOME/.ssh" docker cp $HOME/.ssh/id_rsa.pub $USER-debian-$i:$HOME/.ssh/authorized_keys docker exec -ti $USER-debian-$i /bin/sh -c "chmod 600 ${HOME}/.ssh/authorized_keys && chown $USER:$USER $HOME/.ssh/authorized_keys" docker exec -ti $USER-debian-$i /bin/sh -c "echo '$USER ALL=(ALL) NOPASSWD: ALL'>>/etc/sudoers" docker exec -ti $USER-debian-$i /bin/sh -c "service ssh start" echo "Conteneur $USER-debian-$i créé" done infosNodes } dropNodes(){ echo "Suppression des conteneurs..." docker rm -f $(docker ps -a | grep $USER-debian | awk '{print $1}') echo "Fin de la suppression" } startNodes(){ echo "" docker start $(docker ps -a | grep $USER-debian | awk '{print $1}') for conteneur in $(docker ps -a | grep $USER-debian | awk '{print $1}');do docker exec -ti $conteneur /bin/sh -c "service ssh start" done echo "" } createAnsible(){ echo "" ANSIBLE_DIR="ansible_dir" mkdir -p $ANSIBLE_DIR echo "all:" > $ANSIBLE_DIR/00_inventory.yml echo " vars:" >> $ANSIBLE_DIR/00_inventory.yml echo " ansible_python_interpreter: /usr/bin/python3" >> $ANSIBLE_DIR/00_inventory.yml echo " hosts:" >> $ANSIBLE_DIR/00_inventory.yml for conteneur in $(docker ps -a | grep $USER-debian | awk '{print $1}');do docker inspect -f ' {{.NetworkSettings.IPAddress }}:' $conteneur >> $ANSIBLE_DIR/00_inventory.yml done mkdir -p $ANSIBLE_DIR/host_vars mkdir -p $ANSIBLE_DIR/group_vars echo "" } infosNodes(){ echo "" echo "Informations des conteneurs : " echo "" for conteneur in $(docker ps -a | grep $USER-debian | awk '{print $1}');do docker inspect -f ' => {{.Name}} - {{.NetworkSettings.IPAddress }}' $conteneur done echo "" } # Let's Go !!! ###################################################################"" #si option --create if [ "$1" == "--create" ];then createNodes $2 # si option --drop elif [ "$1" == "--drop" ];then dropNodes # si option --start elif [ "$1" == "--start" ];then startNodes # si option --ansible elif [ "$1" == "--ansible" ];then createAnsible # si option --infos elif [ "$1" == "--infos" ];then infosNodes # si aucune option affichage de l'aide else help fi
Plusieurs options sont prévues :
- –create : la création de conteneurs en ajoutant à cette option un nombre pour indiquer le nombre de docker souhaités
- –drop : pour supprimer les conteneurs lancés avec ce script
- –start : en cas d’arrêt et de relance de votre machine, les conteneurs seront stoppés, cette options permet de les relancer à la volée
- –ansilbe : créé un répertoire dédié aux développements ansible avec notamment un inventory déjà rempli et complété par les ip de chacun des conteneurs
- –infos : pour lister les ip des conteneurs créés
Bien sûr on organise tout cela avec des fonctions bash. La plus fournie étant la fonction de création qui notamment :
- créé un user du même nom du user qui lance le script
- lui définit un password par défaut à “password”
- lui copie votre clef publique dans le authorized_keys
- lance ssh (cf dans notre dockerfile on ne lançait que systemd et pas sshd)
Voilà, j’ai déjà eu pas mal de retour positifs ou de gens qui ont customisé ce script. Certains ont ajouté d’autres OS également. A vous de voir et de vous faire plaisir en personnalisant tout cela et en l’adaptant au mieux à votre cas d’utilisation.
Tout le code source est ici.