Jenkins for Android使用Docker构建

大家好!

我是一名Android开发人员,不久前,我们在项目中遇到了一些想要自动化的例行任务。 例如,我们有5种不同的口味,对于每种口味,我们都需要将我们的作品上载到织物上,有时每天需要多次使用不同的购物车。 是的,也可以使用gradle任务完成此任务,但是我不想在开发人员的计算机上启动此过程,而是以某种方式集中进行。 或者,例如,将Google Play中的版本自动上传到Beta。 好吧,我只是想选择CI系统。 这篇文章的结果是什么,以及我们如何设置它,为什么还有Docker。



据我了解,整个任务大致分为两个阶段:

  1. 使用Android SDK安装和配置Jenkins本身
  2. 设置詹金斯内部已经存在的任务

在本文中,我想谈谈第一点,如果对任何人都感兴趣,那么在下一篇文章中,我将描述在Jenkins本身中设置组装任务的过程。

因此,第一点是Jenkins系统的安装和配置


哈布雷(Habré)在该主题上已经有一篇精彩的文章 ,但是她已经有几年了,其中的一些内容已经有些过时了(例如sdkmanager),尽管她在最初阶段帮了我很多忙,弄清楚了怎么做和如何做。

如果您查看安装Jenkins的官方文档 ,我们将看到三种不同的方法来执行此操作:启动现成的Docker映像,下载并运行war文件,以及仅以旧方式在系统中安装jenkins(例如,使用ubuntu作为示例来apt-get install jenkins )。 第一个选项是最正确的,因为它不对我们的主机系统进行任何不必要的设置和依赖,并且即使在出现问题的任何时候,删除所有内容并重新启动都很容易。 但是jenkins的标准docker映像包含一些我们不需要的数据(例如,blueocean插件),也不包含我们绝对需要的数据(例如,android sdk)。 决定创建自己的docker映像,在其中下载并运行war文件,下载并安装android sdk,以及配置我们需要的所有其他设置。 为了稍后启动,我们需要安装了docker的主机系统。 我建议在这里不要重蹈覆辙,而是使用DigitalOcean。

创建和配置虚拟机


首先,如果其他人未在此处注册,则建议注册 (在撰写本文时,这里有引荐链接,但在阅读规则后我将其抛弃了)。 注册后,您可以在互联网上搜索一个或另一个促销代码,并获得约10美元的启动费。

之后,我们需要获得新的液滴。 选择项目Droplets,然后选择创建Droplet

图片

主机系统是Ubuntu 18.04。 您可以选择已安装并配置了Docker的映像,但是我们将自行完成所有操作。 由于android构建的组装仍然需要大量资源,因此我们需要选择至少20美元的配置,以便正常且相对较快地收集构建。

图片

我们将选择更靠近的位置(例如,在德国)。 然后,有两种方法可以连接到虚拟服务器。 我们可以添加ssh密钥,也可以不使用它。 如果在此位置我们未指明要使用哪个密钥,那么root用户的密码将发送到我们的邮件中。

图片

在这里,我们可以更改服务器名称,并单击“ 创建”按钮完成创建

图片

现在,我们进入创建的Droplet,并复制自己的IP地址,以进行进一步的连接和配置。

图片

我们需要一个ssh客户。 如果您在罂粟下工作,则可以使用标准终端,如果在Windows下工作 ,则可以使用腻子工作或使用Linux子系统 (仅适用于Windows 10)。 我个人使用后一种选择,它完全适合我。

使用以下命令连接到我们的服务器

 ssh root@YOUR_IP_ADDRESS 

控制台将为您提供保存密钥,我们对此表示同意。 连接后,我们将为自己创建一个新用户,将其添加到超级用户中(让他有机会使用不带密码的sudo),将其复制通过ssh访问的密钥并说他是这些文件的所有者(否则它将不起作用)。 用户名已更改为方便您使用的名称。

 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 

使用命令从根断开连接

 exit 

我们将在创建的新用户的帮助下重新连接

 ssh username@YOUR_IP_ADDRESS 

在更新系统并重新启动服务器之后(如果在更新过程中系统会询问您一些信息,在这种情况下始终选择默认值就足够了)。

 sudo apt update && sudo apt full-upgrade -y && sudo apt autoremove -y && sudo reboot 

基本设置完成。 从作战系统的角度来看,它不是很安全,但是在本文的框架内,它是完全合适的。

安装Docker


要将Docker安装到我们的系统中,我们将使用官方文档 。 因为我们有一个新安装的系统,所以我们将跳过这一点,如果您的系统已经运行了很长一段时间,则根据Docker团队的建议,删除可能的旧版本

 sudo apt-get remove docker docker-engine docker.io containerd runc 

不要忘记先通过ssh连接回我们的服务器。 文档中对Docker本身的安装进行了详细描述,我将提供常规命令来简化安装过程。 他们所做的可以在这里阅读。 首先添加存储库。

 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" 

然后安装Docker本身:

 sudo apt update && sudo apt install -y docker-ce docker-ce-cli containerd.io 

因此,将来我们可以调用不带sudo前缀的docker命令,执行以下命令(说明中也对此进行了详细介绍)。

 sudo usermod -aG docker username 

之后,您需要重新登录(使用exit命令并重新连接到服务器),以使其正常工作。

Docker本身已安装,我们可以使用以下命令进行检查

 docker run hello-world 

她下载测试图像,然后在容器中运行它。 启动后,该容器将打印参考消息并退出。

恭喜,我们已经完成服务器准备工作的阶段!

创建您的Docker映像


我们将通过编写我们自己的Dockerfile来创建Docker映像。 如何在互联网,旅行车和小型手推车上正确执行此操作的示例,我将显示完成的版本,并尝试对它进行尽可能多的评论。 docker本身还有一本使用手册 ,其中包含有关dockerfile的正确和规范拼写的示例。

创建并打开您的Dockerfile进行编辑

 touch Dockerfile && nano Dockerfile 

例如,在其中,我们将放置Dockerfile的内容

我整个带有评论的dockerfile
 #    . FROM ubuntu:18.04 #      LABEL author="osipovaleks" LABEL maintainer="osipov.aleks.kr@gmail.com" LABEL version="1.0" LABEL description="Docker image for Jenkins with Android SDK" #  ,  Jenkins    ENV TZ=Europe/Kiev RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # i386    ia32-libs RUN dpkg --add-architecture i386 #      RUN apt-get update && apt-get install -y git \ wget \ unzip \ sudo \ tzdata \ locales\ openjdk-8-jdk \ libncurses5:i386 \ libstdc++6:i386 \ zlib1g:i386 #  ,       RUN apt-get clean && rm -rf /var/lib/apt/lists /var/cache/apt #  RUN locale-gen en_US.UTF-8 ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 #   Android Sdk     ARG android_home_dir=/var/lib/android-sdk/ ARG sdk_tools_zip_file=sdk-tools-linux-4333796.zip RUN mkdir $android_home_dir RUN wget https://dl.google.com/android/repository/$sdk_tools_zip_file -P $android_home_dir -nv RUN unzip $android_home_dir$sdk_tools_zip_file -d $android_home_dir RUN rm $android_home_dir$sdk_tools_zip_file && chmod 777 -R $android_home_dir # environment    ENV ANDROID_HOME=$android_home_dir ENV PATH="${PATH}:$android_home_dir/tools/bin:$android_home_dir/platform-tools" ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/ #   Android SDK RUN yes | sdkmanager --licenses #    Jenkins ENV JENKINS_HOME=/var/lib/jenkins RUN mkdir $JENKINS_HOME && chmod 777 $JENKINS_HOME #     jenkins,   ,         RUN useradd -m jenkins && echo 'jenkins ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers USER jenkins WORKDIR /home/jenkins #   war     Jenkins RUN wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war -nv CMD java -jar jenkins.war #      EXPOSE 8080/tcp 


一些澄清:

  • 最初,人们希望使用较轻的Alpine代替ubuntu,但它不具有ia32-libs支持,这是使用Android SDK构建项目所必需的。
  • 我们安装openjdk-8-jdk而不是安装更轻巧的openjdk-8-jdk-headless,因为某些Jenkins功能需要一个完整的系统(例如,显示单元测试结果)。
  • 由于某些项目没有它们,gradle程序集崩溃而没有明确的错误和日志,因此有必要安装语言环境,而我花了几天时间才探究这个原因(在不在docker中的常规ubuntu上,默认情况下所有语言环境都被填充) 。
  • 我们需要立即接受Android SDK的所有许可,以便在构建过程中Jenkins可以独立安装其所需的组件(例如,不同版本的api所需的SDK)。 如有必要,稍后可以在docker容器内部使用sdkmanager管理SDK,例如sdkmanager --list允许sdkmanager --list查看所有可用的和所有已安装的组件,而sdkmanager --install "platforms;android-26" api版本26安装SDK。
  • 通常,可能不启动用户詹金斯,而是与root用户在一起,但是由于某种原因,这不太正确,您也无法授予他超级用户权限,但是这样做是出于方便的考虑,如果需要安装某些东西在设置和调试阶段。
  • 图像的基本大小非常大(将近800 mb),但总的来说,我得出的结论是,这对我来说不是很关键,并且以这种形式下载图像比花时间搜索和删除不需要的软件包更容易。

编写Dockerfile之后,我们需要根据要创建的容器将其转换为Docker的现成映像。 这是简单地由团队完成的

 docker build -t jenkins-image 

其中-t jenkins-image参数负责-t jenkins-image的名称,命令末尾的点表示您需要在此目录中查找程序集的Dockerfile。 组装过程本身会花费一些时间,并且组装后控制台中应该有类似的内容。
成功构建9fd8f5545c27
成功标记詹金斯图像:最新
这说明我们的形象已经成功组合,我们可以继续下一步,即启动容器

Docker Hub和现成的映像


是的,当然,我们可以使用现成的映像来启动容器,但是如果我们需要在多个设备上执行此操作,则每次创建一个Dockerfile并从中构建现成的映像将不是很方便。 而且,如果我们还更新了Dockerfile的内容,那么在所有节点上展开更改将根本不方便。 为此,有一个公共的Docker Hub映像存储库。 它使您不必每次都在每个节点上收集映像,而只是从公共存储库中将其下载到您自己,并在所有计算机上均等地使用它。 例如,在名为osipovaleks / docker-jenkins-android的存储库中提供了作为本文示例的图像,在本文的后面,我们将使用它。

本文并不意味着对Docker Hub进行了详细的研究,我们将不了解如何在其中上传映像(尽管这不是很困难)以及在那里可以做什么,我们也将不了解仍然可能存在您自己的私有公共或私有存储库,如有必要,所有这些都可以独立进行分类。

集装箱下水


有两种启动容器的方法。

  1. 第一种方法,只需使用docker run ,即可通过以下方式轻松快速地执行此操作

     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 

    其中run命令具有以下参数

    • --name jenkins未来容器的名称
    • -d在后台启动容器
    • -it用于STDIN和tty的标志
    • -v jenkins-data:/var/lib/jenkins-v jenkins-home:/home/jenkins创建(如果未创建)并将特殊的卷文件映射到容器的内部部分,这将使我们即使在重建后也可以保存自定义的Jenkins货柜
    • -p 8080:8080将主机端口映射到容器端口,以便我们可以访问Web界面(是的,这是我们在Dockerfile中指定的端口)
    • --restart unless-stopped该选项确定重新引导主机后的容器自动运行策略(在这种情况下,如果未手动关闭容器,则自动启动)
    • osipovaleks/docker-jenkins-android用于部署的映像。

    在Docker控制台的出口处,我们应该获取已创建容器的ID,并显示有关如何将映像加载到系统中的信息(当然,如果尚未加载),类似这样
    无法在本地找到图像'osipovaleks / docker-jenkins-android:Latest'
    最新:从osipovaleks / docker-jenkins-android中拉出
    6cf436f81810:拉出完成
    987088a85b96:拉出完成
    b4624b3efe06:拉出完成
    d42beb8ded59:拉动完成
    b3896048bb8c:拉完整
    8eeace4c3d64:拉完整
    d9b74624442c:拉完整
    36bb3b7da419:拉动完成
    31361bd508cb:拉出完成
    cee49ae4c825:拉完成
    868ddf54d4c1:拉出完成
    361bd7573dd0:拉出完成
    bb7b15e36ae8:拉动完成
    97f19daace79:拉完整
    1f5eb3850f3e:拉动完成
    651e7bbedad2:拉出完成
    a52705a2ded7:拉出完成
    摘要:sha256:321453e2f2142e433817cc9559443387e9f680bb091d6369bbcbc1e0201be1c5
    状态:为osipovaleks / docker-jenkins-android下载的较新映像:最新
    ef9e5512581da66d66103d9f6ea6ccd74e5bdb3776747441ce6a88a98a12b5a4
  2. 第二种启动方式包括编写一个特殊的compose文件,其中运行命令仅使用YAML语言简单描述,并使用Docker Compose启动。

    为此,我们需要安装它:

     sudo apt update && sudo apt install -y docker-compose 

    接下来,为项目创建一个目录(如果您关心将为容器自动创建的卷将被调用的内容,这将非常重要)并转到该目录

     mkdir jenkinsProject && cd jenkinsProject 

    在内部,我们自己创建撰写文件并进入编辑模式

     touch docker-compose.yml && nano docker-compose.yml 

    并放入以下内容

     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: 

    在其中,也许只有第一行引发问题( version: '3' ),该问题指示撰写文件功能的版本 ,以及带有volumes块的部分,列出了此容器中使用的文件

    使用以下命令运行容器:

     docker-compose up -d 

    -d标志还指示该容器将在后台创建并启动。 结果,Docker应该显示如下内容:
    使用默认驱动程序创建卷“ jenkinsproject_jenkins-data”
    使用默认驱动程序创建卷“ jenkinsproject_jenkins-home”
    拉詹金斯(osipovaleks / docker-jenkins-android:最新)...
    最新:从osipovaleks / docker-jenkins-android中拉出
    6cf436f81810:拉出完成
    987088a85b96:拉出完成
    b4624b3efe06:拉出完成
    d42beb8ded59:拉动完成
    b3896048bb8c:拉完整
    8eeace4c3d64:拉完整
    d9b74624442c:拉完整
    36bb3b7da419:拉动完成
    31361bd508cb:拉出完成
    cee49ae4c825:拉完成
    868ddf54d4c1:拉出完成
    361bd7573dd0:拉出完成
    bb7b15e36ae8:拉动完成
    97f19daace79:拉完整
    1f5eb3850f3e:拉动完成
    651e7bbedad2:拉出完成
    a52705a2ded7:拉出完成
    摘要:sha256:321453e2f2142e433817cc9559443387e9f680bb091d6369bbcbc1e0201be1c5
    状态:为osipovaleks / docker-jenkins-android下载的较新映像:最新
    创建詹金斯...
    创建詹金斯...完成
    记住,我说过创建的卷的名称取决于项目的名称吗? 运行命令:

     docker volume ls 

    我们得到这样的输出
    驾驶员卷名
    本地jenkinsproject_jenkins数据
    本地jenkinsproject_jenkins-home
    jenkins-home我们可以看到,尽管实际上volume的名称是由jenkins-home选择的, jenkins-home实际上,项目名称的前缀jenkinsproject _jenkins-home在其中,而volume的名称却是jenkinsproject _jenkins-home


使用哪个启动选项? 在这里,您可以自己选择,相信Docker Compose可以是一次启动相互关联的多个容器的工具,如果只需要运行一个容器,则可以使用docker run

现在,在完成了用于启动和配置服务器以及使用Jenkins启动容器的这些子步骤之后,我们可以继续进行其初始配置。

Jenkins的初始设置


取得我们服务器的IP地址,将我们指示的端口8080添加到它,然后在浏览器中单击此链接。

http://YOUR_IP_ADDRESS:8080/

如果在此之前一切均已配置并正确启动,那么在这里我们将看到以下图片



对于第一次设置,我们需要输入系统在安装过程中生成的密码。 为此,我们只需要查看文件/var/lib/jenkins/secrets/initialAdminPassword 。 但是这个文件在我们正在运行的容器中,为了读取它,我们需要使用以下命令连接到容器:

 docker exec -it jenkins /bin/bash 

其中jenkins选项类似于运行jenkins docker runjenkins是我们的容器的名称, /bin/bash将在容器中为我们运行/bin/bash并为其提供访问权限。 之后,我们可以看到詹金斯的初始密码:

 cat /var/lib/jenkins/secrets/initialAdminPassword 

控制台中显示以下内容
91092b18d6ca4492a2759b1903241d2a
这是密码。

用户ALexhha建议使用一个更简单的选项来读取此密码,而无需连接到容器本身。 事实是,在启动Jenkins本身时,此密码显示在日志中。 事实证明,我们所需要做的只是读取容器日志。 在我们的例子中,这是通过以下命令完成的:

 docker logs jenkins 


其中 jenkins 我们容器 jenkins 名称,在日志中,您可以看到以下内容:

********************************************************** ***********
********************************************************** ***********
********************************************************** ***********

Jenkins的初始设置是必需的。 已创建管理员用户,并已生成密码。
请使用以下密码继续安装:

91092b18d6ca4492a2759b1903241d2a

这也可以在以下位置找到:/ var / lib / jenkins / secrets / initialAdminPassword

********************************************************** ***********
********************************************************** ***********

******************************************************** ***********

此选项更简单,更快捷。

复制它,将其粘贴到Web界面的Administrator password字段中,然后单击Continue 。 在下一个屏幕上,选择“ 安装建议的插件”并安装一组默认插件。





安装插件后,为自己创建一个用户,然后单击“ 保存并完成”



我们同意“实例配置”部分,在该部分中,我们要求填写Jenkins可以使用的URL(在我们的情况下,请保留所有内容)



然后在下一个屏幕上,单击珍贵的“ 开始使用Jenkins”



因此,我们安装并启动了Jenkins!



已经可以使用它了,但是为了收集我们的Android版本,您需要再配置一些点。 Jenkins的本地化与您的浏览器选择的语言有关,当然,俄语翻译还没有完全完成,我们得到了俄文和英文的混合。 如果您以完全相同的方式获得成功,并且激怒了您,则可以使用特殊的插件并设置默认界面语言。 好吧,或者将浏览器切换到英文界面。

转到Jenkins设置,然后选择系统配置。



我们在环境变量上打勾,并在字段中输入名称ANDROID_HOME ,并在字段中指定/ var / lib / android-sdk / (我们在Dockerfile中将此数据指定为Android SDK的主目录)。



单击“ 保存”按钮,退出此设置部分,然后转到“ 全局工具配置 ”部分。



设置JDK分区(我们也在Dockerfile中填充了JAVA_HOME变量,我们可以使用其值/ usr / lib / jvm / java-8-openjdk-amd64 / here )。



同样在这里,我们仍然需要填写Gradle部分。 我们选择并安装在您将使用此CI系统构建的那些项目中使用的Gradle版本。您可以有多个版本。例如,如果存储库中有gradlew,则也根本无法启动Gradle变量,并且可以使用它来构建它。



这样,我们可以结束我们的第一阶段。 Jenkins系统已全面运行,我们可以继续自行定制构建任务。请注意,系统已根据我们的需求进行了调整,此处可能无法满足您的需求-例如,没有用于测试和NDK的android模拟器。

如果本文感兴趣,那么我将在第二部分继续介绍一个或两个麻烦的示例,我将描述Jenkins和Bitbucket的集成(是他,而不是Github,因为使用免费的私有存储库和Internet上的文章更容易些)它虽然更小,但也许会更有趣),我将告诉您如何使用存储库中容器的ssh键,如何发送电子邮件通知以及其他几种芯片来结交朋友。通常,关于我们已配置的所有内容。

我要求你不要踢太多,这是我关于哈勃尔的第一篇文章。对所有人都好!

Source: https://habr.com/ru/post/zh-CN443606/


All Articles