生成镜像的方法:
A . 从container生成
方法1. # docker commit <container> 这是把container的变更,提交给新image
方法2. # docker export <container> > tarball
# cat tarball | docker import - <image> 同1
B. 从image生成
方法1. # docker save -o tarball registry/reposiry/image 这是从registry的db到本地FS文件
modify the tarball
docker load -i tarball 这是从本地FS文件装在镜像,到本地image的db
C. 从Dockerfile生成
1. 和A,B比,优点: 可追踪image的定义,可升级image中软件版本、几乎不消耗存储、通过阅读Dockerfile代替docker inspect来检视镜像/container的内容
2. 命令: docker build -t <image_name> [-f Dockerfile] <构建目录> [options]
不指定-f选项时,在当前目录下自动搜索Dockerfile。 指定-f选项时,需要是构建目录的相对路径,且位于构建目录的子目录内
3. 原理:
docker build命令是传令官;
构建目录(一般是当前目录 . )下所有内容是build镜像的素材, 由docker build传给docker daemon,存在/var/lib/docker下------
如果要排除一些文件、目录不传给docker daemon,就把它们列入构建目录下的.dockerignore文件
Dockerfile里每一行是docker daemon执行的指令;
docker damon是真正执行build镜像的工人。
这些被执行的命令是在build 镜像是执行的
每执行一个Dockerfile的命令,生成一个中间镜像,和数据缓存;下次再docker build时,会重用最后一条没有改变过的指令的中间层容器,来节省时间------
如果要不留中间层容器:docker build --force-rm=true
如果要从头build不使用缓存和中间层:docker build --no-cache=true
4. 镜像的定制基于哪些素材:
a. 基础镜像 -- 由FROM命令指定,本地有优先用本地的,没有就去registry拉取;强制拉取的选项是 --pull=true
FROM 永远的底格指令
b. 文件素材 -- 须位于构建目录之下
ADD / COPY 不会使用docker build生成的临时层,而是检索docker build传给docker daemon的“文件系统”。
ADD <相对Dockerfile的目录路径> <去往容器的文件的绝对路径>
c. 通信接口 -- 端口
EXPOSE 暴露容器内端口。这个端口可以用于容器连接,或者影射给主机的socket,映射关系可以由docker port察看,宿主机docker-proxy监听宿主机的映射端口(netstat -tupln)。
映射给主机指定的socket地址: docker run -p <主机ip:主机端口>:<被暴露的容器端口>。 主机IP默认是0.0.0.0
映射给主机随机的随机的端口: docker run -P <被暴露的容器端口>
容器连接
d. 修改基础镜像
RUN 比如创建文件、安装软件
e. 修改后续的build镜像的环境变量
ENV <key>=<value> 可以在docker run 时由选项-e <key>=<value> 覆盖
f. 自定义键值,作为镜像的标签
LABEL <key>=<value> 可以一行定义多个,用空格分开,这样避免多个容器层被创建。
LABEL的key的定义没有限制,但推荐使用开发者可控域名的反向顺序的DNS格式:比如: LABEL net.linuxtoys.mylabel=xxx
容器的LABEL可以用docker inspect检视,也可以用docker ps -a --filter “label=<key>=<value>”来筛选容器
也可以用docker images --filter “label=<key>=<value>”来筛选镜像
g. 景象启动时的默认命令
ENTRYPOINT 默认的运行命令,可以在docker run 时由选项--entrypoint="xxx" 覆盖
CMD 默认的ENTRYPOINT的运行参数,可以在docker run时 由 最后的参数覆盖
基于Dockerfile设计容器的原则
1. 一个容器只干一件事
容器连接或K8S编排,实现共享服务
2. 让构建目录尽可能小,否则用.dockerignore文件排除不想包含的文件
目的是减少传递构建目录给docker daemon的时间,也节省/var/lib/docker的空间
3. 高效合理地组织Dockerfile的RUN命令
一行生成一个中间层。
所以,多命令在一行,可以节省空间。但是其中任何命令失败了,下次build还得全部build这一行,浪费时间。
其实合理组织RUN命令,是Docker镜像合理分层的手段。Docker镜像是一种特殊的FS:Union FS,是一系列中间层叠加在基础镜像(也是之前叠加产物)上的结果。docker pull 拉取的,实际是本地已有镜像之上的叠加层。所以Dockerfile的RUN命令,不仅影响开发,也影响拉取使用的效率。
4. ENTRYPOINT命令最先去做清理工作,比如删除上次kill/stop时僵死的进程.pid文件
5. 最佳实践
https://docs.docker.com/engine/reference/builder/
https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
容器开发和运行环境的种类
1. 运行在VirtualBox、KVM上的虚拟机镜像Vagrant,它已经配置好了Docker、K8S等容器开发运行需要的软件(CDK3.9 )
https://developers.redhat.com/products/cdk/download
https://access.redhat.com/downloads/content/293/ver=3.9/rhel---7/3.9/x86_64/product-software
https://access.redhat.com/documentation/en-us/red_hat_container_development_kit/3.9/
2. 运行于Openshift之上 (K8S的包装)
1) 开发者专用的上游项目--容器内的Openshift-- Openshift Origin。 搭建
step1. install redhat7
step2. install docker、kubernetes、etcd
step3. 配置K8S集群
step4. 禁用SELinux
step5. 信任docker registry
step6. 启动docker服务
step7. 拉取、运行Opeshift/origin容器
step8. 打开后台运行的Origin容器的Bash Shell
Step9. 纯Openshift操作,建立项目、app(也就是容器镜像)、pods(启动容器)
2)Ansible搭建的Openshift (NNIT ENET用的),即K8S集群
3)基于AWS、GCE的Openshift