目录
一、基于现有镜像创建
1、创建启动镜像
2、生成新镜像
二、基于本地模板创建
1、OPENVZ 下载模板
2、导入容器生成镜像
三、基于dockerfile创建
1、dockerfile结构及分层
2、联合文件系统
3、docker镜像加载原理
4、dockerfile操作常用的指令
(1)FROM指令
(2)MAINTAINER 指令
(3)RUN指令
(4)ENTRYPOINT指令
(5)CMD指令
(6)EXPOSE指令
(7)ENV指令
(8)ADD指令
(9)COPY指令
(10)VOLUME指令
(11)USER指令
(12)WORKDIR指令
(13)ONBUILD指令
(14)HEALTHCHECK
四、dockerfile构建镜像实例
1、dockerfile构建httpd实例
2、dockerfile构建sshd实例
3、dockerfile构建systemd实例
4、dockerfile构建nginx实例
一、基于现有镜像创建
1、创建启动镜像
(1)首先启动一个镜像,在容器里做修改
docker run -itd centos:7 /bin/bash
#创建并启动镜像
docker ps
#查看启动的镜像信息
2、生成新镜像
(2)将修改后的容器提交为新的镜像,需要使用该容器的 ID 号创建新镜像
docker commit -m "new-images" -a "test" dda50e36fd55 centos:test
#常用选项:
-m 说明信息;
-a 作者信息;
-p 生成过程中停止容器的运行;
docker images
#查看新生成的镜像
二、基于本地模板创建
1、OPENVZ 下载模板
通过导入操作系统模板文件可以生成镜像,模板可以从 OPENVZ 开源项目下载,下载地址为http://openvz.org/Download/template/precreated
wget http://download.openvz.org/template/precreated/debian-7.0-x86-minimal.tar.gz
2、导入容器生成镜像
cat debian-7.0-x86-minimal.tar.gz | docker import - debian:test
#查看这个模板导入到docker的debian:test镜像
三、基于dockerfile创建
1、dockerfile结构及分层
①dockerfile结构大致分为四个部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令
Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了Dockerfile,当我们需要定制自己额外的需求时,只需在Dockerfile上添加或者修改指令,重新生成 image 即可, 省去了敲命令的麻烦。
除了手动生成Docker镜像之外,可以使用Dockerfile自动生成镜像。Dockerfile是由多条的指令组成的文件,其中每条指令对应 Linux 中的一条命令,Docker 程序将读取Dockerfile 中的指令生成指定镜像
②docker镜像的结构分层:
(1)Dockerfile 中的每个指令都会创建一个新的镜像层;
(2)镜像层将被缓存和复用;
(3)当Dockerfile 的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效;
(4)某一层的镜像缓存失效,它之后的镜像层缓存都会失效;
(5)镜像层是不可变的,如果在某一层中添加一个文件,然后在下一层中删除它,则镜像中依然会包含该文件,只是这个文件在容器中不可见了不会影响在镜像中的数据。
2、联合文件系统
联合文件系统(unionFS):分层、轻量级并且高性能的文件系统,即一层一层叠加然后制作成的镜像,底层为内核加载,然后是rootfs系统,再上层是只可读的基础镜像,镜像启动后成为容器即为可读可写层此层保存数据等,然后可以再打包成一个新的镜像保存数据
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
我们下载的时候看到的一层层的就是联合文件系统。
3、docker镜像加载原理
①Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统就是UnionFS
②bootfs主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统。
③在Docker镜像的最底层是bootfs,这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs
④我们可以理解成一开始内核里什么都没有,操作一个命令下载debian,这时就会在内核上面加了一层基础镜像;再安装一个emacs,会在基础镜像上叠加一层image;接着再安装一个apache,又会在images上面再叠加一层image。最后它们看起来就像一个文件系统即容器的rootfs。在Docker的体系里把这些rootfs叫做Docker的镜像。但是,此时的每一层rootfs都是read-only的,我们此时还不能对其进行操作。当我们创建一个容器,也就是将Docker镜像进行实例化,系统会在一层或是多层read-only的rootfs之上分配一层空的read-write的rootfs。
⑤为什么容器中的centos大小只有200M
因为对于精简的OS,rootfs可以很小,只需要包含最基本的命令、工具和程序库就可以了,因为底层直接用宿主机的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。
4、dockerfile操作常用的指令
(1)FROM指令
用于指定生成新的镜像所基于的基础进项,dockerfile的第一条命令必须是FROM指定本次生成镜像是基于那个基础镜像进程的,每创建一个镜像需要一个FROM。
(2)MAINTAINER 指令
说明新镜像的维护人信息
(3)RUN指令
在所基于的镜像上执行命令,并提交到新的镜像中,例如执行yum安装等
(4)ENTRYPOINT指令
ENTRYPOINT ["要运行的程序", "参数 1", "参数 2"]
设定容器启动时第一个运行的命令及其参数,此指令为在使用docker exec 进入容器时就添加的命令参数。
可以通过使用命令docker run --entrypoint 来覆盖镜像中的ENTRYPOINT指令的内容
(5)CMD指令
CMD ["要运行的程序", "参数1", "参数2"]
此指令为指定进入容器之后的第一个命令或脚步,进入容器后在容器中的shell中执行的第一个命令,dockerfile中只能有一条CMD命令若有多条CMD则只执行最后一条命令。
如果在docker run时指定了命令或者镜像中有ENTRYPOINT指令则CMD程序不会执行。
docker RUN优先级>ENTRYPOINT指令>CMD指令
(6)EXPOSE指令
EXPOSE "端口号"
指定dockerfile生成的新镜像加载到 Docker 时要开启的端口
(7)ENV指令
ENV 环境变量 变量值
(8)ADD指令
ADD 源路径 目标路径
ADD指令用于将源文件复制到dockerfile产生的新镜像中,要求源文件必须与dockerfile在同一文件夹下,或者同一个url下。有以下注意事项:
①源路径为文件时,目标路径以/结尾则dockerfile将目标文件视为目录将源路径的文件存到模板路径的目录下,且若模板路径不存在则自动创建模板路径
②源路径为文件时,目标路径不以/结尾则dockerfile将目标路径视为文件,则直接将目标路径文件内容覆盖但名称不会改变,如果模板路径不存在则会创建一个以目标路径为名的文件,内容为源路径的文件内容
③源路径为文件夹时,若目标路径存在则直接将原路径的文件夹拷贝到模板路径的目录下。
若目标路径不存在,则自动创建一个以目标路径为名的文件夹将源文件夹拷贝到目录下。
④若源文件是个归档文件或压缩文件,docker会自动帮忙解压。URL下载和解压特性不能一起使用。任何压缩文件通过URL拷贝,都不会自动解压。
(9)COPY指令
copy 源文件/目录 目标文件/目录
只复制本地主机上的文件/目录 复制目标点为镜像中。要求本机文件必须与dockerfile在同一路径下。
ADD与copy对比:
①都有本地复制文件和目录到镜像的功能
②ADD复制归档文件和压缩文件会自动解压
③都要求与dockerfile在同一文件夹
④URL拉取目录来复制
⑤COPY只能复制本地主机文件到镜像中,ADD可以复制到url中
(10)VOLUME指令
volume ["目录"]
在容器中创建一个挂载点
(11)USER指令
USER 用户名/uid
指定运行容器时的用户
(12)WORKDIR指令
为后续的RUN/CMD/ENTRYPOINT指定工作目录,可以理解为切换到指定的目录执行RUN等其他指令。
(13)ONBUILD指令
指定所生成的镜像作为一个基础镜像时所要允许的命令,调用有ONBUILD命令时的镜像会先执行ONBUILD命令。在使用其他镜像时,仔细检查ONBUILD命令的内容。
当在一个Dockerfile文件中加上ONBUILD指令,该指令对利用该Dockerfile构建镜像(比如为A镜像)不会产生任何实质性影响。 但是当编写一个新的Dockerfile文件来基于A镜像构建一个镜像(比如为B镜像)时,这时构造A镜像的Dockerfile文件中的ONBUILD指令就生效了,在构建B镜像的过程中,首先会执行ONBUILD指令指定的指令,然后才会执行其它指令。
(14)HEALTHCHECK
健康检查
四、dockerfile构建镜像实例
1、dockerfile构建httpd实例
mkdir /opt/apache
cd /opt/apache
#创建并进入文件夹,每个服务一个文件夹
vim Dockerfile
#创建Dockerfile文件,文件内容如下
FROM centos:7
#基于的基础镜像指定为centos:7,注意本机要有此基础镜像
MAINTAINER this is apache image <test>
#说明镜像维护人信息为,指定用户为test
RUN yum -y update
RUN yum -y install httpd
#镜像RUN指令指定启动容器后的运行命令,yum安装update和httpd服务
EXPOSE 80
#开启80端口
ADD index.html /var/www/html/index.html
#复制宿主机index.html文件到容器的 /var/www/html/index.html
ENTRYPOINT ["/usr/sbin/apachectl"]
CMD ["-D","FOREGROUND"]
#使用前台启动apache注意使用绝对路径,如果后台启动,启动完shell就结束了容器就结束了,保存退出。
echo "this is test web">index.thml
#准备网站的网页,注意必须在和Dockerfile文件相同的目录
docker build -t httpd:centos .
#将dockerfile 文件生成镜像注意最后有个点。
docker run -d -p 40330:80 httpd:centos
#新镜像运行容器,映射宿主机的40330端口为容器的80端口
访问192.168.30.11:40330 进行测试是否可以访问容器的httpd主业
2、dockerfile构建sshd实例
FROM centos:7
#指定sshd基于centos:7的镜像
MAINTAINER this is ssh image <ssh>
#说明镜像信息,镜像用户为ssh
RUN yum -y update
#运行RUN指令执行update更新
RUN yum -y install openssh* net-tools lsof telnet passwd
#RUN指令执行安装openssh相关工具,net工具,lsof、telnet、passwd程序
RUN echo "abc123" |passwd --stdin root
#免交互设置root密码为abc123
RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config
#关闭sshd服务的pam认证
RUN sed -i '12d' /etc/pam.d/sshd
#删除/etc/pam.d/sshd的12行,删除12行为取消pam的限制
RUN ssh-keygen -t rsa -A
#生成秘钥认证文件
RUN mkdir -p /root/.ssh && chown root.root /root && chmod 700 /root/.ssh
#递归创建/root/.ssh文件夹并修改属主属租为root,添加权限为700只允许属组属组用户操作
EXPOSE 22
#规定端口为22
ENTRYPOINT [ "/usr/sbin/sshd" ]
CMD ["-D", "FOREGROUND"]
#/usr/sbin/sshd -D用于前台启动sshd服务
docker build -t sshd:centos .
#创建sshd;centos镜像
docker run -d -p 40022:22 sshd:centos
#运行sshd:centos容器并映射容器中的22端口为40022端口
docker ps
#查看容器信息
ssh localhost -p 40022
ifconfig
#宿主机执行验证sshd容器
3、dockerfile构建systemd实例
mkdir /opt/systemctl
cd /opt/systemctl
#创建systemd目录
vim Dockerfile
#编辑Dockerfile文件内容如下
FROM sshd:centos
#以sshd:centos为基础镜像,注意要做上面的sshd实例,不然无此进项不能制作systemd镜像
MAINTAINER this is systemctl image <systemd>
ENV container docker
#除了systemd-tmpfiles-setup.service,删除其它所有文件
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i;done); \
rm -f /lib/systemd/system/multi-user.target.wants/*; \
rm -f /etc/systemd/system/*.wants/*; \
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target. wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
docker build -t systemd:centos
#生成systemd镜像
docker run --privileged -d -P -v /sys/fs/cgroup:/sys/fs/cgroup:ro systemd:centos /sbin/init
#启动容器,并挂载宿主机目录挂载到容器中,和进行初始化
#--privileged:使container内的root拥有真正的root权限。否则,container内的root只是外部的一个普通用户权限。
docker ps -a
docker exec -it 56b06afcef9a /bin/bash
#进入容器
systemctl start sshd
systemctl status sshd
4、dockerfile构建nginx实例
mkdir /opt/nginx
cd /opt/nginx/
cp /opt/nginx-1.12.0.tar.gz /opt/nginx
#创建nginx目录,将nginx安装包放到创建的nginx目录下,必须与Dockerfile文件在同一目录下
vim Dockerfile
#编辑nginx的dockerfile文件内容如下
FROM centos:7
#基于基础镜像,centos
MAINTAINER this is nginx image <nginx>
#用户信息,镜像维护用户为nginx
RUN yum -y update
RUN yum -y install pcre-devel zlib-devel gcc gcc-C++ make
RUN useradd -M -s /sbin/ nologin nginx
#安装编译安装工具
ADD nginx-1.12.0.tar.gz /opt/
#上传nginx软件压缩包,docker自动解压
WORKDIR /opt/nginx-1.12.0
RUN ./ configure \
--prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_stub_status_module && make && make install
ENV PATH /usr/local/nginx/sbin:$PATH
#指定工作目录
EXPOSE 80
EXPOSE 443
#指定http和https端口
RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf
#关闭nginx 在后台运行
ADD run.sh /run.sh
RUN chmod 755 /run.sh
CMD ["/run.sh"]
#添加宿主机中run.sh到容器中
vim run.sh
#创建run.sh脚本,注意必须和dockerfile在同一路径下,内容如下
#!/bin/bash
/usr/local/nginx/sbin/nginx
docker build -t nginx:centos
docker run -itd -P nginx:centos /bin/bash
docker ps -a
#查看nginx容器,访问80对应的随机端口验证,443的端口验证不了,ngingx中每家ssl模块
http://192.168.30.11:32769