Olá pessoal!
Eu trabalho como desenvolvedor Android, e há pouco tempo realizamos algumas tarefas rotineiras em nosso projeto que gostaríamos de automatizar. Por exemplo, temos 5 sabores diferentes, para cada um dos quais precisamos fazer upload de nossa compilação no tecido, às vezes para carrinhos diferentes várias vezes ao dia. Sim, essa tarefa pode ser realizada com a tarefa gradle, mas eu gostaria de não executar esse processo na máquina do desenvolvedor, mas de alguma forma centralizada. Ou, por exemplo, faça upload automaticamente da compilação no google play para a versão beta. Bem, eu só queria escolher o sistema de CI. O que saiu disso e como o configuramos, por que existe o Docker, mais adiante neste artigo.

No meu entendimento, toda a tarefa foi dividida em aproximadamente duas etapas:
- Instale e configure o próprio Jenkins com o SDK do Android
- Configurar tarefas já dentro do Jenkins
Neste artigo, quero abordar o primeiro ponto e, se isso for de interesse de alguém, no próximo artigo, descreverei o processo de configuração de tarefas de montagem no próprio Jenkins.
Portanto, o primeiro ponto é a instalação e configuração do sistema Jenkins
Habré já tem um artigo maravilhoso sobre esse assunto, mas ela já tem alguns anos e algumas coisas estão um pouco desatualizadas (por exemplo, sdkmanager), embora ela tenha me ajudado muito a descobrir o que e como fazer nos estágios iniciais.Se você olhar a
documentação oficial para a instalação do Jenkins, veremos três maneiras diferentes de fazer isso: iniciar uma imagem do docker pronta para download, baixar e executar um arquivo de guerra e também instalar o jenkins no sistema à moda antiga (por exemplo,
apt-get install jenkins
usando o ubuntu como exemplo). A primeira opção é a mais correta, porque não carrega configurações e dependências desnecessárias para o sistema host e, a qualquer momento, mesmo que algo dê errado, é fácil e simples excluir tudo e começar de novo. Mas a imagem padrão do docker para jenkins contém alguns dados que não precisamos (por exemplo, o plug-in blueocean) e não contêm o que definitivamente precisaremos (por exemplo, android sdk). Foi decidido criar nossa própria imagem do docker que, dentro dele, fará o download e executará o arquivo war, baixará e instalará o android sdk, além de definir todas as outras configurações necessárias. Para iniciar mais tarde, precisamos de um sistema host com o docker instalado. Sugiro aqui não reinventar a roda e usar o DigitalOcean.
Crie e configure uma máquina virtual
Para começar, se alguém não estiver registrado lá, sugiro que se
registre (aqui, no momento da redação do artigo, havia um link de referência, mas depois de ler as regras, joguei fora). Após o registro, você pode pesquisar no Google um ou outro código promocional na Internet e obter cerca de 10 dólares para começar.
Depois, precisamos obter uma nova gota. Selecione o item Gotas e, em seguida,
Criar gota .

O sistema host é o Ubuntu 18.04. Você pode escolher uma imagem com o Docker já instalado e configurado, mas faremos tudo por conta própria. Como a montagem de compilações do Android ainda exige muitos recursos, precisamos escolher uma configuração de pelo menos 20 dólares para que as compilações sejam coletadas normalmente e relativamente rapidamente.

Escolheremos um local mais próximo (por exemplo, na Alemanha). Depois, existem duas opções de como nos conectaremos ao nosso servidor virtual. Podemos adicionar uma chave ssh ou ficar sem ela. Se neste local não indicarmos qual chave usar, a senha do usuário root será enviada para o nosso correio.

Aqui podemos alterar o nome do servidor e concluir a criação clicando no botão
Criar .

Agora vamos para o droplet criado e copiamos o endereço IP para nós, para mais conexão e configuração.

Precisamos de um cliente ssh. Se você trabalha com uma papoula, pode usar o terminal padrão; se, no Windows, podemos usar massa para
trabalhar ou usar
o subsistema Linux (somente para Windows 10). Eu pessoalmente uso a última opção, e ela me convém completamente.
Conecte-se ao nosso servidor usando o seguinte comando
ssh root@YOUR_IP_ADDRESS
O console oferecerá que você salve a chave, concordamos com isso. Após a conexão, criaremos um novo usuário para nós mesmos, adicionaremos aos superusuários (e daremos a ele a oportunidade de usar o sudo sem senha), copiaremos a chave de acesso via ssh e dizeremos que ele é o proprietário desses arquivos (caso contrário, não funcionará). O
nome de usuário é alterado para qualquer conveniente para você.
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
Desconecte da raiz com o comando
exit
E vamos reconectar já com a ajuda do novo usuário criado
ssh username@YOUR_IP_ADDRESS
Depois de atualizar o sistema e reiniciar o servidor (se durante o processo de atualização o sistema solicitar algo, basta escolher sempre os valores padrão nesse caso).
sudo apt update && sudo apt full-upgrade -y && sudo apt autoremove -y && sudo reboot
A configuração básica está concluída. Do ponto de vista do sistema de combate, ele não é muito seguro, mas dentro da estrutura deste artigo é completamente adequado.
Instale o Docker.
Para instalar o Docker em nosso sistema, usaremos a
documentação oficial . Como temos um sistema recém-instalado, pularemos esse ponto e, se você tiver um sistema em que algo esteja em execução há muito tempo, por recomendação dos caras do Docker, exclua possíveis versões antigas
sudo apt-get remove docker docker-engine docker.io containerd runc
Não se esqueça de primeiro conectar-se novamente via ssh ao nosso servidor. A instalação do Docker em si é descrita em detalhes na documentação; darei comandos gerais para facilitar isso para você. O que eles fazem pode ser lido lá. Primeiro adicione o repositório.
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"
E instale o próprio Docker:
sudo apt update && sudo apt install -y docker-ce docker-ce-cli containerd.io
Para que, no futuro, possamos chamar comandos do docker sem o prefixo sudo, execute o seguinte comando (que também é cuidadosamente descrito nas
instruções ).
sudo usermod -aG docker username
Depois disso, é necessário efetuar login novamente (usando o comando exit e reconectando-se ao servidor) para que isso funcione.
O Docker está instalado, o que podemos verificar com o comando
docker run hello-world
Ela baixa a imagem de teste e a executa no contêiner. O contêiner, após iniciar, imprime uma mensagem informativa e sai.
Parabéns, terminamos o estágio de preparação do servidor para o trabalho!
Criando sua imagem do Docker
Criaremos a imagem do Docker escrevendo nosso próprio Dockerfile. Exemplos de como fazer isso corretamente na Internet: uma carroça e um carrinho pequeno, mostrarei
minha versão final e tentarei comentar o máximo possível. Há também um
manual de
instruções do docker em si, com exemplos sobre a ortografia correta e canônica do dockerfile.
Crie e abra seu Dockerfile para edição
touch Dockerfile && nano Dockerfile
Nele, por exemplo, colocaremos o conteúdo do meu Dockerfile
Meu dockerfile inteiro com comentários Alguns esclarecimentos:
- No começo, havia um desejo de usar um alpino mais leve em vez do ubuntu, mas ele não possui suporte a ia32-libs , necessário para criar projetos usando o Android SDK.
- Instalamos o openjdk-8-jdk, não o openjdk-8-jdk-headless, mais leve, porque algumas funções do Jenkins precisam de um sistema completo (por exemplo, exibindo resultados de teste de unidade).
- É necessário instalar localidades, devido ao fato de que em alguns projetos, sem eles, o conjunto gradle falha sem erros e logs claros, e eu passei vários dias para chegar ao fundo desse motivo (em um ubuntu normal que não está no docker, todos os locais são preenchidos por padrão) .
- Precisamos aceitar imediatamente todas as licenças do Android SDK, para que, durante o processo de compilação, o Jenkins possa instalar independentemente os componentes necessários (por exemplo, os SDKs necessários para diferentes versões da API). Se necessário, posteriormente, dentro do contêiner do docker, será possível gerenciar o SDK usando o sdkmanager, por exemplo, o
sdkmanager --list
permite exibir todos os componentes disponíveis e todos os componentes instalados e o sdkmanager --install "platforms;android-26"
instalará o SDK para a versão 26 da API. - Em geral, era possível não iniciar o usuário jenkins e ficar com o usuário root, mas de alguma forma não está certo, você também não podia conceder direitos de superusuário, mas isso era feito em termos de conveniência, se algo precisasse ser instalado no estágio de instalação e depuração.
- O tamanho básico da imagem acabou sendo bastante grande (quase 800 mb), mas no geral cheguei à conclusão de que isso não é muito crítico para mim e é mais fácil fazer o download deste formulário do que gastar tempo pesquisando e removendo pacotes dos quais não preciso.
Após escrever o Dockerfile, precisamos transformá-lo em uma imagem pronta para o Docker, com base em quais contêineres serão criados. Isso é feito simplesmente por uma equipe
docker build -t jenkins-image
em que o parâmetro
-t jenkins-image
é responsável pelo nome da sua imagem e o ponto no final do comando indica que você precisa procurar o Dockerfile para o assembly dentro deste diretório. O processo de montagem em si leva algum tempo e, após a montagem, deve haver algo assim no console.
9fd8f5545c27 construído com sucesso
Marcado com sucesso jenkins-image: mais recente
O que nos diz que nossa imagem foi montada com sucesso e podemos prosseguir para a próxima etapa, a saber, o lançamento de nosso contêiner.
Docker Hub e imagens prontas
Sim, é claro, podemos usar nossa imagem pronta para iniciar o contêiner, mas se precisarmos fazer isso em mais de vários dispositivos, criar um Dockerfile a cada vez e criar uma imagem pronta a partir dele não será muito conveniente. E se também atualizarmos o conteúdo do nosso Dockerfile, implementar as alterações em todos os nós não será conveniente. Para esses fins, há um repositório público de imagens do
Docker Hub . Ele permite que você não colete uma imagem toda vez, em cada nó, mas simplesmente faça o download para si mesmo do repositório público e use-a igualmente em todas as máquinas. Por exemplo, a imagem que serviu de exemplo para este artigo está disponível no repositório denominado
osipovaleks / docker-jenkins-android e, posteriormente, no artigo, trabalharemos com ela.
Este artigo não implica um estudo detalhado do Docker Hub, não entenderemos como enviar nossas imagens para lá (embora isso não seja muito difícil) e o que pode ser feito com elas, não entenderemos que ainda pode haver seus próprios repositórios públicos ou privados, Neste, tudo pode ser resolvido independentemente, se necessário.
Lançamento de contêiner
Existem duas maneiras de iniciar um contêiner.
- A primeira maneira, simplesmente usando o
docker run
, permite fazer isso com facilidade e rapidez da seguinte maneira
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
onde o comando run
possui os seguintes parâmetros
--name jenkins
- nome do futuro contêiner-d
- inicia o contêiner em segundo plano-it
- sinalizadores para trabalhar com STDIN e tty-v jenkins-data:/var/lib/jenkins
e -v jenkins-home:/home/jenkins
- create (se não for criado) e mapeie arquivos de volume especiais para as seções internas do contêiner que permitirão salvar nosso Jenkins personalizado mesmo após a reconstrução container-p 8080:8080
- mapeie a porta do host para a porta do contêiner para que tenhamos acesso à interface da web (sim, essa é a porta que especificamos no Dockerfile)--restart unless-stopped
- a opção determina a política de execução automática do contêiner após a reinicialização do host (nesse caso, inicie automaticamente se o contêiner não tiver sido desativado manualmente)osipovaleks/docker-jenkins-android
- imagem para implantação.
Na saída para o console do Docker, devemos obter o ID do contêiner criado e também mostrar informações sobre como a imagem é carregada no sistema (é claro, se ainda não estiver carregada), algo como isto
Não foi possível encontrar a imagem 'osipovaleks / docker-jenkins-android: latest' localmente
mais recente: Puxando de osipovaleks / docker-jenkins-android
6cf436f81810: Puxar concluído
987088a85b96: Puxar concluído
b4624b3efe06: Puxar concluído
d42beb8ded59: Puxar concluído
b3896048bb8c: Puxar concluído
8eeace4c3d64: extração concluída
d9b74624442c: Puxar concluído
36bb3b7da419: Puxar concluído
31361bd508cb: tração concluída
cee49ae4c825: puxar concluído
868ddf54d4c1: Puxar concluído
361bd7573dd0: Puxar concluído
bb7b15e36ae8: Puxar concluído
97f19daace79: Puxar concluído
1f5eb3850f3e: Puxar concluído
651e7bbedad2: Puxar concluído
a52705a2ded7: Puxar concluído
Digest: sha256: 321453e2f2142e433817cc9559443387e9f680bb091d6369bbcbc1e0201be1c5
Status: imagem mais recente baixada para osipovaleks / docker-jenkins-android: mais recente
ef9e5512581da66d66103d9f6ea6ccd74e5bdb3776747441ce6a88a98a12b5a4
- A segunda maneira de começar envolve a gravação de um arquivo de composição especial, em que o comando executar é simplesmente descrito usando a linguagem YAML e iniciado usando o Docker Compose.
Para fazer isso, precisamos instalá-lo:
sudo apt update && sudo apt install -y docker-compose
Em seguida, crie um diretório para o projeto (isso é importante se você se importa como os volumes criados automaticamente para o contêiner serão chamados) e vá para ele
mkdir jenkinsProject && cd jenkinsProject
e por dentro criamos o próprio arquivo de composição e entramos no modo de edição
touch docker-compose.yml && nano docker-compose.yml
e coloque o seguinte conteúdo nele
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:
Nela, talvez, apenas a primeira linha levante questões ( version: '3'
) que indica a versão dos recursos do arquivo de composição, bem como uma seção com o bloco de volumes
que lista as usadas neste contêiner
Execute seu contêiner com o comando:
docker-compose up -d
onde o sinalizador -d
também indica que o contêiner será criado e lançado em segundo plano. Como resultado, o Docker deve mostrar algo como o seguinte:
Criando o volume "jenkinsproject_jenkins-data" com o driver padrão
Criando o volume "jenkinsproject_jenkins-home" com o driver padrão
Puxando jenkins (osipovaleks / docker-jenkins-android: mais recente) ...
mais recente: Puxando de osipovaleks / docker-jenkins-android
6cf436f81810: Puxar concluído
987088a85b96: Puxar concluído
b4624b3efe06: Puxar concluído
d42beb8ded59: Puxar concluído
b3896048bb8c: Puxar concluído
8eeace4c3d64: extração concluída
d9b74624442c: Puxar concluído
36bb3b7da419: Puxar concluído
31361bd508cb: tração concluída
cee49ae4c825: puxar concluído
868ddf54d4c1: Puxar concluído
361bd7573dd0: Puxar concluído
bb7b15e36ae8: Puxar concluído
97f19daace79: Puxar concluído
1f5eb3850f3e: Puxar concluído
651e7bbedad2: Puxar concluído
a52705a2ded7: Puxar concluído
Digest: sha256: 321453e2f2142e433817cc9559443387e9f680bb091d6369bbcbc1e0201be1c5
Status: imagem mais recente baixada para osipovaleks / docker-jenkins-android: mais recente
Criando jenkins ...
Criando jenkins ... concluído
Lembre-se, eu disse que o nome dos volumes criados dependerá do nome do projeto? Execute o comando:
docker volume ls
e temos essa saída
NOME DO VOLUME DO CONDUTOR
local jenkinsproject_jenkins-data
local jenkinsproject_jenkins-home
onde veremos que, apesar do nome do volume ter sido escolhido por jenkins-home
, na realidade, um prefixo do nome do projeto grudou nele e o volume do nome acabou sendo jenkinsproject _jenkins-home
Qual opção de inicialização usar? Aqui você pode escolher por si mesmo, acredita-se que o Docker Compose seja mais uma ferramenta para iniciar vários contêineres de uma só vez, vinculados entre si, e se você precisar iniciar apenas um contêiner, poderá usar o
docker run
.
Agora, após estas subpasso para iniciar e configurar o servidor, bem como iniciar o contêiner com Jenkins, podemos prosseguir para sua configuração inicial
Configuração inicial do Jenkins
Pegue o endereço IP do nosso servidor, adicione a porta 8080 indicada por nós e siga este link no navegador.
http://YOUR_IP_ADDRESS:8080/
Se antes disso tudo estava configurado e iniciado corretamente, então aqui veremos a figura a seguir

Para a primeira configuração, precisamos digitar a senha que o sistema gerou durante a instalação. Para fazer isso, basta olhar para o conteúdo do arquivo
/var/lib/jenkins/secrets/initialAdminPassword
. Mas esse arquivo está dentro do contêiner em execução e, para lê-lo, precisamos nos conectar ao contêiner usando o seguinte comando:
docker exec -it jenkins /bin/bash
onde a opção
-it
é semelhante à execução do
docker run
,
jenkins
é o nome do nosso contêiner e
/bin/bash
executará o
/bin/bash
para nós no contêiner e dará acesso a ele. Depois disso, podemos ver a senha inicial para Jenkins:
cat /var/lib/jenkins/secrets/initialAdminPassword
o seguinte aparece no console
91092b18d6ca4492a2759b1903241d2a
Essa é a senha.
O usuário ALexhha sugeriu uma opção mais simples de ler essa senha, sem conectar-se ao próprio contêiner. O fato é que, no momento do lançamento do próprio Jenkins, essa senha é mostrada nos logs. Acontece que tudo o que precisamos é ler os logs do contêiner. No nosso caso, isso é feito com o seguinte comando: docker logs jenkins
onde jenkins
nome do nosso contêiner e, nos logs, você pode ver o seguinte:******************************************************* ***********
******************************************************* ***********
******************************************************* ***********
A configuração inicial do Jenkins é necessária. Um usuário administrador foi criado e uma senha gerada.
Por favor, use a seguinte senha para prosseguir para a instalação:
91092b18d6ca4492a2759b1903241d2a
Isso também pode ser encontrado em: / var / lib / jenkins / secrets / initialAdminPassword
******************************************************* ***********
******************************************************* ***********
******************************************************* ***********
Esta opção é um pouco mais simples e rápida.Copie-o, cole-o no campo
Senha do
administrador na interface da web e clique em
Continuar . Na próxima tela, selecione
Instalar plug -
ins sugeridos e instale um conjunto de plug-ins padrão.


Após instalar os plugins, crie um usuário para nós mesmos e clique em
Salvar e Concluir
Concordamos com a seção Configuração da instância, na qual é solicitado que você preencha o URL no qual o Jenkins funcionará (no nosso caso, deixe tudo como está)

E na próxima tela, clique no botão
Iniciar, usando o querido
Jenkins.
Então, instalamos e lançamos o Jenkins!

Já é possível trabalhar com ele, mas para coletar nossas compilações do Android, você precisará configurar mais alguns pontos. A localização do Jenkins está relacionada ao idioma selecionado do seu navegador e, é claro, a tradução para o russo não está completamente concluída, e temos uma mistura infernal de russo e inglês. Se você conseguiu exatamente da mesma maneira e isso o enfurece, você pode usar o
plug-in especial e definir o idioma da interface padrão. Bem, ou mude seu navegador para a interface em inglês.
Vá para as configurações do Jenkins e selecione
Configuração do sistema.
Verifique as
variáveis de ambiente e insira o nome
ANDROID_HOME no campo e especifique
/ var / lib / android-sdk / no campo (especificamos esses dados no Dockerfile como o diretório inicial do Android SDK).

Clique no botão
Salvar , saia desta seção de configurações e vá para a seção
Configuração Global de Ferramentas .

Configure a partição
JDK (onde a variável JAVA_HOME também foi preenchida por nós no Dockerfile e podemos usar seu valor
/ usr / lib / jvm / java-8-openjdk-amd64 / aqui ).

Também aqui ainda precisamos preencher a seção
Gradle . Selecionamos e instalamos a versão do Gradle usada nos projetos que você construirá usando esse sistema de IC.
Você pode ter várias versões. Você também não pode iniciar a variável Gradle se tiver gradlew no repositório, por exemplo, e puder construí-la com ela.
Com isso, podemos terminar nossa primeira etapa. O sistema Jenkins está totalmente operacional e podemos personalizar a tarefa de compilação. Observe que o sistema foi ajustado às nossas necessidades e aqui pode não fornecer o que você precisa - por exemplo, não há emuladores Android para testes e NDK.Se este artigo interessar a alguém, continuarei na segunda parte com um exemplo de um ou dois aborrecimentos, descreverei a integração de Jenkins e Bitbucket (é ele, não o Github, porque é mais fácil com repositórios particulares gratuitos e artigos na Internet sobre é menor, mas talvez mais divertido), mostrarei como fazer amizade com a chave ssh do repositório do contêiner, sobre notificações por email e vários outros chips. Em geral, sobre tudo o que configuramos.Peço-lhe para não chutar muito, este é o meu primeiro artigo sobre Habr. Bom para todos!