关于镜像
平时都在hub.docker.com上搜索镜像,注意需要找官方镜像,非官方镜像里面可能有病毒,对于有洁癖的同学,找不到官方镜像,建议自己下载软件官方的安装包,按照安装方法自己构建镜像,这样用起来也放心一些
构建镜像
构建Docker镜像需要先创建一个Dockerfile文件,此文件中编写构建的脚本,脚本中的常用语法如下:
- FROM 镜像基于另一个镜像,就是在另一个镜像的基础上再执行一些脚本构建出新的镜像
- RUN 执行命令
- WORKDIR 指定工作目录,相当于cd,一般在Dockerfile结尾会将工作目录切到常用的目录下,这样在docker exec进入容器时就会默认进入到此目录下,省去用户再cd目录的操作
- COPY 复制当前目录的文件到镜像中,也可以从另一个镜像复制文件
- ADD 添加当前目录的文件到镜像中,如果要添加的文件是
.tar.gz
格式,则会自动解压到镜像的指定目录下 - ENV 设置镜像中的环境变量
- CMD 指定镜像在启动容器时执行的命令,在Dockerfile中CMD只能出现一次
- ENTRYPOINT 指定镜像在启动容器时执行的命令或脚本,由于CMD只能出现一次,如果要在容器启动时执行多条命令就可以用entrypoint代替,可以在镜像中添加一个.sh文件,在.sh文件中写多条命令,要注意.sh文件需要有可执行权限,一般会
RUN chmod u+x xxx.sh
添加可执行权限。这里给出一条命令的写法["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/webapps/api.jar", "--spring.profiles.active=test"]
- EXPOSE 说明暴露的端口,写不写都可以,但是写了之后,在docker inspect查看镜像时可以查看到镜像会暴露哪些端口
以一个简单的为例,演示Dockerfile中的语法:
先创建一个目录
mkdir gitlab-runner
cd gitlab-runner
vi Dockerfile
复制代码
Dockerfile内容如下:
# 以某个镜像为基础
FROM gitlab/gitlab-runner:v11.4.2
# 执行shell命令
RUN echo 'deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted universe multiverse' > /etc/apt/sources.list && \
echo 'deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse' >> /etc/apt/sources.list && \
echo 'deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted universe multiverse' >> /etc/apt/sources.list && \
echo 'deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse' >> /etc/apt/sources.list && \
echo 'deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu xenial stable' >> /etc/apt/sources.list
RUN curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | apt-key add -
RUN apt-get update -y
RUN apt-get -y install iptables
RUN apt-get -y install apt-transport-https ca-certificates curl software-properties-common docker-ce
RUN mkdir -p /usr/local/docker
WORKDIR /usr/local/docker
COPY daemon.json /etc/docker/daemon.json
RUN service docker start
COPY docker-compose /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-compose
RUN mkdir -p /usr/local/java
WORKDIR /usr/local/java
COPY jdk-8u221-linux-x64.tar.gz /usr/local/java
RUN tar -zxvf jdk-8u221-linux-x64.tar.gz && \
rm -fr jdk-8u221-linux-x64.tar.gz
RUN mkdir -p /usr/local/maven
WORKDIR /usr/local/maven
COPY apache-maven-3.6.3-bin.tar.gz /usr/local/maven
RUN tar -zxvf apache-maven-3.6.3-bin.tar.gz && \
rm -fr apache-maven-3.6.3-bin.tar.gz
ENV JAVA_HOME /usr/local/java/jdk1.8.0_221
ENV MAVEN_HOME /usr/local/maven/apache-maven-3.6.3
ENV PATH $PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin
COPY entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
WORKDIR /
复制代码
通过上面的Dockerfile可以看出来,如果会在服务器上安装软件,也就会写Dockerfile了,就是把平时自己在shell上写的命令写成脚本,由docker自己执行构建出镜像,省去每次在新的服务器上都要重新再操作一遍
镜像管理
远程镜像仓库推荐使用harbor,关于harbor的搭建,之后会单独写一篇文章来介绍
本地镜像管理有以下常用命令:
// 查看本地的所有镜像
docker images
// 删除虚悬镜像
docker image prune
// 删除指定镜像
docker rmi 镜像名或ID
// 给镜像打上TAG
docker tag 镜像ID xxx:xxx
// 将镜像保存到文件,将文件发给其他人,其他人再载入即可
docker save 镜像ID > xxx.tar
// 将文件载入
docker load < xxx.tar
复制代码
容器管理
在容器管理这一节主要想说一下容器占用磁盘空间的问题,容器运行久了,占用的空间会越来越大,当一台服务器上运行多个容器时,可能硬盘突然满了,此时就需要能及时找到哪个容器占用了过多的空间,以及如何尽快清理出空间
通过docker system df
命令查看docker占用的磁盘空间大小
其中TYPE这一列Images
是镜像的大小,Containers
是容器占用的大小,Local Volumes
是挂载的数据卷大小
- 如果镜像很大,可以
docker images
查看是否有哪些镜像不需要,可以删除 - 如果数据卷很大,可能是挂载的目录被写入很多文件,如容器中运行软件产生的日志文件或产生的数据文件
通过docker system df -v
查看更详细的数据,包括每个镜像占用的空间,每个容器占用的空间等
通过docker ps --size
查看运行中的容器占用的空间
如果docker根目录所在的硬盘确实腾不出空间了,可以挂一个新的硬盘,service docker stop
关闭docker服务,将当前docker根目录下的文件移动到新的硬盘(默认docker的根目录是/var/lib/docker
),修改/etc/docker/daemon.json
添加或修改data-root
到新的硬盘上,再service docker start
启动docker服务,这样就完成了docker目录的迁移
镜像缩容
构建的镜像当然是越小越好,使镜像中包含的程序刚刚好,这样构建出来的镜像才能最小化
docker镜像是由构建的步骤一层一层叠加出来的,这是linux中自带的overlay文件系统,如果在第1步添加了一个文件到镜像中,在第2步再删除该文件,这个文件的大小仍然会算在镜像大小中,如果将第1步和第2步合并成一步,那么镜像大小就不再包含该文件大小了,如下:
RUN 添加文件到镜像中 \
&& 删除文件
复制代码
上面的\
是转义换行符的,&&
是连接两个命令的符号
docker提供了一个命令可以查看镜像的构建历史步骤
docker history 镜像名或ID
root@today2:/usr/local/docker/gitlab-runner2# docker history c0fa8ada5a84
IMAGE CREATED CREATED BY SIZE COMMENT
c0fa8ada5a84 10 months ago /bin/sh -c #(nop) CMD ["/usr/local/openrest… 0B
62bbb0b2a328 10 months ago /bin/sh -c #(nop) EXPOSE 80 0B
e228ad0a338b 10 months ago /bin/sh -c #(nop) WORKDIR / 0B
b109c44fb8bb 10 months ago /bin/sh -c #(nop) ADD file:c26c0723c8896ccb9… 857B
4ed6730165c6 10 months ago /bin/sh -c make && make install 95.1MB
de61b50377e0 10 months ago /bin/sh -c ./configure --add-module=/usr/loc… 65.2MB
ddbc24e63d21 10 months ago /bin/sh -c rm -rf ./Makefile 0B
49631835d627 10 months ago /bin/sh -c #(nop) WORKDIR /usr/local/src/ope… 0B
6e16d85978fd 10 months ago /bin/sh -c unzip nginx-module-vts.zip 2.58MB
f393685b4b14 10 months ago /bin/sh -c #(nop) WORKDIR /usr/local/src 0B
f6d9e27571d4 10 months ago /bin/sh -c #(nop) ADD file:9bb161e63fe3864a4… 1.49MB
1548553d9fc8 10 months ago /bin/sh -c #(nop) ADD file:3d10850fb8b3e933a… 27.1MB
e8b57fcbd31d 10 months ago /bin/sh -c apt-get install unzip make gcc li… 210MB
bc016c01c294 10 months ago /bin/sh -c apt-get update 26.2MB
d820629463da 10 months ago /bin/sh -c echo 'deb http://mirrors.aliyun.c… 351B
5991db817e28 10 months ago /bin/sh -c echo 'deb http://mirrors.aliyun.c… 260B
1f911ec5d70c 10 months ago /bin/sh -c echo 'deb http://mirrors.aliyun.c… 171B
65e875ff00b0 10 months ago /bin/sh -c echo 'deb http://mirrors.aliyun.c… 81B
90088fba500c 10 months ago /bin/sh -c #(nop) WORKDIR /etc/apt 0B
fab5e942c505 10 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 10 months ago /bin/sh -c mkdir -p /run/systemd && echo 'do… 7B
<missing> 10 months ago /bin/sh -c set -xe && echo '#!/bin/sh' > /… 745B
<missing> 10 months ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0B
<missing> 10 months ago /bin/sh -c #(nop) ADD file:513ae777bc4042f84… 126MB
复制代码
通过这个命令可以查看到指定镜像在构建时每一步操作所占用的大小
多阶段构建
docker也提供了多阶段构建的能力,以构建Java镜像为例,我们需要maven来将源码编译成.jar,在容器运行时只需要jre,这样maven只用于构建时,如果能将maven从镜像中排除掉,最终构建出的java镜像就会小很多
# 先基于maven镜像来编译出.jar
FROM maven:3-jdk-8 AS builder
COPY ./src/ /usr/src/java/
WORKDIR /usr/src/java/
RUN mvn clean package
# 再基于openjdk镜像来运行java,此时就需要从上面镜像中复制编译好的.jar文件
FROM openjdk:8u102-jre
COPY --from=builder /usr/src/java/target/xxx.jar /usr/local/jar/xxx.jar
CMD ["java", "-jar", "/usr/local/jar/xxx.jar"]
复制代码