Android开发如何使用Docker为持续集成助力
为什么使用Docker
我为啥要使用到Docker呢?其实也是被动的,因为公司的项目托管在Coding上面,然后Jenkins集成也用的是Coding的,Coding默认提供了Android-29,JDK-8的构建环境,我们的项目之前也是配置的TargetApi=29,所以正好能用;但是最近因为一些不可明说的原因,将gradle升级到了7.4,JDK升级到了11,TargetApi也提到了31,以及一些Google依赖库更新了版本,这样就要求编译环境必须使用JDK 11,所以Coding上提供的默认构建环境就不能使用了。
最后问了下Coding客服,能不能再提供个高版本api的构建环境,得到的答复是自己动手提交合适的Docker镜像。
既然这样,就只能自己构建需要的环境提交到Coding上使用了
认识Docker
如果仅仅是为了给我们Jenkins集成提供特定编译环境的镜像,只需要大概了解下Docker是什么就差不多了,毕竟我们的关注点还是Android开发嘛,要把有限的生命投入到… 呃呃,不是,把有限的精力投入到搬砖事业中。
那Docker是什么呢?可以粗浅理解成它就像个里面装了很多东西的盒子,如果其他人要用,那就直接把这个盒子拿走捣鼓捣鼓就可以用了,而不需要自己再重新吭哧吭哧把需要的东西一个个装到盒子里。
再说点正经的,Docker里有几个概念需要先了解下,理解了这几个概念,就理解了 Docker 的整个生命周期。:
-
镜像(Image)
Docker的镜像概念类似于虚拟机里的镜像(比如.IOS文件),是一个只读的模板,一个独立的文件系统,包括运行容器所需的数据,可以用来创建新的容器。
例如:一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了MySQL或用户需要的其它应用程序。
这里的镜像就如虚拟机创建时候使用的镜像类似。这个镜像便于移动,并且这个镜像我们可以交给任何人使用,其他人使用的时候也很方便,只需要将其实例化即可。 -
容器(Container)
Docker容器是由Docker镜像创建的运行实例,类似VM虚拟机,支持启动,停止,删除等。
每个容器间是相互隔离的,容器中会运行特定的应用,包含特定应用的代码及所需的依赖文件。
容器就类似与虚拟机中我们创建好的虚拟机系统,之后我们所有的操作都是在容器中进行的,我们的程序也是运行在容器中。 -
仓库(Repository)
镜像便于传播,而仓库就是专门用来传播这些镜像的地方,他有点类似与Github,或者你可以把他看成一个存放各种镜像的镜像商店
Docker官方的仓库: 他的服务器处于国外,所以下载速度较慢,不过我们可以通过换源解决。
Daocloud国内仓库: 国内也有一些优秀的商店,他和Docker官方的仓库的区别类似与Github和Gitee的区别
Docker使用流程
了解了是什么(What)之后,就需要知道怎么用了(How),想成功构建Android项目,一般是这么几个步骤:
- 安装Docker Desktop
- 编写dockerfile
- 构建docker镜像
- 运行Docker容器
- 构建Android项目
Docker Desktop
Docker Desktop 是一款适用于 Mac 或 Windows 环境的易于安装的桌面应用程序,使您能够在几分钟内开始编码和容器化。Docker Desktop 包含了从您的机器构建、运行和共享容器化应用程序所需的一切。
Docker Desktop for Mac
Docker 官网下载 Docker Desktop for Mac 可能比较慢,需要的同学可以联系我
成功安装 Docker Desktop 后,打开一个终端,运行 docker --version 来检查机器上安装的 Docker 版本。接下来可以运行如下命令检验下安装结果是否正常
docker run hello-world
hello-world是官方镜像,如果你的终端显示像我这样那就没问题了
mango@mangodeMacBook-Pro ~ % docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
客户端是长这个样子的
我们一般只用关注前面两个就行了,第一个Containers/Apps是当前环境下存在的容器列表,第二个Images是当前环境里的存在的镜像列表。
Dockerfile
大家是不是对这种命名风格有点熟悉?比如c/c++里的makefile,makefile是干嘛的,它是用来自动化编译 C/C++ 项目,内部描述了 C/C++ 工程的编译规则,只需要一个 make 命令,整个工程就开始自动编译,不再需要手动执行 GCC 命令。其实像我们经常接触的CMakeLists.txt文件功能也是类似的,描述编译步骤。
所以Dockerfile的功能也就出来了,就是用来告诉Docker如何构建一个Docker镜像的文件,里面包含了一条条构建镜像所需的指令和说明。
先把我的内容贴上来
FROM centos:latest
RUN yum update -y
RUN yum install -y curl \
&& yum install -y wget \
&& yum install -y zip \
&& yum install -y unzip \
&& yum install -y tar \
&& yum install -y lsof \
&& yum install -y git
WORKDIR /home
RUN yum install -y java-11-openjdk-devel
RUN wget https://services.gradle.org/distributions/gradle-7.4-bin.zip
RUN unzip gradle-7.4-bin.zip
RUN cp -r gradle-7.4 /usr/lib
RUN wget https://dl.google.com/android/repository/commandlinetools-linux-9123335_latest.zip
RUN unzip commandlinetools-linux-9123335_latest.zip
RUN mkdir Android
RUN cp -r cmdline-tools /home/Android/
WORKDIR /home/Android/cmdline-tools
RUN mkdir latest
RUN mv bin/ lib/ NOTICE.txt source.properties -t latest/
WORKDIR /home/Android/cmdline-tools/latest/bin
RUN yes | ./sdkmanager "build-tools;33.0.1" "build-tools;30.0.3" "platforms;android-33" "platform-tools"
接下来对内容做具体说明:
FROM centos:latest
我们构建的镜像一般都是基于已有的镜像,而FROM命令就是表面我们的镜像是基于centos构建的
RUN yum update -y
RUN yum install -y curl \
&& yum install -y wget \
&& yum install -y zip \
&& yum install -y unzip \
&& yum install -y tar \
&& yum install -y lsof \
&& yum install -y git
RUN的作用看名字就知道了,是用来运行后面的命令的,这里的语句是安装一些常用的linux工具
WORKDIR /home
有的时候我们下载工具需要放到指定目录,而WORKDIR的作用就是这个,指定当前的工作目录,如该目录不存在, WORKDIR 会帮你建立目录,接下来的命令都在这个目录执行。
RUN yum install -y java-11-openjdk-devel
这条语句就是用来安装jdk11,因为我的项目是基于AGP 7.X的
RUN wget https://services.gradle.org/distributions/gradle-7.4-bin.zip
RUN unzip gradle-7.4-bin.zip
RUN cp -r gradle-7.4 /usr/lib
这里是下载gradle文件,然后拷贝到指定目录;当然你如果使用gradlew来执行gradle命令,这一步可以省略
RUN wget https://dl.google.com/android/repository/commandlinetools-linux-9123335_latest.zip
RUN unzip commandlinetools-linux-9123335_latest.zip
RUN mkdir Android
RUN cp -r cmdline-tools /home/Android/
WORKDIR /home/Android/cmdline-tools
RUN mkdir latest
RUN mv bin/ lib/ NOTICE.txt source.properties -t latest/
WORKDIR /home/Android/cmdline-tools/latest/bin
RUN yes | ./sdkmanager "build-tools;33.0.1" "build-tools;30.0.3" "platforms;android-33" "platform-tools"
这些语句是下载sdkmanager命令行工具,然后用它来下载Android Sdk
Docker镜像
dockerfile写完了,就可以用它来构建镜像了,这时候需要使用build命令
docker build -t android-build:v1 .
-t是用来指定镜像的name和tag;后面的点号就是根据当前目录的dockerfile来构建镜像,也可以通过-f来指定Dockerfile的完整路径。
构建结束后可以通过docker images命令来查看当前存在的镜像
Docker容器
镜像只是一个只读类型的文件,而我们的环境不可能只是一个这样的文件,所以我们需要把这个镜像加载成我们的环境,也就是让他变成容器。而创建容器就需要使用到run命令:
docker run [可选参数] 镜像名 [向启动容器中传入的命令]
我这里使用到的完整命令比较简单:
docker run -it --name box -v /Users/mango/Docker/project:/home/project android-build:v1 /bin/bash
- –name是指定容器名称。
- -v表示目录映射关系,这里是将宿主机的/Users/mango/Docker/project和容器的/home/project建立映射关系,后面就不需要在容器里下载项目等东西了。
- 追加/bin/bash,这样在创建容器后就可以进入容器shell命令界面,方便进入后续操作。
容器创建后可以使用docker ps命令来查看当前存在的容器
构建Android项目
运行项目之前需要在容器终端配置下JDk的环境变量
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-11.0.13.0.8-4.el8_5.x86_64
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
然后再 配置下SDK的环境变量
export ANDROID_HOME=/home/Android
export PATH=$ANDROID_HOME/platform-tools:$ANDROID_HOME/cmdline-tools/latest/bin:$PATH
还记得我刚才运行容器做的目录映射吗
/Users/mango/Docker/project:/home/project
那么我只需要在自己电脑的/Users/mango/Docker/project目录上把工程下载好,就可以在容器的/home/project目录看到了,最后就可以通过assembleRelease来进行打包看看环境是否安装成功了
所有准备操作一切就绪,接下来就可以把镜像文件推送到Coding的Docker仓库了,当然了,大家也可以推送到Docker的官方仓库Docker Hub