Docker Image简单说明:含有启动容器所需要的内核和文件系统。
采用【分层构建】机制,最底层为bootfs,之上为rootfs
bootfs:是引导系统的文件系统。包含bootloader和kernel,容器启动完后,宿主机(docker deamon进程所在的机器)的会从内存中卸载掉bootfs,以节约资源。
从下图可以看处来,bootfs层使用了aufs或者btrfs文件系统。
rootfs:位于bootfs之上,表现为docker容器的根文件系统。从下图可以看出来,rootfs给我们提供了基本的根文件系统(/bin, /var, /usr等)。
- 传统模式中,系统启动时,内核挂载rootfs时会首先将其挂载为只读模式,完整性自检完成后将其重新挂载为读写模式。
- docker中,rootfs由内核挂载为只读模式,而后通过【联合挂载】技术额外挂载一个【可写】层。
docker image layer:
- 下图深蓝色的镜像都称为父镜像(parent image),深蓝色最下层是基础镜像(Base Image)
- 最上层的浅蓝色层为【可读写】层,它之下都是【只读】层。
例子:要在Debian内核上搭建一个apache环境的话:
- 先去找一个纯净的最小的Debian image
- 让后再在Debian image上面,堆上一个编辑器软件 image(Emacs,或者vim)
- 然后在Emacs image上再堆上一个apache image
启动关联:当要启动apache image时,必须要先启动Debian image,再启动Emacs image。
当某个容器启动后,产生的临时文件,怎么处理?
不是docker的apache 启动后,产生的临时文件一般放在/var下。但是既然是docker了,apache产生的临时文件就不可以写入Debian image的/var目录下了。理由是,这些深蓝色的image层都是只读的,并且这些深蓝色image层也会让别的软件共同使用,所以产生的临时文件就写到了浅蓝色的apache container层了。
当执行了docker container rm
容器后,保存在apache container层里的临时文件也一并被删除了。
docker 的【分层构建,联合挂载】功能,需要由专有的文件系统支撑。
aufs:advanced-multi-layered unification filesystem(高级多层统一文件系统)
被用于实现docker的【联合挂载】功能。
aufs包装了UnionFS,2006年由日本人Junjiro Okajima开发。但由于UnionFS本身就不好,所以aufs也很臃肿,导致linux本人一直没有同意把aufs加入到linux的内核里。
docker最初使用aufs作为容器文件系统层,目前也支持。
aufs的竞争产品是overlayfs,后者从3.18版本开始被加入到linux内核。
docker的分层镜像,除了aufs,还支持btrfs,vfs,devicemapper等
新版本的docker使用的是:overlay2(抽象2级文件系统,必须建立在某个文件系统上)
Storage Driver: overlay2 Backing Filesystem: xfs
docker registry:
启动容器时,docker daemon进程会试图从本地获取相关的镜像,但当本地镜像不存在时,将从Registry(默认的registry 就是docker hub)中下载该镜像并保存到本地。
如果启动容器时,只指定镜像和tag的话,就默认去找docker hub。除非你指定了registry的ip地址。
public docker registry:默认就是docker hub。
private docker registry:是自己创建的registry服务。自己创建也不麻烦,可以使用由VMware提供的开源
harbor
,来创建自己的registry服务。一般docker hub上的镜像,比如nginx,拿过来是用不了的,因为配置都不一样。所以项目上一般都是自己打成镜像。
Sponsor Registry:第三方的Registry,供客户和docker社区使用
Mirror Registry:第三方的registry,比如阿里的Registry
Vendor Registry:由发布docker镜像的供应商提供的Registry。比如redhat给自己操作系统提供的镜像。
docker registry包含repository和index
- repository:docker镜像的所有迭代版本组成的镜像仓库。一个registry中可以有多个repository。
- repository又分为:
- 顶层仓库:直接用image:tag来表示,比如,redis:5。
- 用户仓库:用户名/仓库名来表示,比如,user1/redis:5.
- 每个仓库可以包含多个tag(标签)。
- repository又分为:
- index
- 维护用户账户,镜像的校验以及公共命名空间的信息。
- 相当于为registry提供了一个完成用户认证等功能的检索接口。
实际项目开发时,对docker的运用流程:
开发人员从docker hub上,下载要使用的镜像,然后再修改它后,放入到自己公司的私有registry上;后来再由运维人员做各种环境的部署。
cloud native(云原生)大致意思:
比如从docker hub上下个redis,redis的配置文件是需要定制的,我总不能因为要改个配置文件,而从新打包个redis镜像,所以redis配置文件的就不能写死在redis镜像里了,而是通过读取系统的环境变量,来生成配置文件。这样一来,在启动redis容器时,就可以把你自己的配置,通过环境变量的方式传递给redis镜像,从而达到修改配置文件的目的。
docker hub功能介绍:
- Image Repository:自己的私有docker image 仓库。一般用法:从docker hub上拉一个image,然后修改,再推到这里。
- automated builders:自动构建image,当监听到github上的 dockerfile文件发生变化后,自动构建image。
- webhooks:是automated builders里的功能之一,当你成功提交image到自己的docker hub后,调用这个钩子。
- organizations:创建一个工作组。
- github and bitbucket intergration:和github,bitbucket集成使用。
如何从docker hub以外的registry上下载image呢?
# docker pull [:port]/[]:
当从https://quay.io/ 上下载image时,使用下面的命令:
# docker pull quya.io/coreos/flannel::v0.11.0-arm64
这里省略了port,默认的port是443(https协议的端口号)。
coreos是用户仓库。比如,user1/redis:5.
下载完成后,使用docker image ls
查看的结果:发现多了【quay.io】的前缀,说明是从quay.io上下载的image,而不是从docker hub上下载的image。
REPOSITORY TAG IMAGE ID SIZE
quay.io/coreos/flannel v0.11.0-arm64 32ffa9fadfd7 53.5MB
namespace用法:
namespace examples organization:组织 redhat/k8s, google/k8s login(user name):用户名 user1/app, user2/app role:角色 devel/app, test/app, prod/app
制作自己的image的方法:
1,使用dockerfile
制作
2,基于容器制作
3,基于docker hub的automated builds功能制作
基于容器制作image
容器启动后,把发生了变化的内容,打成一个image。
命令用法:
# docker container commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
OPTIONS:
Options:
-a, --author string Author (e.g., "John Hannibal Smith ")
-c, --change list Apply Dockerfile instruction to the created image
-m, --message string Commit message
-p, --pause Pause container during commit (default true)
举例:先下载一个busybox image,然后在里面添加一个/data/html/index.html文件,文件内容:【welcome to busybox!!】执行docker container rm
,再执行docker container run
busybox后,发现刚才创建的/data/html/index.html文件没有了,所以可以得知,没有commit的修改再下次启动后,就没有了。
创建完/data/html/index.html文件后,为了防止在commit的过程中某些东西又产生了改动,指定-p
选项,告诉docker先把container暂停一下,那么我们先commit(docker container commit -p bb1)一次,不指定repository和tags看看效果,用docker image ls
查看,发现多了一行none的一行。
REPOSITORY TAG IMAGE ID SIZE
1e7b9d544ff6 1.22MB
说明image成功了,但是没有repository和tag,只有个image id。
下面通过使用docker tag
命令把只有image id的image加上repository和tag
# docker tag 1e7b9d544ff6 ys/busybox:local1
执行结果查看(docker image ls):repository和tag都添加上了。
REPOSITORY TAG IMAGE ID SIZE
ys/busybox local1 1e7b9d544ff6 1.22MB
可以再一个tag:docker tag ys/busybox:local1 ys/busybox:local2
结果如下:image id是相同的,所以是同一个image(镜像),只是tag不同,版本相同。
REPOSITORY TAG IMAGE ID SIZE
ys/busybox local1 1e7b9d544ff6 1.22MB
ys/busybox local2 1e7b9d544ff6 1.22MB
tag命令用法:
# docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
检查一下commit后的image里是否有/data/html/index.html文件,先终止container(docker container rm),再run,发现里面有/data/html/index.html文件,说明commit成功了。
删除一个tag看看,tag只是某个image的引用,删除掉一个tag,如果还有别tag指向这个同一个image,则image还是不会被删除的。tag和linux里的硬链接差不多。当然tag的主要作用还是表示同一个image的不同版本,所以一般每个tag对应的image id都是不同的。
到此为止,我们只是在原来的image里添加了一些文件,如果我想改变image启动时默认的运行程序呢?这就需要用到-c
选项了。
比如我让image启动后运行的命令为httpd
。注意CMD都是大写。-f
是让httpd在前台运行,-h
指定html的路径。
# docker container commit -a "ys " -c 'CMD ["/bin/httpd","-f","-h","data/html"]' -p bb1 ys/busybox:local3
然后启动ys/busybox:local3,用docker inspect bb1
查看CMD变成了:
"Cmd": [
"/bin/httpd",
"-f",
"-h",
"data/html"
],
发现IP是172.17.0.2,所以运行curl 172.17.0.2
后,在控制台打印出来的就是【welcome to busybox!!】。
测试完我们自己打的image没有问题了,想把这个image传到registry上的话,怎么办呢?
比如传到docker hub上。
首先你先申请一个docker hub账户。比如docker hub账户名是ys。
在docker hub上创建一个repository,repository的名字必须和你在本地用docker container commit是指定的名字一样才行。
在终端登录到docker hub,使用命令
docker login
,不指定[SERVER]的话,就是登录到docker hub。# docker login [OPTIONS] [SERVER] Options: -p, --password string Password --password-stdin Take the password from stdin -u, --username string Username
用docker image ls,确保你本地的repository的名字和你在docker hub上创建的repository的名字一样。
用
docker image push [OPTIONS] NAME[:TAG]
,把本地的image,推送到docker hub上。# docker image push ys/busybox:v0.1
执行上面的命令后,在你的docker hub上创建的ys里的tags里就有了v0.1了。
如果不指定tag,则把本地所有的tags都推送到docker hub上。
退出登录:
docker logout
比如把制作好的image,上传到阿里的registry上。
- 首先你先申请一个阿里云账户。
- 创建【命名空间】和【仓库名称】。
- 点击创建好的仓库行最后的【管理】,安装里面的说明操作就可以了。
需求:在一台机器A上打了个image,机器B也想用。可以,通过阿里云或者docker hub中转一下,下载到机器B上,但是这样比较麻烦。所以需要使用轻量的方法。
步骤1:机器A,使用docker save把image压缩成一个文件。
Usage: docker image save [OPTIONS] IMAGE [IMAGE...] Save one or more images to a tar archive (streamed to STDOUT by default) Options: -o, --output string Write to a file, instead of STDOUT
例子:把本机的redis镜像保存成test.gz。把这个test.gz发给机器B。
# docker image save -o test.gz redis:5
步骤2:机器B,使用docker load把从机器A得到的压缩后的文件,存储成image文件。
Usage: docker image load [OPTIONS] Load an image from a tar archive or STDIN Options: -i, --input string Read from tar archive file, instead of STDIN -q, --quiet Suppress the load output
例子:把机器A传过来的test.gz,做成image文件。
# docker image load -i test.gz