docker镜像制作并上传

一、 Linux 版从 dockerfile 制作 Docker 镜像

制作linux版的docker镜像需要一些准备工作,然后编写对应的dockerfile, 执行dockerfile 、推送镜像到服务端

1. 准备工作

1.1 准备好可访问外网的虚拟机,并安docker等软件

1
2
3
4
5
6
7
8
# 安装
yum install -y docker
yum install -y git
# 启动
systemctl start docker.service
# 显示docker 版本
docker --version
// Docker version 19.03.12, build dd074a9

1.2 登录docker

1
2
3
docker login docker-registry.qqqqq.virtual
<username>: xxxxx
<passwd>: xxxxx

1.3 拉取依赖的基础镜像

1
docker pull docker-registry.qqqqq.virtual/library/centos7:7-iqqqqq-13

1.4. 部署andriod编译依赖的gradle工具

通过 https://gradle.org/releases/ 下载4.10.1版二进制包

1
2
3
4
5
6
7
# 获取二进制包
wget https://services.gradle.org/distributions/gradle-4.10.1-bin.zip
# 解压
unzip gradle-4.10.1-bin.zip
mkdir -p /opt/soft/android/gradle
# 将gradle拷贝到指定路径下
mv gradle-4.10.1 /opt/soft/android/gradle

1.5. 部署 andriod 编译依赖的NDK工具

NDK的安装是通过 sdkmanager 来安装的,而 sdkmanager 包含在 commandlinetools 包中的,Android Studio 包含了commandlinetools工具,因为不需要图形化界面所以在Command line tools only标题下只下载linux版的 commandlinetools 就好了,不用下载完整的Android Studio

https://developer.android.com/studio#downloads

1.5.1 部署 commandlinetools 及其依赖

1
2
3
4
5
6
7
# sdkmanager 依赖java开发包,所以先安装java开发包
yum install java-1.8.0-openjdk-devel.x86_64 -y
# 解压
unzip commandlinetools-linux-7583922_latest.zip
mkdir -p /opt/soft/android/sdk/cmdline-tools/
# 必须为latest目录,否则执行sdkmanager会报错,要求设置
mv cmdline-tools/ /opt/soft/android/sdk/cmdline-tools/latest

1.5.2 设置环境变量

因为 sdkmanager 的执行依赖部分环境变量,所以需要提前设置
vim ~/.bash_profile 添加以下内容:

1
2
3
4
export ANDROID_SDK_ROOT=/opt/soft/android/sdk
export ANDROID_HOME=${ANDROID_SDK_ROOT}
export GRADLE_HOME=/opt/soft/android/gradle/gradle-4\.10\.1
PATH=$PATH:$HOME/bin:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$GRADLE_HOME/bin

官方文档中说不设置ANDROID_HOME也可以,为了减少不必要的麻烦,设置上也没问题

执行以下命令使环境变量生效

1
source ~/.bash_profile

1.5.3 验证commandlinetools 部署

1
2
3
cd /opt/soft/android/sdk/cmdline-tools/latest/bin
# 成功显示版本号说明 commandlinetools
./sdkmanager --version

1.5.4 通过 sdkmanager 安装指定版本的NDK

sdkmanager的应用参考《官方文档
常规用法如下:

1
2
3
4
5
6
# 显示可通过sdkmanager安装的软件包或已经安装的软件包,其中--channel后的数值 0 (stable), 1 (beta), 2 (dev), or 3 (canary)
./sdkmanager --list --channel=0
# CMake 或 NDK,请使用以下语法:
sdkmanager --install
["ndk;major.minor.build[suffix]" | "cmake;major.minor.micro.build"]
[--channel=channel_id] // NDK channels: 0 (stable), 1 (beta), or 3 (canary)

执行以下命令安装需要的ndk20版

1
2
3
4
# 安装ndk20.1.5948944版
./sdkmanager --install "ndk;20.1.5948944" --channel=0
# 下一步将显示软件许可协议,输入 y 即可,然后等待下载完毕
# 下载完毕后将会在/opt/soft/android/sdk下自动创建licenses、ndk、patcher 等目录

执行以下命令安装需要的cmake3.10.2版

1
2
# 执行完毕后将在/opt/soft/android/sdk下自动创建cmake目录
./sdkmanager --install "cmake;3.10.2.4988404" --channel=0

1.6. 通过 gradle 编译mydns

此步骤目的主要是执行gradle 编译指令,由gradle自动获取编译mydns时需要的各种依赖工具,相关的依赖工具内容会存储在当前用户根目录的.gradle目录下,后面需要把这些依赖工具打到制作的docker镜像中

1.6.1 拉取 mydns 代码

此内容只适合与首次获取代码

1
2
3
git clone ssh://git@gitlab.qqqqq.domain:10022/edge-cloud/mydns.git 
cd mydns
git submodule update --init --recursive

1.6.2 通过 gradle 编译mydns及其依赖的子项目

1.6.2.1替换gradle编译时依赖的sdk.dir和ndk.dir目录
1
2
3
echo -e "sdk.dir=${ANDROID_SDK_ROOT}\nndk.dir=${ANDROID_SDK_ROOT}/ndk/20.1.5948944" > ./third-party/acl/android/acl_c++_shared/local.properties
echo -e "sdk.dir=${ANDROID_SDK_ROOT}\nndk.dir=${ANDROID_SDK_ROOT}/ndk/20.1.5948944" > ./third-party/mbedtls-2.7.12/android/mbedtls_c++shared/local.properties
echo -e "sdk.dir=${ANDROID_SDK_ROOT}\nndk.dir=${ANDROID_SDK_ROOT}/ndk/20.1.5948944" > src/android/dns_c++shared/local.properties
1.6.2.2 使用gradle 编译 acl
1
2
3
4
5
cd ./third-party/acl/android/acl_c++_shared/
# 执行gradle编译
gradle build
# 执行完毕后回到mydns根目录
cd -
1.6.2.3 使用gradle 编译 mbedtls
1
2
3
4
5
cd third-party/mbedtls-2.7.12/android/mbedtls_c++shared/
# 执行gradle编译
gradle build
# 执行完毕后回到mydns根目录
cd -
1.6.2.4 使用gradle 编译 libdns
1
2
3
4
5
cd src/android/dns_c++shared/libdns/
# 执行gradle编译
gradle build
# 执行完毕后回到mydns根目录
cd -
1.6.2.5 使用gradle 编译 libqnet
1
2
3
4
5
cd src/android/dns_c++shared/libqnet
# 执行gradle编译
gradle build
# 执行完毕后回到mydns根目录
cd -
1.6.2.6 使用gradle 编译 mydns
1
2
3
4
5
cd src/android/dns_c++shared/mydns
# 执行gradle编译
gradle build
# 执行完毕后回到mydns根目录
cd -

1.7 拷贝gradle缓存目录到docker 镜像制作目录

因为计划将dockerfile中的COPY命令的context设置在/opt/soft/android目录下,便于生成镜像时拷贝相关目录文件

1
cp -r ~/.gradle /opt/soft/android

1.8 异常及解决方法

  • 编译 libdns 时
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    > Task :libdns:lint FAILED

    FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ':libdns:lint'.
    > Could not resolve all artifacts for configuration ':libdns:debugAndroidTestRuntimeClasspath'.
    > Could not download hamcrest-core.jar (org.hamcrest:hamcrest-core:1.3)
    > Could not get resource 'https://jcenter.bintray.com/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar'.
    > Could not HEAD 'https://jcenter.bintray.com/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar'.
    > Read timed out

    解决方法
    1
    2
    3
    方法1 通过再次执行gradle build  有可能会下载成功
    方法2 修改当前目录下的build.gradle 文件,使用阿里镜像 未验证此方法
    参考 《[如何用gradle配置国内阿里云镜像源](https://blog.csdn.net/yizhuanlu9607/article/details/96971042)》

2 编写 dockerfile

vim /opt/soft/android/dockerfile 文件中的内容如下:

1
2
3
4
5
6
7
8
9
10
11
FROM docker-registry.qqqqq.virtual/library/centos7:7-iqqqqq-13

RUN yum install -y java-1.8.0-openjdk-devel.x86_64 which git zip unzip

COPY ./gradle /opt/soft/android/gradle
COPY ./sdk /opt/soft/android/sdk
COPY /.gradle /root/.gradle
ENV ANDROID_SDK_ROOT=/opt/soft/android/sdk
ENV ANDROID_HOME=$ANDROID_SDK_ROOT
ENV GRADLE_HOME=/opt/soft/android/gradle/gradle-4\.10\.1
ENV PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$GRADLE_HOME/bin:$ANDROID_SDK_ROOT/ndk/20\.1\.5948944/toolchains/aarch64-linux-android-4\.9/prebuilt/linux-x86_64/bin:$ANDROID_SDK_ROOT/ndk/20\.1\.5948944/toolchains/arm-linux-androideabi-4\.9/prebuilt/linux-x86_64/bin:$ANDROID_SDK_ROOT/ndk/20\.1\.5948944/toolchains/x86-4\.9/prebuilt/linux-x86_64/bin

3 根据 dockerfile 创建镜像

  • 创建本地镜像
1
2
3
4
5
cd /opt/soft/android/
# 创建镜像,最后的.不能少
docker build -t mydns_linux_base:1.0 .
# 查看创建的镜像 mydns_linux_base 版本为1.0
docker images
  • 根据新的本地镜像创建一个容器,并验证环境变量和目录的正确性
    1
    docker run --name test_mydns -it -v `pwd`:/root/workspace --privileged=true mydns_linux_base:1.0 /bin/bash

4 将创建的镜像推送到远端仓库中

4.1 创建标签并推送到远端仓库中

1
2
3
4
5
6
7
# 查看新创建的mydns_linux_base本地镜像的id
docker images --filter=reference='mydns_linux_base:*'
# 必须创建新的标签,才能push 到远端。
# 如要推送的路径是docker-registry.qqqqq.virtual/edge-cloud/mydns_linux_base 的1.0版,则需要先创建以下标签
docker tag f234786cc5f9 docker-registry.qqqqq.virtual/edge-cloud/mydns_linux_base:1.0
# 推送到仓库 docker-registry.qqqqq.virtual/edge-cloud/mydns_linux_base 下 标签为1.0
docker push docker-registry.qqqqq.virtual/edge-cloud/mydns_linux_base:1.0

4.2 推送镜像查看

打开 以下网址查看是否有新推的 mydns_linux_base 镜像
http://qae.cloud.qqqqq.domain/registry/namespaces/?filter_text=undefined:edge-cloud

4.3 本地清理及使用获取远端仓库镜像

推送成功后可以将本地的 mydns_linux_base 进行删除

1
2
3
4
5
6
7
# 此时本地的 mydns_linux_base和docker-registry.qqqqq.virtual/edge-cloud/mydns_linux_base的id都是 f234786cc5f9
# 无法通过 以下命令直接删除
docker rmi f234786cc5f9
# 应该先删除docker tag改名前的镜像,使用镜像名称删除,(一般在docker tag镜像改名后,最好删除改名前的镜像
docker rmi docker-registry.qqqqq.virtual/edge-cloud/mydns_linux_base:1.0
# 再执行删除 mydns_linux_base
docker rmi mydns_linux_base:1.0

4.4 异常及解决方法

  • push时权限错误
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    The push refers to repository [docker-registry.qqqqq.virtual/edge-cloud/mydns_linux_base]
    1885a8d3b104: Preparing
    7e0dbba8fe17: Preparing
    6bb0d2c98d31: Preparing
    fd846adc3060: Preparing
    41c37881aa1c: Preparing
    edfc6fdcb211: Preparing
    ddd02f1907f4: Preparing
    a51dabe2037e: Preparing
    129b697f70e9: Preparing
    error parsing HTTP 403 response body: invalid character 'T' looking for beginning of value: "The supplied authentication is not authorized to access this resource"
    解决方法
    1
    2
    3
    4
    5
    6
    # 退出docker 当前登录用户,使用有权限的账号进行登录
    docker logout docker-registry.qqqqq.virtual
    # 从新登陆
    docker login docker-registry.qqqqq.virtual

    参考http://docker.gitlab.qqqqq.domain/readme/sample.html

    二、 Linux 版从 container 制作 Docker 镜像

    使用以下命令可以从特定的container直接制作新的镜像

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

如: docker commit mycontainer myimage:v1.0

三、Windows 版编译服务器设置

3.1 安装必要的依赖软件

  1. 安装vs2019、git、curl、7-Zip 到默认的c盘路径下

  2. 配置环境变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    INCLUDE变量内容
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\winrt
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include

    LIB变量内容
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\lib\x86
    C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\ucrt\x86
    C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x86

    PATH变量内容
    C:\Users\cloudbase-init\curl\curl-7.76.1-win64-mingw\bin
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\bin\Hostx86\x86
    C:\Program Files\Git\cmd
    C:\Program Files\7-Zip
  3. 生成本机的sshkey
    因为在部署git的时候已经默认安装了ssh-keygen工具,所以直接在命令窗口执行ssh-keygen工具生成本机的ssh秘钥即可

  4. 在mydns项目中添加本机的sshkey
    将上一步生成的公钥添加到 mydns/settings/repository 下的 Deploy Keys 中即可