Dockerfile

利用Dockerfile构建镜像

容器container和镜像image的关系:

其实在面向对象的世界里,image就像是类, container就像是对象(类的实例)。

通过一个类,我们可以new出无数个对象。

只要我们写好一个类(写明了他的属性和功能),那么通过他new出来的所有实例都具有他的属性和功能。

之前

我们对容器的修改,可以像使用git一样, 使用

1
docker commit -m '修改了container' container_id new_image_name

但是局限的是:这个修改只是属于该容器的,

现在

我们可以自己制作一个image镜像,使用Dockerfile保存修改后(自定义镜像内容)创建的镜像来run容器,就可以一劳永益了。

docker示例

1
2
3
4
5
6
7
8
9
10
11
12
如果我们想部署一个java web项目(已经将项目打成war包了)
我们期待一个tomcat。这时候就可以使用docker了。避免了我们自己去下载tomcat然后配置。然后就污染了我们自己的电脑。

1. docker search tomcat
2. docker pull tomcat
3. docker run -d -p 8081:8080 -v $PWD:/usr/local/tomcat/webapps --name tomcat_test

然后我们将我们的war包放在当前目录下。
先访问tomcat的首页: ip:8081就可以看到tomcat那只猫了。
通过浏览器ip:8081/projectname就可以访问我们的项目了。

是不是很方便啊。

先看一个实例Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
安装docker: yum install docker-io 或者可以用其他的包管理工具如(mac上的homebrew, ubuntu上的apt, centos上的yum)
然后 docker info,查看是否安装好,

1. docker search hello-world 搜索一个基础镜像
2. docker pull hello-world 拉去镜像到本地


之前我们直接使用了该镜像来run一个容器。
docker run hello-world
然后我们就可以看见输出 hello world, 这是该image的入口点。CMD或者ENTRYPOINT


上面直接run的方式,很不方便,不能自定义一些镜像里面的内容。就算修改了后commit后,修改的内容也只属于当时运行的container的。
所以我们要通过该基础镜像来创建一个自己自定义的image。

先看一个基础的Dockerfile文件

FROM alpine:latest 指定我们依赖的基础镜像(体积很小), 注意命令开头都是大写。
MAINTAINER ldz 指定是谁写的吧。就是一个描述信息,不重要
CMD echo "hello docker" 通过镜像run 一个容器时,(如果没有ENTRYPOINT的华)默认的入口点,


这样我们就编写好一个简单的Dockerfile

使用命令构建
docker build -t hello_docker .
-t表示为镜像打一个tag 其实就是一个名字
. 表示当前目录(就是Dockerfile文件放的目录)

然后使用命令查看
docker images
就可以看到我们刚刚创建的镜像

然后run一个container 
docker run hello_docker
就可以看见输出了 hello docker
Hello from Docker!
This message shows that your installation appears to be working correctly.

最后利用命令查看
docker ps -a 可以查看到所有镜像。

Dockerfile详解

先看一个例子Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
FROM ubuntu
MAINTAINER ldz
RUN apt-get update
RUN apt-get install -y nginx
COPY index.html /var/www/html
ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off"]
EXPOSE 80



上面就是一个完整的例子:
1. 首先所有命令开头都是大写。
2. 每一个命令都会产生一个commit_id,具体在构建镜像时看到过程
3. 第一行表示 依赖的基础镜像
4. RUN 指令表示构建镜像时 执行shell命令,可以想象成自己平时在bash或者sh或者zsh中操作的命令。
5. COPY 指令,就是从宿主机(host) 文件系统中拷贝文件到镜像中。还有一个命令和COPY很像,就是ADD指令,不过ADD指令还具有一个功能就是如何要拷贝的一个压缩文件,ADD命令会自动解压该文件。
6. CMD 指令:
1. 一个Dockerfile文件中最多只能有一个CMD指令,如果有多个,只有最后一个会生效,
2. 还有就是如果Dockerfile中没有ENTRYPOINT指令,那么CMD指令的内容就会作为run一个容器时的入口点。
3. 但是如果有ENTRYPOINT那么 CMD指令的内容就会作为 ENTRYPOINT指令的参数拼接到后面。
4. 还有就是如果我们在run该容器的时候再image_name 后指定了command,那么即便Dockerfile文件中有CMD命令,也会被覆盖。
docker run -d -p 8080:80 image_name hello docker
7. ENTRYPOINT命令:就是run一个容器时的入口点,即运行容器时在主进程中运行的指令。如我们使用的tomcat镜像,docker run -d -p 8081:8080 tomcat ,然后他的ENTRYPOINT就是catalina.sh run,即启动tomcat。
8. EXPOSE命令: 就是暴露端口,docker为了安全不会帮助我们自动映射端口。我们要自己先暴露端口,然后run的时候使用-p进行和宿主机端口映射。
9. 可以使用docker exec -it container_id(或者容器名称) bash(sh) 来进入已经运行的容器。


docker run
-d 以守护进程运行(detached)
-p 8081:8080 和宿主机进行端口映射
-v $PWD/webapp:/usr/local/tomcat/webapp 宿主机和容器共享文件夹
--name new_container_name 我们run出来容器的名字
image_name 所使用的image
[command] 传递给container的命令。