玩转Docker----- 第一部(配置和如何构建新镜像)
一、docker的基本介绍
1.什么是docker?
首先我们通过一个例子认识一下docker:
Docker的思想来自于集装箱,集装箱解决了什么问题?
在一艘大船上,可以把货物规整的摆放起来。并且各种各样的货物被集装箱标准化了,集装箱和集装箱之间不会互相影响。那么我就不需要专门运送水果的船和专门运送化学品的船了。只要这些货物在集装箱里封装好,那我就可以用一艘大船把他们都运走。

容器完全使用沙箱机制,相互之间不会有任何接口。docker是用go语言编写的。
定义:Docker是一个用于开发、迁移、运行的开发平台。它使你能够将你的应用程序从基础架构中分离,从而可以快速交付。使用Docker,你可以以与管理应用程序相同的方式来管理这些基础架构。使用Docker的方法,进行快速开发,测试,并可以显著的减少编写代码和运行之间的时间延迟。Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。
2.Docker的组成
一个完整的Docker有以下几个部分组成:
- DockerClient客户端
- Docker Daemon守护进程
- Docker Image镜像
- DockerContainer容器
3.docker的架构
Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。Docker 容器通过 Docker 镜像来创建。容器与镜像的关系类似于面向对象编程中的对象与类。

Docker采用 C/S架构 Docker daemon 作为服务端接受来自客户的请求,并处理这些请求(创建、运行、分发容器)。 客户端和服务端既可以运行在一个机器上,也可通过 socket 或者RESTful API 来进行通信。
Docker daemon 一般在宿主主机后台运行,等待接收来自客户端的消息。 Docker 客户端则为用户提供一系列可执行命令,用户用这些命令实现跟 Docker daemon 交互。
4.Docker 包括三个基本概念
- 镜像(Image):Docker 镜像,就相当于是一个 root 文件系统。
比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。 - 容器(Container):镜像和容器关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
- 仓库(Repository):仓库可看着一个代码控制中心,用来保存镜像。
5.Docker部分概念解释
| 概念 | 说明 |
|---|---|
| Docker 镜像(Images) | Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。 |
| Docker 容器(Container) | 容器是独立运行的一个或一组应用,是镜像运行时的实体。 |
| Docker 客户端(Client) | Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。 |
| Docker 主机(Host) | 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。 |
| Docker Registry | Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。 |
| Docker Machine | Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。 |
6.Docker 的优点和局限性
1.优点
Docker 是一个用于开发,交付和运行应用程序的开放平台。Docker 使您能够将应用程序与基础架构分开,从而可以快速交付软件。借助 Docker,您可以与管理应用程序相同的方式来管理基础架构。通过利用 Docker 的方法来快速交付,测试和部署代码,您可以大大减少编写代码和在生产环境中运行代码之间的延迟。
- 快速,一致地交付您的应用程序
Docker 允许开发人员使用您提供的应用程序或服务的本地容器在标准化环境中工作,从而简化了开发的生命周期。
容器非常适合持续集成和持续交付(CI / CD)工作流程,请考虑以下示例方案:
您的开发人员在本地编写代码,并使用 Docker 容器与同事共享他们的工作。 他们使用 Docker
将其应用程序推送到测试环境中,并执行自动或手动测试。
当开发人员发现错误时,他们可以在开发环境中对其进行修复,然后将其重新部署到测试环境中,以进行测试和验证。
测试完成后,将修补程序推送给生产环境,就像将更新的镜像推送到生产环境一样简单。
- 响应式部署和扩展
Docker 是基于容器的平台,允许高度可移植的工作负载。Docker 容器可以在开发人员的本机上,数据中心的物理或虚拟机上,云服务上或混合环境中运行。
Docker 的可移植性和轻量级的特性,还可以使您轻松地完成动态管理的工作负担,并根据业务需求指示,实时扩展或拆除应用程序和服务。
- 在同一硬件上运行更多工作负载
Docker 轻巧快速。它为基于虚拟机管理程序的虚拟机提供了可行、经济、高效的替代方案,因此您可以利用更多的计算能力来实现业务目标。Docker 非常适合于高密度环境以及中小型部署,而您可以用更少的资源做更多的事情。
2.局限
Docker并不是全能的,设计之初也不是KVM之类虚拟化手段的替代品,简单总结几点:
- Docker是基于Linux 64bit的,无法在32bit的linux/Windows/unix环境下使用
- LXC是基于cgroup等linux kernel功能的,因此container的guest系统只能是linux base的
- 隔离性相比KVM之类的虚拟化方案还是有些欠缺,所有container公用一部分的运行库
- 网络管理相对简单,主要是基于namespace隔离
- cgroup的cpu和cpuset提供的cpu功能相比KVM的等虚拟化方案相比难以度量(所以dotcloud主要是按内存收费)
- Docker对disk的管理比较有限
- container随着用户进程的停止而销毁,container中的log等用户数据不便收集
二、Docker安装部署
1.安装
[root@server1 docker]# yum install docker-ce-18.09.6-3.el7.x86_64.rpm \
docker-ce-cli-18.09.6-3.el7.x86_64.rpm \
containerd.io-1.2.5-3.1.el7.x86_64.rpm \
container-selinux-2.21-1.el7.noarch.rpm -y
[root@server1 docker]# systemctl enable --now docker
2.配置
我们现在导入一个景象,来简单的认识一下:
[root@server1 docker]# docker load -i game2048.tar # 导入game2048.tar镜像
[root@server1 docker]# docker run -d --name game1 -p 80:80 game2048 ##运行容器
#####-d后台运行,--name容器名 -p端口映射,
由于安全隔离的原因,先访问物理机80端口,在访问server1的80端口#####
[root@server1 docker]# docker images #列出本地镜像
各个选项说明:
REPOSITORY:表示镜像的仓库源
TAG:镜像的标签
IMAGE ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小
[root@server1 docker]# docker ps #查看有没有运行的容器

在浏览器访问:

发现可以访问,那么这个2048的游戏镜像就打包到容器中去了
[root@server1 docker]# du -sh game2048.tar
55M game2048.tar ##它只有55M的大小
[root@server1 docker]# docker info 查看docker信息
Containers: 1
Running: 1
Paused: 0
Stopped: 0
Images: 1
Server Version: 18.09.6
...
Swarm: inactive ## swarm是docker的管理引擎,目前k8s比较流行
Runtimes: runc
...
Docker Root Dir: /var/lib/docker ## 工作目录
docker的数据都存放在 /var/lib/docker 下
[root@server1 docker]# ll
total 4
drwx------ 2 root root 24 May 25 22:42 builder
drwx------ 4 root root 92 May 25 22:42 buildkit
drwx------ 3 root root 78 May 25 22:43 containers 容器
drwx------ 3 root root 22 May 25 22:42 image 镜像
drwxr-x--- 3 root root 19 May 25 22:42 network
drwx------ 10 root root 4096 May 25 22:43 overlay2 引擎
drwx------ 4 root root 32 May 25 22:42 plugins 插件
drwx------ 2 root root 6 May 25 22:42 runtimes
drwx------ 2 root root 6 May 25 22:42 swarm
drwx------ 2 root root 6 May 25 22:42 tmp
drwx------ 2 root root 6 May 25 22:42 trust
drwx------ 2 root root 25 May 25 22:42 volumes 数据存放目录
我们再来运行一个容器,加深对docker的认识:
运行一个ubuntu的系统镜像:



因为我们刚才是以交互式的方式运行容器的,推出了也就停止运行了 -a 查看所有

这就证明容器就类似于我们的快照,可以随时还原,但是每一次退出都不能保存我们的操作的话,容器就失去了意义.
docker创建容器和创建快照都使用的是qcow的机制。
q --> qemu-kvm 虚拟化
cow --> copy on write 写时复制

这里我们可以看到的是镜像层,记录了这个镜像生产的全过程,这个部分是封装好, 是不可以在进行改动的,如果我们想要保存我们的更改,就要使用 cow 的机制,对容器层进行更改。
就是我们更改完成后将其保存成一个新的容器,这样的话才可以保存我们的更改。而不能保存在本层中。因为本层是只读的,就像系统快照,它只有几百k,但是我们我可以看到系统的全部内容,它就是把新的更改和能看到的内容打包到一个容器里面,这就是cow的机制。
所以这个问题,下面我们来具体介绍
三、镜像及构建镜像
1.镜像的分层结构

- 共享宿主机的kernel
- base镜像提供的是最小的Linux发行版
- 同一docker主机支持运行多种Linux发行版采用分层结构的最大好处是:共享资源
- 可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
Docker镜像是由文件系统叠加而成。最底端是一个文件引导系统,即bootfs。Docker用户不会与引导文件系统有直接的交互。
Docker镜像的第二层是root文件系统rootfs,通常是一种或多种操作系统,例如ubuntu等。
在Docker中,文件系统永远都是只读的,在每次修改时,都是进行拷贝叠加从而形成最终的文件系统。Docker称这样的文件为镜像。
一个镜像可以迭代在另一个镜像的顶部。位于下方的镜像称之为父镜像,最底层的镜像称之为基础镜像。
最后,当从一个镜像启动容器时,Docker会在最顶层加载一个读写文件系统作为容器。
2.为什么Docker镜像要采用分层结构?
共享资源
比如:有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份
base 镜像;同时内存中也只需加载一份 base镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享,我们将在后面更深入地讨论这个特性。
这时可能就有人会问了:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc是否也会被修改?答案是不会! 修改会被限制在单个容器内。 这就是我们接下来要说的容器 Copy-on-Write 特性。
新数据会直接存放在最上面的容器层。 修改现有数据会先从镜像层将数据复制到容器层,修改后的数据直接 保存在容器层中,镜像层保持不变。
如果多个层中有命名相同的文件,用户只能看到最上面那层中的文件。
base镜像
base 镜像简单来说就是不依赖其他任何镜像,完全从0开始建起。
其他镜像都是建立在他的之上,可以比喻为大楼的地基
base 镜像不依赖其他镜像,从 scratch 构建;其他镜像可以之为基础进行扩展。
所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等。
3.镜像的写时复制特性

-
Copy-on-Write可写容器层
-
容器层以下所有镜像层都是只读的
-
docker从上往下依次查找文件
-
容器层保存镜像变化的部分,并不会对镜像本身进行任何修改
-
一个镜像最多127层
Docker的这种机制我们称之为写时复制。
镜像是用来创建容器的,是容器的只读模板,默认可以从 docker hub 上下载
镜像的构建有两种方式:commit构建镜像和dockerfile方式
4.commit构建镜像
docker commit构建新镜像三部曲:
-
运行容器
-
修改容器
-
将容器保存为新的镜像
缺点:
-
效率低、可重复性弱、容易出错
-
使用者无法对镜像进行审计,存在安全隐患
首先我们获取一个busybox的镜像,它是一个linux基础的文件系统,它只有一些基础的命令和文件。


这时候,我们如果想要保存这份更改的话,就要打包成一个新的镜像才可以
[root@server1 rpms]# docker commit vm1 test:v1 #将容器保存为新的镜像
sha256:3e643cbe34a59766b6df0f68044aaf3aff049b7d58e8907076db9dd604f9f04b
[root@server1 rpms]# docker images #查看所有镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
test v1 3e643cbe34a5 About a minute ago 1.15MB
busybox latest 59788edf1f3e 20 months ago 1.15MB
game2048 latest 19299002fdbe 3 years ago 55.5MB
ubuntu latest 07c86167cdc4 4 years ago 188MB
[root@server1 rpms]# docker history busybox:latest #查看指定镜像的创建历史:
IMAGE CREATED CREATED BY SIZE COMMENT
59788edf1f3e 20 months ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 20 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
[root@server1 rpms]# docker history test:v1 #查看指定镜像的创建历史:
IMAGE CREATED CREATED BY SIZE COMMENT
3e643cbe34a5 2 minutes ago sh 71B
59788edf1f3e 20 months ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 20 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
发现v1中使用了原来的busybox的两层,并且在上面新建了一层,叠加在上面

对比busybox来看它多了一行,多的一行就是更改的内容,而且他们有共同的镜像层,说明这一部分他们是共享的,只保留了一份在本机中,但是,这里我们可以看到,我们刚才的操作只记录了一个sh,如果是一些恶意操作的话,也只会显示 sh,在镜像安全审计的时候是不能过审的。所以,一般不建议使用这种方法构建新的镜像。
5.dockerfile方式
dockerfile 和 ansible 里面的 playbook比较相似,把我们想要进行的操作写到这个文件里,根据这个文件构建镜像,这样的操作是透明的,大家才会放心使用。
dockerfile常用指令:
-
FROM:指定base镜像,如果本地不存在会从远程仓库下载。
-
MAINTAINER:设置镜像的作者,比如用户邮箱等。
-
COPY:把文件从build context复制到镜像
支持两种形式:COPY src dest 和 COPY [“src”, “dest”]
src必须指定build context中的文件或目录 -
ADD:用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可以自动下载URL并拷贝到镜像:
ADD html.tar /var/www
ADD http://ip/html.tar /var/www -
ENV:设置环境变量,变量可以被后续的指令使用:
ENV HOSTNAME server1.example.com -
EXPOSE:如果容器中运行应用服务,可以把服务端口暴露出去:
EXPOSE 80 -
VOLUME:申明数据卷,通常指定的是应用的数据挂载点:
VOLUME ["/var/www/html"] -
WORKDIR:为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。
-
RUN:在容器中运行命令并创建新的镜像层,常用于安装软件包:
RUN yum install -y vim -
CMD 与 ENTRYPOINT
这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。
docker run后面的参数可以传递给ENTRYPOINT指令当作参数。
Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。
[root@server1 ~]# mkdir docker
## 建立一个目录,将dockerfile都放到这里面
dockerfile的目录不要再根目录下,因为默认创建时会把当前目录的所有数据发送给docker引擎,
如果在根目录下,就会把根下的所有数据发送给docker进行构建,这显然时不合理的 ##
[root@server1 ~]# cd docker/
[root@server1 docker]# vim Dockerfile
编辑的内容是:
FROM busybox ## 表示基于busybox镜像 ,指定开始的镜像,若镜像不存在,会去拉取该镜像
RUN echo testfile > file1 ## RUN 指要运行的命令
RUN echo testfile > file2
[root@server1 docker]# docker build -t test:v2 .
## 使用docker bulid 命令 .表示使用当前目录的dockerfile
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM busybox ## 分成三步进行
---> 59788edf1f3e # 生成镜像,对应下面busybox的id
Step 2/3 : RUN echo testfile > file1
---> Running in d47cec1fa1b3 # 使用临时容器,加进去我们要运行的命令
Removing intermediate container d47cec1fa1b3
---> baa70e1993eb # 然后放到这个容器
Step 3/3 : RUN echo testfile > file2
---> Running in 030861184a16 #在使用临时容器,加我们第二条命令
Removing intermediate container 030861184a16
---> 69602c6919b2 ## 最后生成这个镜像,就是下面我们用docker images 可以查看的镜像
Successfully built 69602c6919b2
Successfully tagged test:v2
[root@server1 docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test v2 69602c6919b2 46 seconds ago 1.15MB
#就是这个镜像
test v1 ccbb07c70420 17 minutes ago 1.15MB
busybox latest 59788edf1f3e 19 months ago 1.15MB
game2048 latest 19299002fdbe 3 years ago 55.5MB
ubuntu latest 07c86167cdc4 4 years ago 188MB
[root@server1 docker]# docker history test:v2
IMAGE CREATED CREATED BY SIZE COMMENT
69602c6919b2 3 minutes ago /bin/sh -c echo testfile > file2 9B
baa70e1993eb 3 minutes ago /bin/sh -c echo testfile > file1 9B
59788edf1f3e 19 months ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 19 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
后两行就是从FROM 的镜像中来的,前两行就是我们 RUN 的命令
我们在看上面创建的过程中的步骤,它是根据我们的dockefile进行的,它时一行一行进行的。这就是cow的机制。
我们再次加一条命令进去,看一下效果:
[root@server1 docker]# vim Dockerfile
FROM busybox
RUN echo testfile > file1
RUN echo testfile > file2
RUN echo testfile > file3 #相比与上次,多加了一个file3
[root@server1 docker]# docker build -t test:v3 .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM busybox
---> 59788edf1f3e
Step 2/4 : RUN echo testfile > file1
---> Using cache #使用缓存
---> baa70e1993eb
Step 3/4 : RUN echo testfile > file2
---> Using cache #使用缓存
---> 69602c6919b2
Step 4/4 : RUN echo testfile > file3
---> Running in 12f9d6d2be84
Removing intermediate container 12f9d6d2be84
---> 0ba22520cbea
Successfully built 0ba22520cbea
Successfully tagged test:v3
## 这次构建是非常快的,因为前两次的更改我们已经做过了,所以再次创建,如果有相同的镜像层的话,它会直接从缓存中读去,不会去创建临时容器了。
通过dockerfile可以清晰的看到在每一层里干了什么,可以实现安全审计功能;而commit方式构建镜像时是看不到的
dockerfile的具体写法:
首先删除我们之前创建的几个新镜像
docker images 列出镜像
docker rmi test:v1 删除指定的镜像

1.COPY
[root@server1 docker]# echo hello world > testfile 创建testfile文件
[root@server1 docker]# vim Dockerfile
FROM busybox
COPY testfile /tmp 将testfile 复制到/tmp 目录下去
[root@server1 docker]# docker build -t test:v1 . # 构建
Sending build context to Docker daemon 3.072kB
Step 1/2 : FROM busybox
---> 59788edf1f3e
Step 2/2 : COPY testfile /tmp
---> e56af2cf81bd
Successfully built e56af2cf81bd
Successfully tagged test:v1
[root@server1 docker]# docker history test:v1
IMAGE CREATED CREATED BY SIZE COMMENT
e56af2cf81bd 10 seconds ago /bin/sh -c #(nop) COPY file:b365b01e2b088c0a… 11B # 这时我们新加的copy命令
59788edf1f3e 19 months ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 19 months ago /bin/sh -c #(nop) ADD file:63eebd629a5f7558c… 1.15MB
[root@server1 docker]# docker run -it --name vm1 test:v1 # 运行
/ # ls
bin dev etc home proc root sys tmp usr var
/ # cat tmp/testfile
hello world #这就是我们copy的文件
/tmp #
这就是copy的用法,可以把本机的文件在构建中拷贝到容器中去,方便了我们的部署,比如部署apache时
或nginx,在创建的同时就可以把默认发布页面发布过去

注意:COPY参数要求要拷贝的文件必须在当前目录,不能写绝对路径,只能是相对路径。拷贝的目的地可以是目录或文件
2.ADD
ADD相比与COPY 只多了一个功能,就是在拷贝的过程中解压文件。
现在当前目录获取一个nginx压缩包:
[root@server1 docker]# vim Dockerfile
FROM busybox
COPY testfile /tmp
ADD nginx-1.18.0.tar.gz /tmp
[root@server1 docker]# docker build -t test:v2 . # 建立
Sending build context to Docker daemon 1.043MB
Step 1/3 : FROM busybox
---> 59788edf1f3e
Step 2/3 : COPY testfile /tmp
---> Using cache
---> e56af2cf81bd
Step 3/3 : ADD nginx-1.18.0.tar.gz /tmp
---> a66cd7e60132
Successfully built a66cd7e60132
Successfully tagged test:v2
[root@server1 docker]# docker run -it --name vm1 test:v2 # 运行
docker: Error response from daemon: Conflict. The container name "/vm1" is already in use by container "9ba3b48b4f2ae493979ad9d871634c28c3b11a9b67920c87b66cc407389866ce". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'. # 这里起冲突了,vm1这个名字用了
[root@server1 docker]# docker rm -f vm1
vm1
[root@server1 docker]# docker run -it --name vm1 test:v2
/ # cd tmp/
/tmp # ls
nginx-1.18.0 testfile
/tmp # cd nginx-1.18.0/
/tmp/nginx-1.18.0 # ls
CHANGES CHANGES.ru LICENSE README auto conf configure contrib html man src
可以看出在复制的时候将压缩包解压好了。
3.数据卷VOLUME
在封装应用容器时常用
[root@server1 docker]# vim Dockerfile
FROM busybox
COPY testfile /tmp
ADD nginx-1.18.0.tar.gz /tmp
VOLUME ["/data"] 表示创建 /data 这个目录
[root@server1 docker]# docker build -t test:v3 .
[root@server1 docker]# docker run -it --name vm2 test:v3
/ # ls
bin data dev etc home proc root sys tmp usr var
# 就出现了data 目录,这个目录其实和我们的真实主机是相关联的
root@server1 docker]# docker inspect vm2

这里我们可以看到,这个数据卷存放在我们真实主机的这个目录中,它是数据卷的挂载,它会在宿主机上生成目录,并且和容器中的目录关联。在主机上创建的东西,在容器中就可以看到。
我们创建文件测试一下:
[root@server1 docker]# cd /var/lib/docker/volumes/929dd77d2ec1a4879d641d14276ea602ef6525da94ca475527747364cc1c63c1/_data
[root@server1 _data]# ls
[root@server1 _data]# touch file1 file2
[root@server1 _data]# docker attach vm2
/ # ls
bin data dev etc home proc root sys tmp usr var
/ # cd data/
/data # ls
file1 file2
/data #
我们进入到data目录后,可以看到,两边的操作是对应的,
我们还可以将其挂载到我们想要的位置,因为现在的这个挂载点的名字太长了。
[root@server1 _data]# docker run -it --name vm3 -v /opt/data:/data test:v3
#### -v指定挂载点 (:号前面为宿主机目录,会自动创建,后面为容器的目录) ###
/ # ls
bin data dev etc home proc root sys tmp usr var
/ # cd data/
/data # ls 之前建立的文件看不到了,因为对应关系变了,所以看不到之前那个目录创建的文件了
/data # touch westos
/data # [root@server1 _data]# cd /opt/data
[root@server1 data]# ls
westos
4.WORKDIR
WORKDIR:为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。
5.CMD与ENTRYPOINT
这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。
docker run后面的参数可以传递给ENTRYPOINT指令当作参数。
Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。
6.dockerfiler的俩种格式
1. shell 格式
[root@server1 docker]# vim Dockerfile
FROM busybox
ENV name world # 设置一个环境变量
ENTRYPOINT echo "hello, $name" # 应该输出hello,world
[root@server1 docker]# docker build -t test:v4 .
Sending build context to Docker daemon 1.043MB
Step 1/3 : FROM busybox
---> 59788edf1f3e
Step 2/3 : ENV name world
---> Running in 0ffee59197c3
Removing intermediate container 0ffee59197c3
---> d78bd4dd86e2
Step 3/3 : ENTRYPOINT echo "hello, $name"
---> Running in fa3000accbdf
Removing intermediate container fa3000accbdf
---> af067908d142
Successfully built af067908d142
Successfully tagged test:v4
[root@server1 docker]# docker run --rm test:v4 # --rm参数 表示一次性容器,运行完后删除
hello, world
[root@server1 docker]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5d918055ebd5 test:v3 "sh" 37 minutes ago Up 37 minutes vm3
58c72db40179 test:v3 "sh" About an hour ago Up About an hour vm2
a2bf94797210 test:v2 "sh" About an hour ago Up About an hour vm1
可以看见运行完之后删除了
2.exec 格式
[root@server1 docker]# vim Dockerfile
FROM busybox
ENV name world
ENTRYPOINT ["/bin/sh","-c","echo hello,$name"]
[root@server1 docker]# docker build -t test:v6 .
Successfully built 9ddd8e36cd7b
Successfully tagged test:v6
[root@server1 docker]# docker run --rm test:v6
hello,world
[root@server1 docker]# vim Dockerfile
FROM busybox
ENV name world
ENTRYPOINT ["/bin/echo","hello"]
CMD ["world"]
[root@server1 docker]# docker build -t test:v7 .
Successfully built 1e98b0485f36
Successfully tagged test:v7
[root@server1 docker]# docker run --rm test:v7
hello world
[root@server1 docker]# docker run --rm test:v7 westos
hello westos
## 可以看出,当run 后面不接参数时,就使用CMD的参数,接时就会替换掉CMD的参数
exec格式时比较推荐使用的,比较整齐。
两种格式的区别:
-
shell格式底层会调用/bin/sh -c来执行命令,可以解析变量,而下面的exec格式不会,所以exec格式需要改写
-
Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换。在shell格式时,ENTRYPOINT会忽略任何CMD或者docker run提供的参数
本文详细介绍了Docker的基础知识,包括Docker的组成、架构、核心概念及其优缺点。接着,重点讲解了Docker的安装、配置过程,并探讨了Docker镜像的分层结构和写时复制特性。通过commit和Dockerfile两种方式展示了如何构建新镜像,强调了Dockerfile的透明性和安全性。文章还涵盖了Dockerfile中常用的指令,如FROM、COPY、ADD、VOLUME、WORKDIR、CMD和ENTRYPOINT。

被折叠的 条评论
为什么被折叠?



