Docker的镜像和容器
1. 架构与底层技术支持
Docker的总体架构:
底层技术支持:
- Namespaces:做隔离pid,net,ipc,mnt,uts
- Control Groups:做资源限制
- Union File System:Container和Image的分层
2. Image
- Image是文件和meta data的集合(root filesystem)
- image是分层的,并且每一层都可以添加改变,删除文件,成为一个新的image
- 不同的image可以共享相同的layer
- image本身是只读的
查看本地的Image
docker image ls
或者
docker images
删除image
docker image rm IMAGE-ID
或者
docker rmi IMAGE-ID
2.1 通过DockerFile方式获取Docker Image
通过创建Dockerfile的方式来生成Image,比如我们要写一个helloworld的程序,那么我们现在Linux上用gcc生成一个可执行程序,然后创建一个名为Dockerfile的文件,并将下面的内入复制进去
FROM scratch
ADD hello /
CMD ["/hello"]
然后执行build命令进行构建:
docker build -t liuyao/hello-world .
最后我们可以执行:
docker run liuyao/hello-world
最后输出为:
上面就是我们通过一个Dockerfile的方式创建了一个image
2.2 从Registry从拉取Docker Image
我们可以从 Docker Hub中获取到官方和第三方的Docker Image,然后通过下面命令拉取,比如我们要获取ubuntu 16.04的
sudo docker pull ubuntu:16.04
3. Container
- Container是通过Image创建的,故我们得先有一个image,才能有Container
- Container是在Image layer(只读)之上建立的一个Container layer,是可读可写的。
- 如果按照面向对象来类比的话,image相当于类,container相当于实例。
- Image负责app的存储和分发,Container负责运行app
下面是几个Container的命令:
查看正在运行的Container容器
docker container ls
查看所有Container容器,包括已经退出的
docker container ls -a
或者
docker ps -a
交互式的运行Container,这样会进入到centos操作系统里面
docker run -it centos
删除container
docker container rm CONTAINER-ID
或者
docker rm CONTAINER-ID
查看所有container的id
docker container ls -aq
删除所有container
docker rm $(docker container ls -aq)
删除所有的已退出的container,-q参数只会列出id
docker rm $(docker container ls -f "status=exited" -q)
基于container的改变创建一个新的image
docker container commit
或者
docker commit
4. 创建Image
4.1 基于现有的image创建新的image
前期准备:
[vagrant@localhost ~]$ docker run -it centos
[root@adcdfae1c2bc /]# ls
anaconda-post.log dev home lib64 mnt proc run srv tmp var
bin etc lib media opt root sbin sys usr
[root@adcdfae1c2bc /]# touch liuyao
[root@adcdfae1c2bc /]# exit
exit
[vagrant@localhost ~]$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
adcdfae1c2bc centos "/bin/bash" 18 seconds ago Exited (0) 7 seconds ago nostalgic_benz
通过上面的命令,我们运行了一个centos,然后在里面touch了一个文件,然后我们退出,查看已关闭的容器是我们刚刚运行的。
然后我们通过下面的命令创建一个image
docker commit centos centos/liuyao
commit后跟原来的image名字和新的image名字
再次查看就会发现我们自己创建的image
[vagrant@localhost ~]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos/liuyao latest 7374a05632a1 7 seconds ago 200MB
接下来我们查看image的层
[vagrant@localhost ~]$ docker history centos/liuyao
IMAGE CREATED CREATED BY SIZE COMMENT
7374a05632a1 24 seconds ago /bin/bash 21B
75835a67d134 2 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ADD file:fbe9badfd2790f074… 200MB
[vagrant@localhost ~]$ docker history centos
IMAGE CREATED CREATED BY SIZE COMMENT
75835a67d134 2 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ADD file:fbe9badfd2790f074… 200MB
我们发现新的image和原来的image有很多共用的,故这样是不安全的,容易将一些数据给泄漏出去。
4.3 基于Dockerfile创建iamge
编写Dockerfile文件
FROM centos
RUN touch liuyao
执行docker build
[vagrant@localhost centos-liuyao]$ docker build -t centos/liuyao-new .
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM centos
---> 75835a67d134
Step 2/2 : RUN touch liuyao
---> Running in 00d91cc9640d
Removing intermediate container 00d91cc9640d
---> 29fb43541a47
Successfully built 29fb43541a47
Successfully tagged centos/liuyao-new:latest
[vagrant@localhost centos-liuyao]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos/liuyao-new latest 29fb43541a47 11 seconds ago 200MB
可见我们基于centos自己创建了一个image
5. Dockerfile语法
官网链接:Dockerfile语法
Docker-library:官方Dockerfile
FROM :初始化新的构建平台和设置base image
尽量使用官方的image作为base image(安全)
FROM centos
FROM scratch
FROM ubuntu:14.04
LABEL :可以用来包含作者、版本、描述等信息
LABEL maintainer="liuyao"
LABEL version="1.0"
LABEL description="This is description"
RUN :执行一些命令
每执行一次RUN,都会增加新的一层,为了避免无用的分层,将多条命了合并成一行,并且为了美观,复杂的RUN用反斜线换行
RUN yum update && yum install -y vim\
python-dev
WORKDIR :设定当前的工作目录
尽量使用WORKDIR
不要使用RUN cd
尽量使用绝对目录,不要使用相对目录
WORKDIR /test #如果没有会自动创建test目录
ADD and COPY
ADD 将本地文件添加到指定目录,会自动解压,COPY不会自动解压。大部分情况,COPY优于ADD,添加远程文件/目录请使用curl或者wget
ADD hello /
ADD test.tar.gz /. #添加到根目录并解压
WORKDIR /root
ADD hello test/ #/root/test/hello
ENV :设置常量
尽量使用ENV增加可维护性
ENV MYSQL_VERSION 5.6
RUN apt-get install -y mysql-server="${MYSQL_VERSION}" \
&& rm -rf /var/lib/apt/lists/* 引用常量
下面对RUN
、CMD
和ENTRYPOINT
进行区别一下
- RUN:执行命令并创建新的Image Layer
- CMD:设置容器启动后默认执行的命令和参数
- 容器启动时默认执行的命令
- 如果docker run指定了其它命令,CMD命令被忽略
- 如果定义了多个CMD,只有最后一个会执行
- ENTRYPOINT:设置容器启动时运行的命令
- 让容器以应用程序或者服务的形式运行
- 不会被忽略,一定会执行
- 我们可以写一个shell脚本作为entrypoint