1 打造最小docker基础镜像
1.1 使用alpine-glib作为基础镜像
Alpine
操作系统是一个面向安全的轻型Linux
发行版。采用了 musl libc 和 busybox 以减小系统的体积和运行时资源消耗,但功能上比 busybox 又完善的多,因此得到开源社区越来越多的青睐,相比于其他Docker
镜像,它的容量非常小,仅仅只有5 MB
左右
但是由于Alpine
是基于MUSL libc(mini libc)
而我们日常使用的很多环境都需要GUN Standard C library(glibc)
所以我们选择带有glib
的Alpine
镜像:docker.io/jeanblanchard/alpine-glibc
(12M)
docker.io/jeanblanchard/alpine-glibc
1.2 优化你的alpine-glibc
alpine-glibc
虽然解决了Alpine
没有glib
的问题,但是还是有许多坑等着我们踩的!
如果你没看过这篇文章,你怕是要吃苦啦,要反反复复的打基础包,然后打语言包,然后打应用包..
在这里我要优化我们的alpine-glibc
镜像,来解决一些后面可能会踩到的坑
- 编码问题(解决乱码问题)
- 时区问题(默认可是UTC+0)
- apk镜像源问题(安装加速)
- bash问题(默认只有
sh
,没有bash
,有些软件是要用bash
的,比如conda
)
FROM docker.io/jeanblanchard/alpine-glibc
MAINTAINER Naah
# 修改编码为utf-8
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
# 增加镜像源
RUN echo "https://mirror.tuna.tsinghua.edu.cn/alpine/v3.9/main/" > /etc/apk/repositories
# 修改时区为上海时区
RUN apk add tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone \
&& apk del tzdata
# 安装bash
RUN apk update \
&& apk upgrade \
&& apk add --no-cache bash \
&& rm -rf /var/cache/apk/*
2 优化你的Dockerfile
要想优化我们的Dockerfile
,首先我们要知道Docker
的镜像原理是什么样的!
Unable to find image 'jeanblanchard/alpine-glibc:latest' locally
latest: Pulling from jeanblanchard/alpine-glibc
921b31ab772b: Pull complete
a8498d4f0312: Pull complete
Digest: sha256:d42d763ab3db4eb2164b0beccab0860bcb4cd087fe7c3b0ed5eca464e3efbf67
Status: Downloaded newer image for jeanblanchard/alpine-glibc:latest
通过上面的docker pull
日志,我们发现有很多次的 Pull complete
,这是为啥呢?
2.1 docker 镜像基础
docker 镜像就是一个多层存储的文件,docker使用sha256
来确定是否需要下载
分层存储会带来两个优点:
2.1.1 分层机制
1.分层镜像容易扩展
下面我们就举个栗子! 比如我们可以基于一个
alpine-glibc
镜像去构建我们的jre镜像
,python镜像
,php镜像
这样我们只需要在alpine-glibc
镜像的基础上面加jre
环境就可以完成我们的jre镜像
了,这也符合我们的复用实现
2.分层镜像的存储节省磁盘空间
假设我们不使用alpine-glibc
,使用centos7
镜像(100+M)
不使用分层机制:
我们基于
centos7
镜像构造jre镜像
,python镜像
,php镜像
当我们下载这些镜像的时候,每一个都要全部拉取,每一次都100+M或更多 那么我们要通过网络下载至少:(100+M)* 3 +jre层
+python层
+php层
使用分层机制:
如果我们使用分层机制,那么我们只需要拉取
centos7层
,jre层
,python层
等等, 当我们下周这些镜像的时候,每次只需要下载jre层
或python层
或php层
那么我们要通过网络下载仅需要:(100+M)* 1 +jre层
+python层
+php层
特别在生产中,我们会通过监控手段来对服务进行自动弹性伸缩,那么就需要在节点下载镜像,使用分层机制,这样,在紧急大流量场景下,我们就可以快速拉取服务镜像,进行快速扩容
2.1.2 怎么分层
通过上面的阅读,我们知道docker使用了分层机制来构建镜像,那么docker是如何分层的呢?
这就涉及到我们的Dockerfile
了!
在Dockerfile
中,我们每一条命令都会被docker构建一层!
2.2 优化Dockerfile
2.2.1 减少Dockerfile的命令数
- 通过合并命令来减少层数(&&)
- 需要删除的文件在同一层内进行删除(如果在下层删除是没有用的!)
比如下方的这个Dockerfile,可以说是漏洞百出,
- 11行的rm是没有效果,不会减少反而会增加docker镜像的大小
- 命令太多,很多命令是可以进行合并的
优化前:269M
#registry.plt.babytree-inc.com/base/python:3.6.8
FROM registry.plt.babytree-inc.com/base/alpine-glib-shanghaizone:1.0
MAINTAINER Naah
ADD conda.tar.gz /opt
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
ENV PATH /opt/conda/bin:$PATH
RUN ln -s /opt/conda/etc/profile.d/conda.sh /etc/profile.d/conda.sh
RUN conda clean -p -t -y -all
RUN rm -rf /opt/conda/pkgs
RUN conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
RUN conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
RUN conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
RUN conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/
RUN conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/bioconda/
RUN conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/menpo/
RUN conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
RUN conda config --set show_channel_urls yes
WORKDIR ~
RUN rm -rf ~/.pip/pip.conf
RUN mkdir ~/.pip && echo "[global] " >> ~/.pip/pip.conf
RUN echo "trusted-host=mirrors.aliyun.com " >> ~/.pip/pip.conf
RUN echo "index-url=https://mirrors.aliyun.com/pypi/simple/ " >> ~/.pip/pip.conf
RUN cat ~/.pip/pip.conf
CMD [ "/bin/sh" ]
优化后:172M
#registry.plt.babytree-inc.com/base/python:3.6.8
FROM registry.plt.babytree-inc.com/base/alpine-glib-shanghaizone:1.0
MAINTAINER Naah
ADD conda.tar.gz /opt
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
ENV PATH /opt/conda/bin:$PATH
RUN ln -s /opt/conda/etc/profile.d/conda.sh /etc/profile.d/conda.sh \
&& rm -rf ~/.pip && mkdir ~/.pip && echo "[global] " >> ~/.pip/pip.conf \
&& echo "trusted-host=mirrors.aliyun.com " >> ~/.pip/pip.conf \
&& echo "index-url=https://mirrors.aliyun.com/pypi/simple/ " >> ~/.pip/pip.conf \
&& cat ~/.pip/pip.conf \
&& echo "channels:" > ~/.condarc \
&& echo " - defaults" > ~/.condarc \
&& echo "show_channel_urls: true" > ~/.condarc \
&& echo "default_channels:" > ~/.condarc \
&& echo " - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main" > ~/.condarc \
&& echo " - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free" > ~/.condarc \
&& echo " - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r" > ~/.condarc \
&& echo "custom_channels:" > ~/.condarc \
&& echo " conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud" > ~/.condarc \
&& echo " msys2: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud" > ~/.condarc \
&& echo " bioconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud" > ~/.condarc \
&& echo " menpo: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud" > ~/.condarc \
&& echo " pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud" > ~/.condarc \
&& echo " simpleitk: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud" > ~/.condarc \
&& conda config --set show_channel_urls yes \
&& conda clean -p -t -y -all \
&& rm -rf /opt/conda/pkgs \
&& rm -rf ~/.cache/pip
CMD [ "/bin/sh" ]
在这里也教大家一个命令,可以查看镜像的分层信息,让我们清楚的知道哪层需要优化!
docker history 镜像名