Hola a todos!
Trabajo como desarrollador de Android, y no hace mucho tiempo nos topamos con algunas tareas de rutina en nuestro proyecto que nos gustaría automatizar. Por ejemplo, tenemos 5 sabores diferentes, para cada uno de los cuales necesitamos cargar nuestra construcción en la tela, a veces para diferentes carros varias veces al día. Sí, esta tarea también se puede hacer usando la tarea de gradle, pero me gustaría no comenzar este proceso en la máquina del desarrollador, sino hacerlo de manera centralizada. O, por ejemplo, cargue automáticamente la compilación en Google Play a beta. Bueno, solo quería elegir el sistema CI. Lo que surgió de esto y cómo lo configuramos, por qué está Docker, más adelante en el artículo.

En mi opinión, toda la tarea se dividió en aproximadamente dos etapas:
- Instale y configure Jenkins con el SDK de Android
- Configurar tareas que ya están dentro de Jenkins
En este artículo, quiero tocar el primer punto, y si esto es de interés para alguien, en el próximo artículo describiré el proceso de configuración de tareas de ensamblaje en Jenkins.
Entonces, el primer punto es la instalación y configuración del sistema Jenkins
Habré ya tiene un artículo maravilloso sobre este tema, pero ya lleva un par de años y algunas cosas están un poco desactualizadas (por ejemplo, sdkmanager), aunque me ayudó mucho a descubrir qué y cómo hacer en las etapas iniciales.Si observa la
documentación oficial para instalar Jenkins, veremos tres formas diferentes de hacerlo: inicie una imagen acoplada lista para usar, descargue y ejecute un archivo war, y también simplemente instale jenkins en el sistema a la antigua usanza (por ejemplo,
apt-get install jenkins
usando ubuntu como ejemplo). La primera opción es la más correcta, ya que no lleva configuraciones innecesarias y dependencias a nuestro sistema host, y en cualquier momento, incluso si algo sale mal, es fácil y simple eliminar todo y comenzar de nuevo. Pero la imagen estándar de Docker para Jenkins contiene algunos de los datos que no necesitamos (por ejemplo, el complemento blueocean) y no contiene lo que definitivamente necesitaremos (por ejemplo, Android SDK). Se decidió crear nuestra propia imagen de acoplador que en su interior descargará y ejecutará el archivo war, descargará e instalará el sdk de Android, y configurará todas las demás configuraciones que necesitemos. Para iniciarlo más tarde, necesitamos un sistema host con docker instalado. Sugiero aquí no reinventar la rueda y usar DigitalOcean.
Crear y configurar una máquina virtual
Para empezar, si alguien más no está registrado allí, sugiero que se
registre (aquí, al momento de escribir el artículo, había un enlace de referencia, pero después de leer las reglas, lo descarté). Después del registro, puede buscar en Google uno u otro código promocional en Internet y obtener unos 10 dólares para comenzar.
Después tenemos que conseguir una nueva gota. Seleccione el elemento Gotitas y luego
Crear gotita .

El sistema host es Ubuntu 18.04. Puede elegir una imagen con Docker ya instalado y configurado, pero haremos todo por nuestra cuenta. Dado que el ensamblaje de las compilaciones de Android aún requiere muchos recursos, debemos elegir una configuración de al menos 20 dólares para que las compilaciones se recopilen normalmente y con relativa rapidez.

Elegiremos una ubicación más cercana (por ejemplo, en Alemania). Luego hay dos opciones sobre cómo nos conectaremos a nuestro servidor virtual. Podemos agregar una clave ssh o prescindir de ella. Si en este lugar no indicamos qué clave usar, la contraseña del usuario raíz se enviará a nuestro correo.

Aquí podemos cambiar el nombre del servidor y completar la creación haciendo clic en el botón
Crear .

Ahora vamos al droplet creado y copiamos la dirección IP para nosotros, para una mayor conexión y configuración.

Necesitamos un cliente ssh. Si trabaja desde debajo de una amapola, entonces puede usar el terminal estándar, si desde debajo de Windows podemos usar masilla para
trabajar o usar
el subsistema Linux (solo para Windows 10). Yo personalmente uso la última opción, y me queda completamente bien.
Conéctese a nuestro servidor usando el siguiente comando
ssh root@YOUR_IP_ADDRESS
La consola le ofrecerá guardar la clave, estamos de acuerdo con esto. Después de conectarnos, crearemos un nuevo usuario para nosotros, lo agregaremos a los superusuarios (y le daremos la oportunidad de usar sudo sin contraseña), le copiaremos la clave de acceso a través de ssh y le diremos que es el propietario de estos archivos (de lo contrario, no funcionará). El
nombre de usuario se cambia a cualquier conveniente para usted.
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
Desconectarse de la raíz con el comando
exit
Y ya nos volveremos a conectar con la ayuda del nuevo usuario creado.
ssh username@YOUR_IP_ADDRESS
Después de actualizar el sistema y reiniciar nuestro servidor (si durante el proceso de actualización el sistema le preguntará algo, es suficiente elegir siempre los valores predeterminados en este caso).
sudo apt update && sudo apt full-upgrade -y && sudo apt autoremove -y && sudo reboot
La configuración básica está completa. Desde el punto de vista del sistema de combate, no es muy seguro, pero dentro del marco de este artículo es completamente adecuado.
Instalar Docker.
Para instalar Docker en nuestro sistema, utilizaremos la
documentación oficial . Dado que tenemos un sistema recién instalado, omitiremos este punto, y si tiene un sistema en el que algo se ha estado ejecutando durante mucho tiempo, por recomendación de los chicos de Docker, elimine las posibles versiones anteriores
sudo apt-get remove docker docker-engine docker.io containerd runc
No olvide conectarse primero a través de ssh a nuestro servidor. La instalación de Docker en sí se describe con gran detalle en la documentación, daré comandos generales para que sea más fácil para usted. Lo que hacen se puede leer allí. Primero agregue el repositorio.
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"
Y luego instale Docker:
sudo apt update && sudo apt install -y docker-ce docker-ce-cli containerd.io
Para que en el futuro podamos llamar a los comandos de Docker sin el prefijo sudo, ejecute el siguiente comando (que también se describe cuidadosamente en las
instrucciones ).
sudo usermod -aG docker username
Después de eso, debe volver a iniciar sesión (usando el comando de salida y reconectando al servidor) para que esto funcione.
Docker está instalado, lo que podemos verificar con el comando
docker run hello-world
Ella descarga la imagen de prueba, la ejecuta en el contenedor. El contenedor, después de comenzar, imprime un mensaje informativo y sale.
¡Felicitaciones, hemos terminado la etapa de preparación del servidor para el trabajo!
Crear tu imagen de Docker
Crearemos la imagen de Docker escribiendo nuestro propio Dockerfile. Ejemplos de cómo hacer esto correctamente en Internet, un vagón y un carrito pequeño, mostraré
mi versión terminada e intentaré comentarla lo más posible. También hay un
manual de
instrucciones de Docker con ejemplos sobre la ortografía correcta y canónica de dockerfile.
Crea y abre tu Dockerfile para editar
touch Dockerfile && nano Dockerfile
En él, por ejemplo, colocaremos el contenido de mi Dockerfile
Todo mi dockerfile con comentarios Algunas aclaraciones:
- Al principio, había un deseo de usar un alpine más ligero en lugar de ubuntu, pero no tiene soporte para ia32-libs , que es necesario para construir proyectos usando el SDK de Android.
- Instalamos openjdk-8-jdk, no el openjdk-8-jdk-headless más liviano, porque algunas funciones de Jenkins necesitan un sistema completo (por ejemplo, mostrar resultados de pruebas unitarias).
- Es necesario instalar configuraciones regionales, debido al hecho de que en algunos proyectos, sin ellos, el ensamblaje de gradle se bloquea sin errores y registros claros, y pasé varios días para llegar al fondo de esta razón (en ubuntu regular que no está en la ventana acoplable, todas las configuraciones regionales se llenan por defecto) .
- Necesitamos aceptar de inmediato todas las licencias para el SDK de Android, de modo que durante el proceso de compilación Jenkins pueda instalar de forma independiente los componentes que necesita (por ejemplo, los SDK que necesita para diferentes versiones de la API). Si es necesario, más adelante dentro del contenedor docker será posible administrar el SDK usando sdkmanager, por ejemplo
sdkmanager --list
permite ver todos los componentes disponibles y todos instalados, y sdkmanager --install "platforms;android-26"
instalará el SDK para la versión 26 de la API. - En general, era posible no iniciar el usuario jenkins y permanecer con el usuario raíz, pero de alguna manera no es del todo correcto, tampoco podría otorgarle derechos de superusuario, pero esto se hizo en términos de conveniencia, si es necesario instalar algo en la etapa de configuración y depuración.
- El tamaño básico de la imagen resultó ser bastante grande (casi 800 mb), pero en general llegué a la conclusión de que para mí esto no es muy crítico, y es más fácil para mí descargarlo de esta forma que pasar tiempo buscando y eliminando paquetes que no necesito.
Después de escribir Dockerfile, debemos convertirlo en una imagen preparada para Docker, en función de qué contenedores se crearán. Esto lo hace simplemente un equipo
docker build -t jenkins-image
donde el parámetro
-t jenkins-image
es responsable del nombre de su imagen, y el punto al final del comando indica que debe buscar el Dockerfile para ensamblar dentro de este directorio. El proceso de compilación en sí toma algo de tiempo, y después de la compilación, la consola debería tener un mensaje similar.
Construido con éxito 9fd8f5545c27
Etiquetado correctamente jenkins-image: último
Lo que nos dice que nuestra imagen se ha ensamblado con éxito, y podemos proceder al siguiente paso, a saber, el lanzamiento de nuestro contenedor
Docker Hub e imágenes listas para usar
Sí, por supuesto, podemos usar nuestra imagen preparada para iniciar el contenedor, pero si necesitamos hacerlo en más de varios dispositivos, crear un Dockerfile cada vez y construir una imagen preparada a partir de él no será muy conveniente. Y si también actualizamos el contenido de nuestro Dockerfile, no será conveniente implementar los cambios en todos los nodos. Para estos fines, existe un repositorio público de imágenes de
Docker Hub . Le permite no recopilar una imagen cada vez, en cada nodo, sino simplemente descargarla desde el repositorio público y usarla por igual en todas las máquinas. Por ejemplo, la imagen que sirvió como ejemplo para este artículo está disponible en el repositorio llamado
osipovaleks / docker-jenkins-android , y más adelante en el artículo trabajaremos con ella.
Este artículo no implica un estudio detallado del Docker Hub, no entenderemos cómo cargar nuestras imágenes allí (aunque esto no es muy difícil) y qué se puede hacer con ellas allí, no entenderemos que todavía puede haber sus propios repositorios públicos o privados, En esto, todo se puede resolver de forma independiente si es necesario.
Lanzamiento de contenedores
Hay dos formas de iniciar un contenedor.
- La primera forma, simplemente usando el
docker run
, le permite hacer esto fácil y rápidamente de la siguiente manera
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
donde el comando de run
tiene los siguientes parámetros
--name jenkins
- nombre del futuro contenedor-d
- iniciar contenedor en segundo plano-it
- banderas para trabajar con STDIN y tty-v jenkins-data:/var/lib/jenkins
y -v jenkins-home:/home/jenkins
- crea (si no se creó) y asigna archivos de volumen especiales a las secciones internas del contenedor que nos permitirán guardar nuestro Jenkins configurado incluso después de la reconstrucción contenedor-p 8080:8080
el puerto del host al puerto del contenedor para que tengamos acceso a la interfaz web (sí, este es el puerto que especificamos en el Dockerfile)--restart unless-stopped
: la opción determina la política de ejecución automática del contenedor después de reiniciar el host (en este caso, inicio automático si el contenedor no se apagó manualmente)osipovaleks/docker-jenkins-android
: imagen para la implementación.
A la salida de la consola de Docker, deberíamos obtener la identificación del contenedor creado y también mostrar información sobre cómo se carga la imagen en el sistema (por supuesto, si aún no está cargada), algo como esto
No se puede encontrar la imagen 'osipovaleks / docker-jenkins-android: latest' localmente
último: extracción de osipovaleks / docker-jenkins-android
6cf436f81810: extracción completa
987088a85b96: extracción completa
b4624b3efe06: extracción completa
d42beb8ded59: Pull complete
b3896048bb8c: extracción completa
8eeace4c3d64: extracción completa
d9b74624442c: extracción completa
36bb3b7da419: Pull complete
31361bd508cb: extracción completa
cee49ae4c825: extracción completa
868ddf54d4c1: extracción completa
361bd7573dd0: Pull complete
bb7b15e36ae8: Pull complete
97f19daace79: Pull complete
1f5eb3850f3e: extracción completa
651e7bbedad2: extracción completa
a52705a2ded7: extracción completa
Resumen: sha256: 321453e2f2142e433817cc9559443387e9f680bb091d6369bbcbc1e0201be1c5
Estado: Imagen más reciente descargada para osipovaleks / docker-jenkins-android: latest
ef9e5512581da66d66103d9f6ea6ccd74e5bdb3776747441ce6a88a98a12b5a4
- La segunda forma de comenzar implica escribir un archivo de composición especial, donde el comando de ejecución simplemente se describe usando el lenguaje YAML y se inicia usando Docker Compose.
Para hacer esto, necesitamos instalarlo:
sudo apt update && sudo apt install -y docker-compose
A continuación, cree un directorio para el proyecto (esto es importante si le importa cómo se llamarán los volúmenes creados automáticamente para el contenedor) y vaya a él
mkdir jenkinsProject && cd jenkinsProject
y dentro creamos el archivo de composición en sí y pasamos al modo de edición
touch docker-compose.yml && nano docker-compose.yml
y poner los siguientes contenidos en él
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:
En él, tal vez, solo la primera línea plantea preguntas ( version: '3'
) que indica la versión de las capacidades del archivo de composición, así como una sección con el bloque de volumes
que enumera las utilizadas en este contenedor
Ejecute su contenedor con el comando:
docker-compose up -d
donde el indicador -d
también indica que el contenedor se creará y se iniciará en segundo plano. Como resultado, Docker debería mostrar algo como lo siguiente:
Creación del volumen "jenkinsproject_jenkins-data" con el controlador predeterminado
Creación del volumen "jenkinsproject_jenkins-home" con el controlador predeterminado
Tirando de jenkins (osipovaleks / docker-jenkins-android: latest) ...
último: extracción de osipovaleks / docker-jenkins-android
6cf436f81810: extracción completa
987088a85b96: extracción completa
b4624b3efe06: extracción completa
d42beb8ded59: Pull complete
b3896048bb8c: extracción completa
8eeace4c3d64: extracción completa
d9b74624442c: extracción completa
36bb3b7da419: Pull complete
31361bd508cb: extracción completa
cee49ae4c825: extracción completa
868ddf54d4c1: extracción completa
361bd7573dd0: Pull complete
bb7b15e36ae8: Pull complete
97f19daace79: Pull complete
1f5eb3850f3e: extracción completa
651e7bbedad2: extracción completa
a52705a2ded7: extracción completa
Resumen: sha256: 321453e2f2142e433817cc9559443387e9f680bb091d6369bbcbc1e0201be1c5
Estado: Imagen más reciente descargada para osipovaleks / docker-jenkins-android: latest
Creando Jenkins ...
Creando jenkins ... hecho
¿Recuerdas que dije que el nombre de los volúmenes creados dependerá del nombre del proyecto? Ejecute el comando:
docker volume ls
y obtenemos tal salida
NOMBRE DE VOLUMEN DEL CONDUCTOR
jenkinsproject_jenkins-data local
jenkinsproject_jenkins-home local
donde veremos que a pesar del hecho de que el nombre del volumen fue elegido por jenkins-home
, en realidad, un prefijo del nombre del proyecto se jenkinsproject _jenkins-home
a él y el nombre del volumen resultó ser jenkinsproject _jenkins-home
¿Qué opción de inicio usar? Aquí puede elegir por sí mismo, se cree que Docker Compose es más una herramienta para lanzar varios contenedores a la vez, que están vinculados entre sí, y si necesita iniciar solo un contenedor, puede usar el
docker run
.
Ahora, después de estos pasos secundarios para iniciar y configurar el servidor, así como también para iniciar el contenedor con Jenkins, podemos proceder a su configuración inicial
Configuración inicial de Jenkins
Tome la dirección IP de nuestro servidor, agregue el puerto 8080 indicado por nosotros y siga este enlace en el navegador.
http://YOUR_IP_ADDRESS:8080/
Si antes de eso todo se configuró y comenzó correctamente, entonces aquí veremos la siguiente imagen

Para la primera configuración, necesitamos ingresar la contraseña que el sistema generó durante la instalación. Para hacer esto, solo necesitamos mirar el contenido del archivo
/var/lib/jenkins/secrets/initialAdminPassword
. Pero este archivo está dentro de nuestro contenedor en ejecución, y para leerlo, necesitamos conectarnos al contenedor usando el siguiente comando:
docker exec -it jenkins /bin/bash
donde la opción
-it
es similar a ejecutar
docker run
,
jenkins
es el nombre de nuestro contenedor y
/bin/bash
ejecutará
/bin/bash
para nosotros en el contenedor y le dará acceso. Después de eso, podemos ver la contraseña inicial para Jenkins:
cat /var/lib/jenkins/secrets/initialAdminPassword
lo siguiente aparece en la consola
91092b18d6ca4492a2759b1903241d2a
Esta es la contraseña.
El usuario ALexhha sugirió una opción más simple para leer esta contraseña, sin conectarse al contenedor en sí. El hecho es que al momento de lanzar Jenkins, esta contraseña se muestra en los registros. Resulta que todo lo que necesitamos es leer los registros del contenedor. En nuestro caso, esto se hace con el siguiente comando: docker logs jenkins
donde jenkins
nombre de nuestro contenedor, y en los registros puede ver lo siguiente:***************************************************** ***********
***************************************************** ***********
******************************************** .... ***********
Se requiere la configuración inicial de Jenkins. Se ha creado un usuario administrador y se ha generado una contraseña.
Utilice la siguiente contraseña para proceder a la instalación:
91092b18d6ca4492a2759b1903241d2a
Esto también se puede encontrar en: / var / lib / jenkins / secrets / initialAdminPassword
******************************************** .... ***********
******************************************** .... ***********
******************************************** .... ***********
Esta opción es un poco más simple y rápida.Cópielo, péguelo en el campo
Contraseña de administrador en la interfaz web y haga clic en
Continuar . En la siguiente pantalla, seleccione
Instalar complementos sugeridos e instale un conjunto de complementos predeterminados.


Después de instalar los complementos, cree un usuario para nosotros y haga clic en
Guardar y finalizar
Estamos de acuerdo con la sección Configuración de instancia, donde se nos pide que completemos la URL en la que trabajará Jenkins (en nuestro caso, deje todo como está)

Y en la siguiente pantalla, haga clic en el preciado
Comenzar a usar Jenkins
¡Así que instalamos y lanzamos Jenkins!

Ya es bastante posible trabajar con él, pero para recopilar nuestras compilaciones de Android, deberá configurar algunos puntos más. La localización de Jenkins está relacionada con el idioma seleccionado de su navegador y, por supuesto, la traducción al ruso no está completamente terminada, y obtenemos una mezcla infernal de ruso e inglés. Si tuvo éxito exactamente de la misma manera, y eso lo enfurece, entonces puede usar el
complemento especial y configurar el idioma predeterminado de la interfaz. Bueno, o cambie su navegador a la interfaz en inglés.
Vaya a la configuración de Jenkins y seleccione
Configuración del sistema.
Verifique las
variables de entorno e ingrese el nombre
ANDROID_HOME en el campo y especifique
/ var / lib / android-sdk / en el campo (especificamos estos datos en el Dockerfile como el directorio de inicio para el SDK de Android).

Haga clic en el botón
Guardar , salga de esta sección de configuración y vaya a la sección llamada
Configuración de herramientas globales .

Configure la partición
JDK (donde la variable JAVA_HOME también fue poblada por nosotros en el Dockerfile, y podemos usar su valor
/ usr / lib / jvm / java-8-openjdk-amd64 / here ).

También aquí todavía tenemos que completar la sección de
Gradle . Seleccionamos e instalamos la versión de Gradle que se utiliza en los proyectos que creará con este sistema CI.
Puedes tener varias versiones. Tampoco puede iniciar la variable Gradle si tiene gradlew en el repositorio, por ejemplo, y puede construirlo con él.
Con esto podemos terminar nuestra primera etapa. El sistema Jenkins está en pleno funcionamiento y podemos pasar a personalizar las tareas de compilación ellos mismos. Tenga en cuenta que el sistema se ajustó a nuestras necesidades y aquí puede no proporcionarle lo que necesita; por ejemplo, no hay emuladores de Android para pruebas y NDK.Si este artículo le interesa a alguien, entonces continuaré en la segunda parte con un ejemplo de uno o dos problemas, describiré la integración de Jenkins y Bitbucket (es él, no Github, porque es más fácil con repositorios privados gratuitos y artículos en Internet sobre es más pequeño, pero quizás más divertido), te diré cómo hacer amigos con la clave ssh de nuestro contenedor con el repositorio, sobre notificaciones por correo electrónico, así como varios otros chips. En general, sobre todo lo que hemos configurado.Te pido que no patees mucho, este es mi primer artículo sobre Habr. Bueno para todos!