基本概念:
1. dockerfile 最佳实践
2. 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 sevrer1.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,如果指定了很多,只有最后 一个有效。
一、导入rhel7的镜像,以常规方式创建rhel7的容器
1.导入镜像,查看已有镜像
[root@server1 ~]# ls
docker game2048.tar nginx.tar rhel7.tar ubuntu.tar
[root@server1 ~]# docker load -i rhel7.tar
e1f5733f050b: Loading layer 147.1MB/147.1MB
[root@server1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
game2048 latest 19299002fdbe 2 years ago 55.5MB
ubuntu latest 07c86167cdc4 3 years ago 188MB
rhel7 latest 0a3eb3fde7fd 4 years ago 140MB


2.查看原始镜像的层数
[root@server1 ~]# docker history rhel7:latest
IMAGE CREATED CREATED BY SIZE COMMENT
0a3eb3fde7fd 4 years ago 140MB Imported from

3.创建容器vm2并以bash的方式运行镜像,这样就可以在其中直接使用命令行,在容器中配置yum源
[root@server1 ~]# docker run -it --name vm2 rhel7 bash
bash-4.2# ls
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
bash-4.2# cd /etc/yum.repos.d
bash-4.2# ls
rhel7.repo
bash-4.2# vi dvd.repo
dvd.repo文件内容:
[dvd]
name=yum
baseurl=http://172.25.19.250/rhel7.3
gpgcheck=0
bash-4.2# yum repolist

4.在容器中安装httpd,会出现报错(Rpmdb checksum is invalid: dCDPT(pkg checksums): systemd-libs.x86_64 0:219-30.el7 - u),这是因为索引数据库有问题,出现这个问题时会非0退出,运行指令 rpmdb --rebuliddb,重新构建仓库即可,重新构建之后再次安装httpd
注意:联网的话可以从网上下载仓库
bash-4.2# yum install -y httpd
Skipping unreadable repository '///etc/yum.repos.d/rhel7.repo'
Rpmdb checksum is invalid: dCDPT(pkg checksums): systemd-libs.x86_64 0:219-30.el7 - u
bash-4.2# rpmdb --rebuilddb
bash-4.2# yum install -y httpd
Skipping unreadable repository '///etc/yum.repos.d/rhel7.repo'
Package httpd-2.4.6-45.el7.x86_64 already installed and latest version
Nothing to do
bash-4.2# exit

- 安装完httpd之后出现的报错


二、以dockerfile的方式构建容器
1.创建docker目录,编辑Dockerfile,编辑yum.repo文件
[root@server1 ~]# cd /tmp
[root@server1 tmp]# ls
[root@server1 tmp]# mkdir docker
[root@server1 tmp]# ls
docker
[root@server1 tmp]# cd docker/
[root@server1 docker]# ls
[root@server1 docker]# vim Dockerfile
[root@server1 docker]# vim yum.repo

Dockerfile文件的内容如下:
FROM rhel7 ##从哪一个镜像获取
COPY yum.repo /etc/yum.repos.d/yum.repo
##将宿主机的yum.repo文件复制到容器的 /etc/yum.repos.d/yum.repo 目录下
RUN rpmdb --rebuilddb && yum install -y httpd ##运行rpmdb --rebuilddb 和yum install -y httpd命令
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"] ##开启httpd服务
yum.repo文件的内容如下:
[yum]
name=yum
baseurl=http://172.25.19.250/rhel7.3
gpgcheck=0
2.构建镜像,可以看到构建镜像一共有四步,每一步都是dockerfile中写入的步骤,他会从上往下执行文件中的内容
注意构建镜像到当前目录,不能构建到/下,文件太大
[root@server1 docker]# docker build -t rhel7:v1 .


3.查看镜像,镜像的层数和构建过程中显示的一致
[root@server1 docker]# docker images
[root@server1 docker]# docker history rhel7:v1

4.删除正在运行的容器vm1,运行刚刚构建的镜像创建新的容器,并且映射本地的80端口
[root@server1 docker]# docker rm -f vm1
vm1
[root@server1 docker]# netstat -tnlp

[root@server1 docker]# docker run -d --name apache -p 80:80 rhel7:v1
f77be4feb196a2d6e24ecb65130f14593c8a64ff1548689c8ab49d3298f082fd
[root@server1 docker]# netstat -tnlp

可以在浏览器中访问宿主机的IP,这是会看到httpd的默认测试页
5.再次编辑dockerfile,编辑一个index.html的测试页
[root@server1 docker]# vim Dockerfile
[root@server1 docker]# vim index.html
[root@server1 docker]# ls
Dockerfile index.html yum.repo

dockerfile中新增加了一行:
FROM rhel7
COPY yum.repo /etc/yum.repos.d/yum.repo
RUN rpmdb --rebuilddb && yum install -y httpd
COPY index.html /var/www/html/index.html
##新增加的内容是这一行,表示将index.html文件复制为镜像的/var/www/html/index.html文件
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
6.再次构建镜像
[root@server1 docker]# docker build -t rhel7:v2 .

可以对比出和上一个镜像前两行都一样,也就是在原有的基础上叠加(这个说法可能不太准确,理解就好)
7.删除容器apache,并且在/tmp/docker目录下新建一个目录website,并将index.html文件移动到这个目录下
[root@server1 docker]# docker rm -f apache
apache
[root@server1 docker]# ls
Dockerfile index.html yum.repo
[root@server1 docker]# mkdir website
[root@server1 docker]# mv index.html website/

8.创建一个新的容器,挂载/tmp/docker/website目录,并且设置端口映射 (-v表示配置挂载)
[root@server1 docker]# docker run -d --name apache -p 80:80 -v /tmp/docker/website:/var/www/html rhel7:v2
647a50483a6cc470d43b577a454626ef787fb5aacc1969a27ce2636635b7f405

9.访问宿主机IP,可以看到index.html文件中写的内容

10.查看容器的详细信息,可以找到容器的具体挂载信息
[root@server1 docker]# docker inspect apache


11.修改index.html文件的内容,在浏览器中刷新页面可以看到发生变化
[root@server1 docker]# ls
Dockerfile website yum.repo
[root@server1 docker]# cd website/
[root@server1 website]# ls
index.html
[root@server1 website]# vim index.html


三、shell和exec的区别
- shell合适底层会直接调用/bin/sh-c执行命令,可以识别到变量
- 而exec需要写成这样的格式: ENTRYPOINT ["/bin/sh",“c”, “echo hello,$name”]
- exec格式ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时替换,但shell格式ENTRYPOINT会忽略所有CMD或docker run提供的参数
1.导入busybox的镜像,这个镜像比较小,是在这里进行验证比较适用
[root@server1 ~]# ls
busybox.tar docker game2048.tar nginx.tar rhel7.tar ubuntu.tar
[root@server1 ~]# docker load -i busybox.tar
8a788232037e: Loading layer 1.37MB/1.37MB
Loaded image: busybox:latest

2.使用shell格式编辑dockerfile
[root@server1 docker]# vim Dockerfile
文件内容:
FROM busybox
ENV name world
ENTRYPOINT echo "hello,$name"

3.构建镜像,并查看运行时显示的内容
[root@server1 docker]# docker build -t busybox:v1 .
[root@server1 docker]# docker run --rm busybox:v1
hello,world

4.使用exec格式编辑dockerfile,构建镜像运行容器,可以看到显示的内容没有识别变量
[root@server1 docker]# vim Dockerfile
文件内容:
FROM busybox
ENV name world
ENTRYPOINT ["/bin/echo", "hello,$name"]
[root@server1 docker]# docker build -t busybox:v2 .
[root@server1 docker]# docker run --rm busybox:v2
hello,$name

5.使用加了执行环境的exec格式编辑dockerfile,构建镜像,运行容器
[root@server1 docker]# vim Dockerfile
[root@server1 docker]# docker build -t busybox:v3 .
FROM busybox
ENV name world
ENTRYPOINT ["/bin/sh","c", "echo hello,$name"]
[root@server1 docker]# docker run --rm busybox:v3
hello,world

(5)使用shell+exec格式,构建镜像并运行容器,变量被识别,但是发现在运行容器的时候加上新的变量dockerfile中的CMD后的内容会被覆盖
[root@server1 docker]# vim Dockerfile
[root@server1 docker]# docker build -t busybox:v4 .
FROM busybox
ENTRYPOINT ["/bin/echo","hello"]
CMD ["world"]
[root@server1 docker]# docker run --rm busybox:v4
hello world
[root@server1 docker]# docker run --rm busybox:v4 westos
hello westos

补充:
1.docker引擎会自动分配目录,默认目录 /var/lib/docker
2.WORKDIR 类似于cd 切换目录
3.在dockerfile中cmd会被覆盖 entrpoint不会
4.运行容器时加参数(–rm )运行之后直接删除
5.env可以指定变量
6.删除镜像的时候要先删除容器(rm)再删除镜像(rmi),因为不删除容器的话镜像就相当于是在被一个进程占用,无法删除
7.在运行交互式的容器(rhel)时需要加上bash
8.在dockerfile中from后加的是镜像的名称
run 表示运行指令
copy可以将当前目录中的指定文件复制到容器中的目的路径,一定是当前目录中的文件
cmd 表示运行,在容器启动的时候运行,只能有一个
9.容器中尽管显示的是超级用户但还是会被限制的
10.docker有自己的仓库