Bonjour à tous!
Je travaille en tant que développeur Android, et il n'y a pas si longtemps, nous avons rencontré des tâches de routine sur notre projet que nous aimerions automatiser. Par exemple, nous avons 5 saveurs différentes, pour chacune desquelles nous devons télécharger notre build sur fabric, parfois pour différents chariots plusieurs fois par jour. Oui, cette tâche peut être effectuée avec une tâche gradle, mais je voudrais ne pas exécuter ce processus sur la machine du développeur, mais le faire de manière centrale. Ou, par exemple, téléchargez automatiquement la version dans Google Play en version bêta. Eh bien, je voulais juste choisir le système CI. Qu'est-ce qui est arrivé et comment nous l'avons mis en place, pourquoi Docker, plus loin dans l'article.

À ma connaissance, l'ensemble de la tâche a été divisée en deux étapes environ:
- Installez et configurez Jenkins lui-même avec le SDK Android
- Configurer des tâches déjà dans Jenkins
Dans cet article, je veux aborder le premier point, et si cela intéresse quelqu'un, je décrirai dans le prochain article le processus de configuration des tâches d'assemblage dans Jenkins lui-même.
Donc, le premier point est l'installation et la configuration du système Jenkins
Habré a déjà un merveilleux article sur ce sujet, mais elle a déjà quelques années, et certaines choses sont légèrement dépassées (par exemple sdkmanager), même si elle m'a beaucoup aidé à comprendre quoi et comment faire aux étapes initiales.Si vous consultez la
documentation officielle pour l'installation de Jenkins, nous verrons trois façons différentes de le faire: lancer une image docker prête à l'emploi, télécharger et exécuter un fichier war, et aussi simplement installer jenkins dans le système à l'ancienne (par exemple,
apt-get install jenkins
utilisant ubuntu comme exemple). La première option est la plus correcte, car elle ne transporte pas de paramètres et de dépendances inutiles sur notre système hôte, et à tout moment, même en cas de problème, il est facile et simple de tout supprimer et de recommencer. Mais l'image docker standard pour jenkins contient certaines des données dont nous n'avons pas besoin (par exemple, le plugin blueocean) et ne contiennent pas ce dont nous aurons certainement besoin (par exemple, android sdk). Il a été décidé de créer notre propre image docker qui, à l'intérieur, téléchargera et exécutera le fichier war, téléchargera et installera le sdk android, ainsi que configurera tous les autres paramètres dont nous avons besoin. Pour le démarrer plus tard, nous avons besoin d'un système hôte avec docker installé. Je suggère ici de ne pas réinventer la roue et d'utiliser DigitalOcean.
Créer et configurer une machine virtuelle
Pour commencer, si quelqu'un d'autre n'y est pas inscrit, je suggère de
m'inscrire (ici au moment de la rédaction de l'article il y avait un lien de parrainage, mais après avoir lu les règles je l'ai jeté). Après l'enregistrement, vous pouvez google un ou un autre code promotionnel sur Internet, et obtenir environ 10 dollars pour commencer.
Après, nous devons obtenir une nouvelle gouttelette. Sélectionnez l'élément Droplets, puis
Créer une droplet .

Le système hôte est Ubuntu 18.04. Vous pouvez choisir une image avec Docker déjà installé et configuré, mais nous ferons tout par nous-mêmes. Étant donné que l'assemblage des builds Android est toujours gourmand en ressources, nous devons choisir une configuration pour au moins 20 dollars afin que les builds soient collectés normalement et relativement rapidement.

Nous choisirons un emplacement plus proche (par exemple, en Allemagne). Ensuite, il existe deux options pour la façon dont nous nous connecterons à notre serveur virtuel. On peut ajouter une clé ssh ou s'en passer. Si, à cet endroit, nous n'indiquons pas quelle clé utiliser, le mot de passe de l'utilisateur root sera envoyé à notre courrier.

Ici, nous pouvons changer le nom du serveur et terminer la création en cliquant sur le bouton
Créer .

Maintenant, nous allons dans le droplet créé et copions l'adresse IP pour nous-mêmes, pour une connexion et une configuration supplémentaires.

Nous avons besoin d'un client ssh. Si vous travaillez sous un pavot, vous pouvez utiliser le terminal standard, si sous Windows, nous pouvons utiliser du mastic pour
travailler ou utiliser
le sous-système Linux (pour Windows 10 uniquement). J'utilise personnellement cette dernière option, et elle me convient parfaitement.
Connectez-vous à notre serveur à l'aide de la commande suivante
ssh root@YOUR_IP_ADDRESS
La console vous proposera de sauvegarder la clé, nous en convenons. Après la connexion, nous allons créer un nouvel utilisateur pour nous-mêmes, l'ajouter aux superutilisateurs (et lui donner la possibilité d'utiliser sudo sans mot de passe), lui copier la clé d'accès via ssh et dire qu'il est le propriétaire de ces fichiers (sinon cela ne fonctionnera pas). Le
nom d'utilisateur est changé en n'importe quel endroit qui vous convient.
useradd -m -s /bin/bash username \ && echo 'username ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \ && mkdir /home/username/.ssh \ && cp /root/.ssh/authorized_keys /home/username/.ssh/authorized_keys \ && chown username:username -R /home/username/.ssh
Se déconnecter de root avec la commande
exit
Et nous nous reconnecterons déjà avec l'aide du nouvel utilisateur créé
ssh username@YOUR_IP_ADDRESS
Après avoir mis à jour le système et redémarré notre serveur (si pendant le processus de mise à jour le système vous demandera quelque chose, il suffit de toujours choisir les valeurs par défaut dans ce cas).
sudo apt update && sudo apt full-upgrade -y && sudo apt autoremove -y && sudo reboot
La configuration de base est terminée. Du point de vue du système de combat, il n'est pas très sécurisé, mais dans le cadre de cet article il est tout à fait adapté.
Installez Docker.
Pour installer Docker dans notre système, nous utiliserons la
documentation officielle . Puisque nous avons un système nouvellement installé, nous ignorerons ce point, et si vous avez un système sur lequel quelque chose fonctionne depuis longtemps, sur la recommandation des gars de Docker, supprimez les anciennes versions possibles
sudo apt-get remove docker docker-engine docker.io containerd runc
N'oubliez pas de vous reconnecter d'abord via ssh à notre serveur. L'installation de Docker lui-même est décrite en détail dans la documentation, je vous donnerai des commandes générales pour vous faciliter la tâche. Ce qu'ils font peut y être lu. Ajoutez d'abord le référentiel.
sudo apt update \ && sudo apt install -y apt-transport-https ca-certificates \ curl gnupg-agent software-properties-common \ && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - \ && sudo apt-key fingerprint 0EBFCD88 \ && sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
Et puis installez Docker lui-même:
sudo apt update && sudo apt install -y docker-ce docker-ce-cli containerd.io
Pour qu'à l'avenir nous puissions appeler des commandes docker sans le préfixe sudo, exécutez la commande suivante (qui est également soigneusement décrite dans les
instructions ).
sudo usermod -aG docker username
Après cela, vous devez vous reconnecter (en utilisant la commande exit et en vous reconnectant au serveur) pour que cela fonctionne.
Docker lui-même est installé, ce que nous pouvons vérifier avec la commande
docker run hello-world
Elle télécharge l'image de test, l'exécute dans le conteneur. Le conteneur, après avoir démarré, imprime un message d'information et se ferme.
Félicitations, nous avons terminé l'étape de préparation du serveur pour le travail!
Création de votre image Docker
Nous allons créer l'image Docker en écrivant notre propre Dockerfile. Des exemples de comment le faire correctement sur Internet un wagon et un petit chariot, je vais montrer
ma version finale, et je vais essayer de commenter autant que possible. Il existe également un
manuel d'instructions de docker lui-même avec des exemples sur l'orthographe correcte et canonique de dockerfile.
Créez et ouvrez votre Dockerfile pour le modifier
touch Dockerfile && nano Dockerfile
Par exemple, nous y mettrons le contenu de mon Dockerfile
Mon dockerfile entier avec commentaires Quelques précisions:
- Au début, il y avait un désir d'utiliser un alpin plus léger au lieu d'ubuntu, mais il ne prend pas en charge ia32-libs , qui est requis pour la construction de projets à l'aide du SDK Android.
- Nous installons openjdk-8-jdk, pas le plus léger openjdk-8-jdk-headless, car certaines fonctions Jenkins ont besoin d'un système complet (par exemple, afficher les résultats des tests unitaires).
- Il est nécessaire d'installer des locales, car sur certains projets, sans eux, l'assembly gradle se bloque sans erreurs claires et sans journaux, et j'ai passé plusieurs jours pour aller au fond de cette raison (sur ubuntu normal qui n'est pas dans docker, toutes les locales sont remplies par défaut) .
- Nous devons accepter immédiatement toutes les licences pour le SDK Android, afin que pendant le processus de construction Jenkins puisse installer indépendamment les composants dont il a besoin (par exemple, les SDK dont il a besoin pour différentes versions d'api). Si nécessaire, plus tard à l'intérieur du conteneur Docker, il sera possible de gérer le SDK à l'aide de sdkmanager, par exemple
sdkmanager --list
permet de visualiser tous les composants disponibles et installés, et sdkmanager --install "platforms;android-26"
installera le SDK pour la version 26 de l'api. - En général, il était possible de ne pas démarrer l'utilisateur jenkins et de rester avec l'utilisateur root, mais en quelque sorte ce n'est pas tout à fait correct, vous ne pouviez pas non plus lui donner des droits de superutilisateur, mais cela a été fait en termes de commodité, si quelque chose doit être installé à l'étape de configuration et de débogage.
- La taille de base de l'image s'est avérée plutôt grande (près de 800 Mo), mais dans l'ensemble, je suis arrivé à la conclusion que pour moi, ce n'est pas très critique, et il est plus facile pour moi de la télécharger sous cette forme que de passer du temps à rechercher et supprimer des packages dont je n'ai pas besoin.
Après avoir écrit Dockerfile, nous devons le transformer en une image prête à l'emploi pour Docker, sur la base des conteneurs qui seront créés. Cela se fait simplement par une équipe
docker build -t jenkins-image
où le
-t jenkins-image
est responsable du nom de votre image et le point à la fin de la commande indique que vous devez rechercher le Dockerfile pour l'assembly dans ce répertoire. Le processus d'assemblage lui-même prend un certain temps, et après l'assemblage, il devrait y avoir quelque chose comme ça dans la console.
9fd8f5545c27 construit avec succès
Tag jenkins-image avec succès: le dernier
Ce qui nous dit que notre image a été assemblée avec succès, et nous pouvons passer à l'étape suivante, à savoir le lancement de notre conteneur
Docker Hub et images prêtes à l'emploi
Oui, bien sûr, nous pouvons utiliser notre image prête à l'emploi pour lancer le conteneur, mais si nous devons le faire sur plus de plusieurs appareils, créer un Dockerfile à chaque fois et en construire une image finie ne sera pas très pratique. Et si nous mettons également à jour le contenu de notre Dockerfile, le déploiement des modifications sur tous les nœuds ne sera pas du tout pratique. À ces fins, il existe un référentiel public d'images
Docker Hub . Il vous permet de ne pas collecter une image à chaque fois, sur chaque nœud, mais simplement de la télécharger à vous-même à partir du référentiel public et de l'utiliser également sur toutes les machines. Par exemple, l'image qui a servi d'exemple pour cet article est disponible dans le référentiel nommé
osipovaleks / docker-jenkins-android , et plus tard dans l'article, nous travaillerons avec.
Cet article n'implique pas une étude détaillée du Docker Hub, nous ne comprendrons pas comment y télécharger nos images (bien que ce ne soit pas très difficile) et ce qui peut être fait avec elles là-bas, nous ne comprendrons pas qu'il puisse toujours y avoir vos propres référentiels publics ou privés personnels, En cela, tout peut être trié indépendamment si nécessaire.
Lancement de conteneurs
Il existe deux façons de démarrer un conteneur.
- La première façon, en utilisant simplement la
docker run
, vous permet de le faire facilement et rapidement de la manière suivante
docker run --name jenkins -d -it -v jenkins-data:/var/lib/jenkins -v jenkins-home:/home/jenkins -p 8080:8080 --restart unless-stopped osipovaleks/docker-jenkins-android
où la commande run
a les paramètres suivants
--name jenkins
- nom du futur conteneur-d
- démarre le conteneur en arrière-plan-it
- drapeaux pour travailler avec STDIN et tty-v jenkins-data:/var/lib/jenkins
et -v jenkins-home:/home/jenkins
- crée (s'il n'est pas créé) et mappe des fichiers de volume spéciaux aux sections internes du conteneur qui nous permettront de sauvegarder nos Jenkins personnalisés même après la reconstruction conteneur-p 8080:8080
- mappez le port hôte sur le port conteneur afin que nous ayons accès à l'interface web (oui c'est le port que nous avons spécifié dans le Dockerfile)--restart unless-stopped
- l'option détermine la stratégie d'exécution automatique du conteneur après le redémarrage de l'hôte (dans ce cas, démarrage automatique si le conteneur n'a pas été désactivé manuellement)osipovaleks/docker-jenkins-android
- image pour le déploiement.
À la sortie de la console Docker, nous devrions obtenir l'id du conteneur créé et également afficher des informations sur la façon dont l'image est chargée dans le système (bien sûr, si elle n'est pas déjà chargée), quelque chose comme ça
Impossible de trouver l'image 'osipovaleks / docker-jenkins-android: latest' localement
dernier: tirant de osipovaleks / docker-jenkins-android
6cf436f81810: Pull complet
987088a85b96: Pull complet
b4624b3efe06: Pull complet
d42beb8ded59: Pull complet
b3896048bb8c: Pull complet
8eeace4c3d64: tirer complet
d9b74624442c: Pull complet
36bb3b7da419: traction complète
31361bd508cb: Pull complet
cee49ae4c825: tirer complet
868ddf54d4c1: Pull complet
361bd7573dd0: Pull complet
bb7b15e36ae8: Pull complet
97f19daace79: Pull complet
1f5eb3850f3e: tirer complètement
651e7bbedad2: Pull complet
a52705a2ded7: Pull complet
Résumé: sha256: 321453e2f2142e433817cc9559443387e9f680bb091d6369bbcbc1e0201be1c5
Statut: Image plus récente téléchargée pour osipovaleks / docker-jenkins-android: dernière
ef9e5512581da66d66103d9f6ea6ccd74e5bdb3776747441ce6a88a98a12b5a4
- La deuxième façon de commencer consiste à écrire un fichier de composition spécial, où la commande d'exécution est simplement décrite en utilisant le langage YAML et est lancée à l'aide de Docker Compose.
Pour ce faire, nous devons l'installer:
sudo apt update && sudo apt install -y docker-compose
Ensuite, créez un répertoire pour le projet (c'est important si vous vous souciez du nom des volumes créés automatiquement pour le conteneur) et allez-y
mkdir jenkinsProject && cd jenkinsProject
et à l'intérieur, nous créons le fichier de composition lui-même et passons en mode édition
touch docker-compose.yml && nano docker-compose.yml
et y mettre le contenu suivant
version: '3' services: jenkins: container_name: jenkins image: osipovaleks/docker-jenkins-android ports: - "8080:8080" restart: unless-stopped volumes: - "jenkins-data:/var/lib/jenkins" - "jenkins-home:/home/jenkins" volumes: jenkins-data: jenkins-home:
Dans ce document, peut-être, seule la première ligne soulève des questions ( version: '3'
) qui indique la version des capacités du fichier de composition, ainsi qu'une section avec le bloc de volumes
qui répertorie celles utilisées dans ce conteneur
Exécutez votre conteneur avec la commande:
docker-compose up -d
où l'indicateur -d
indique également que le conteneur sera créé et lancé en arrière-plan. Par conséquent, Docker devrait afficher quelque chose comme ceci:
Création du volume "jenkinsproject_jenkins-data" avec le pilote par défaut
Création du volume "jenkinsproject_jenkins-home" avec le pilote par défaut
Pulling jenkins (osipovaleks / docker-jenkins-android: dernier) ...
dernier: tirant de osipovaleks / docker-jenkins-android
6cf436f81810: Pull complet
987088a85b96: Pull complet
b4624b3efe06: Pull complet
d42beb8ded59: Pull complet
b3896048bb8c: Pull complet
8eeace4c3d64: tirer complet
d9b74624442c: Pull complet
36bb3b7da419: traction complète
31361bd508cb: Pull complet
cee49ae4c825: tirer complet
868ddf54d4c1: Pull complet
361bd7573dd0: Pull complet
bb7b15e36ae8: Pull complet
97f19daace79: Pull complet
1f5eb3850f3e: tirer complètement
651e7bbedad2: Pull complet
a52705a2ded7: Pull complet
Résumé: sha256: 321453e2f2142e433817cc9559443387e9f680bb091d6369bbcbc1e0201be1c5
Statut: Image plus récente téléchargée pour osipovaleks / docker-jenkins-android: dernière
Création de jenkins ...
Création de jenkins ... terminé
Rappelez-vous, j'ai dit que le nom des volumes créés dépendra du nom du projet? Exécutez la commande:
docker volume ls
et nous obtenons une telle sortie
NOM DU VOLUME DU CONDUCTEUR
jenkinsproject_jenkins-data local
local jenkinsproject_jenkins-home
où nous verrons qu'en dépit du fait que le nom du volume a été choisi par jenkins-home
, en réalité, un préfixe du nom du projet y est resté et que le nom du volume s'est avéré être jenkinsproject _jenkins-home
Quelle option de démarrage utiliser? Ici, vous pouvez choisir par vous-même, on pense que Docker Compose est plutôt un outil pour lancer plusieurs conteneurs à la fois, qui sont liés les uns aux autres, et si vous n'avez besoin d'exécuter qu'un seul conteneur, vous pouvez utiliser la
docker run
.
Maintenant, après ces sous-étapes pour démarrer et configurer le serveur, ainsi que pour démarrer le conteneur avec Jenkins, nous pouvons procéder à sa configuration initiale
Configuration initiale de Jenkins
Prenez l'adresse IP de notre serveur, ajoutez-y le port 8080 que nous vous avons indiqué et suivez ce lien dans le navigateur.
http://YOUR_IP_ADDRESS:8080/
Si avant cela, tout était configuré et démarré correctement, alors ici nous verrons l'image suivante

Pour la première configuration, nous devons saisir le mot de passe généré par le système lors de l'installation. Pour ce faire, il suffit de regarder le contenu du fichier
/var/lib/jenkins/secrets/initialAdminPassword
. Mais ce fichier est à l'intérieur de notre conteneur en cours d'exécution, et pour le lire, nous devons nous connecter au conteneur à l'aide de la commande suivante:
docker exec -it jenkins /bin/bash
où l'option
-it
est similaire à l'exécution de
docker run
,
jenkins
est le nom de notre conteneur et
/bin/bash
exécutera
/bin/bash
pour nous dans le conteneur et lui donnera accès. Après cela, nous pouvons voir le mot de passe initial de Jenkins:
cat /var/lib/jenkins/secrets/initialAdminPassword
ce qui suit apparaît dans la console
91092b18d6ca4492a2759b1903241d2a
Ceci est le mot de passe.
L'utilisateur ALexhha a suggéré une option plus simple pour lire ce mot de passe, sans se connecter au conteneur lui-même. Le fait est qu'au moment du lancement de Jenkins lui-même, ce mot de passe est affiché dans les journaux. Il s'avère que tout ce dont nous avons besoin est de lire les journaux des conteneurs. Dans notre cas, cela se fait avec la commande suivante: docker logs jenkins
où jenkins
nom de notre conteneur, et dans les journaux, vous pouvez voir ce qui suit:***************************************************** ***********
***************************************************** ***********
****************************************** .... ***********
La configuration initiale de Jenkins est requise. Un utilisateur administrateur a été créé et un mot de passe généré.
Veuillez utiliser le mot de passe suivant pour procéder à l'installation:
91092b18d6ca4492a2759b1903241d2a
Vous pouvez également le trouver sur: / var / lib / jenkins / secrets / initialAdminPassword
****************************************** .... ***********
******************************************** .... ***********
******************************************** .... ***********
Cette option est un peu plus simple et plus rapide.Copiez-le, collez-le dans le champ
Mot de passe administrateur de l'interface Web et cliquez sur
Continuer . Sur l'écran suivant, sélectionnez
Installer les plugins suggérés et installez un ensemble de plugins par défaut.


Après avoir installé les plugins, créez un utilisateur pour nous-mêmes et cliquez sur
Enregistrer et terminer
Nous sommes d'accord avec la section de configuration d'instance, où il nous est demandé de remplir l'URL sur laquelle Jenkins fonctionnera (dans notre cas, laissez tout tel quel)

Et sur l'écran suivant, cliquez sur le chéri
Commencer à utiliser Jenkins
Nous avons donc installé et lancé Jenkins!

Il est déjà tout à fait possible de travailler avec, mais pour collecter nos builds Android, vous devrez configurer quelques points supplémentaires. La localisation de Jenkins est liée à la langue sélectionnée de votre navigateur, et bien sûr la traduction en russe n'est pas terminée avant la fin, et nous obtenons un mélange infernal de russe et d'anglais. Si vous avez réussi exactement de la même manière et que cela vous exaspère, vous pouvez utiliser le
plug-in spécial et définir la langue d'interface par défaut. Eh bien, ou passez votre navigateur à l'interface anglaise.
Accédez aux paramètres Jenkins et sélectionnez
Configuration système.
Vérifiez
les variables d'environnement , entrez le nom
ANDROID_HOME dans le champ et spécifiez
/ var / lib / android-sdk / dans le champ (nous avons spécifié ces données dans le Dockerfile comme répertoire de base pour le SDK Android).

Cliquez sur le bouton
Enregistrer , quittez cette section des paramètres et accédez à la section intitulée
Configuration des outils globaux .

Configurez la partition
JDK (où la variable JAVA_HOME a également été remplie par nous dans le Dockerfile, et nous pouvons utiliser sa valeur
/ usr / lib / jvm / java-8-openjdk-amd64 / ici ).

Ici aussi, nous devons encore remplir la section
Gradle . Nous sélectionnons et installons la version de Gradle qui est utilisée dans les projets que vous construirez en utilisant ce système CI.
Vous pouvez avoir plusieurs versions. Vous ne pouvez pas non plus démarrer la variable Gradle du tout si vous avez gradlew dans le référentiel, par exemple, et vous pouvez la construire avec.
Avec cela, nous pouvons terminer notre première étape. Le système Jenkins est entièrement opérationnel et nous pouvons passer à la personnalisation des tâches de construction elles-mêmes. Veuillez noter que le système a été personnalisé en fonction de nos besoins et peut ne pas fournir ce dont vous avez besoin - par exemple, il n'y a pas d'émulateurs Android pour les tests et NDK.Si cet article intéresse quelqu'un, alors je continuerai dans la deuxième partie avec un exemple d'un ou deux tracas, je décrirai l'intégration de Jenkins et Bitbucket (c'est lui, pas Github, car c'est plus facile avec des référentiels privés gratuits et des articles sur Internet à propos de il est plus petit, mais peut-être plus amusant), je vais vous dire comment vous faire des amis avec la clé ssh de notre conteneur avec le référentiel, sur les notifications par e-mail, ainsi que plusieurs autres puces. En général, sur tout ce que nous avons configuré.Je vous demande de ne pas trop taper, c'est mon premier article sur Habr. Bon à tous!