容器系列之docker镜像管理
1.Docker Images
docker镜像含有启动容器所需要的文件系统及其内容,因此,其用于创建并启动docker容器采用分层构建机制,最底层为bootfs,其之为rootfs
- bootfs: 用于系统引导的文件系统,包括bootloader和kernel,容器启动完成后会被卸载以节约内存资源
- rootfs: 位于bootfs之上,表现为docker容器的根文件系统
传统模式中,系统启动之时,内核挂载rootfs时会首先将其挂载为“只读”模式,完整性自检完成后将其重新挂载为读写模式docker中,rootfs由内核挂载为“只读”模式,而后通过"联合挂载“技术额外挂载一个”可写“层
[root@node1 ~]# docker exec -it web1 /bin/sh #拥有完整意义上的文件系统 / # ls bin etc lib mnt root sbin sys usr dev home media proc run srv tmp var
2.Docker Image Layer
- 位于下层的镜像为父镜像(parent image),最底层的称为基础镜像(base image)
- 最上层为"可读写”层,其下的均来"只读“层
描述:如apache镜像可能在一个很底层的系统镜像之上,底层镜像可能是了小化的发行版本,再向上添加一软件可其他,每添加一个都是独立的层,底下的bootfs引导完rootfs后被卸载,并不是删除文件,是在内存中被移除掉它,真正被运行有三层Base image,image,image,其中base image通常用于构成一个系统的基本构成,如果需要使用到额外的工具就在上面执行安装操作,如最小化安装centos,要使用vim直接使用yum就可以了。
对于底层的镜像本来就是最小化安装,是不会动的,去安装一个vim是会这个镜像基础上新的生成一个层次,再安装一个nginx,就会再生成一层。启动时,先从底层开始启动,一层层的挂载,从下到上操作,是层加在一起所以是联合挂载。
其中只有最顶层才是可写的,下面的层次都是只读,删除了容器,可读写层是会被删除的。
Aufs
- advanced multi-layered unification filesystem: 高级多层统一文件系统
- 用于为Linux文件系统实现"联合挂载”
- aufs是之前的UnionFS的重新实现,2006年由Junjiro Okajinma开发(3万行代码,很烂,ext4之类只是几千行代码,因为代码要整合到内核中使用)
- Dokcer是最初使用aufs作为容器文件系统层,它目前仍作为存储后端之一来支持
- aufs竞争产品是overlayfs(叠加),后者自从3.18版本开始被合并到Linux内核(centos使用是3.10版本,可以向内核打补丁,可以基于它的稳定发酵的基础上制作模块,单独的rpm包,load上去安装)
- docker的分层镜像,除子aufs,docker还支持btfs,devicemapper和vfs等
- 在Ubuntu系统下,docker默认Ubuntu的utfs,而在Centos7上,用的是devicemapper
注:devicemapper叫dm是redhat领头来维持的一个模块,有人测试不太稳定,不适用
3.Docker Registry
- 启动容器时,docker daemon会试图从本地获取相关的镜像,本地镜像不存在时,其将registry(没有特别指定是docker hub,
如果要指定其它的路径,就要在镜像的访问路径中提供服务器地址)中下载镜像并保存到本地,为了安全docker daemon要求registry必需是https,如果必须配置它不安全,但是可以使用
4.Docker Registry分类
- Registry用于保存docker镜像,包括镜像的层次结构和元数据
- 用户可自建Registry,也可使用官方docker hub
- 分类
Sponsor Registry: 第三方的registry,供客户和Docker社区使用
Mirrot Registry: 第三方的registry,只让客户使用
Vendor Registry: 由发布Docker镜像的供应商提供的Registry
Private Registry: 通过设有防火墙和额外的安全层的私有实体提供的registry
5.Registry(repository and incex)
Repository
- 由某特定的docker镜像的所有迭代版本组成的镜像仓库
- 一个Registry中可以存在多个Repository
Repository可分为"顶层仓库“和“用户仓库”
用户仓库名称格式为"用户名/仓库名"
- 每个仓库可以包含多个Tag(标签),每个标签对应一个镜像(一个镜像可有多个tag,但是一个tag只属于一个镜像)
index
- 维护用户账户、镜像的检验以及公共命名空间的信息
- 相当于为Registry提供一个完成用户认证等功能检索接口
6.Docker Registry镜像来源
- Docker Registry中的镜像通常是由开发人员制作,而后推送至”公共“或"私有”registry上保存,供其他人员使用,例如"部署“到生产环境
cloud native
描述:程序员写程序应该是针对某个开发环境所写的,如写C程序应该是针对C环境,特别是系统级的开发应该是针对系统的库,编程接口,写的C程序调用的系统库,或者是自行补进的第三方库中的库文件,去生成代码,代码就可以运行在系统级环境上,这叫做系统源生,云源生就是面向云环境中运行的程序而调用云系统本身即有的功能来开发程序,为了云计算环境运行而生的,明显开发在单机之上的应用程序如nginx,如果托管到容器云上云运行,有很多不方便的地方,如修改配置文件,而且云开发的程序会使用对云计算怎么配置更加方便,使用那种配置接口来提供所谓的配置逻辑,而容器本来就加了一层外壳,去操作里面的数据时很不方便。
早期的解决方案是向容器起动时来传环境变量来传入信息,配置文件应该是容器启动时,从环境变量加载自动注入到配置文件中所生成的,但是nginx很少说能通过注入环境变量来生成,所以不太适合云源生。云源生是通过大量环境变量注入生成配置文件的。
base image
描述:最小化的底层基础镜像是docker hub的维护人员手动制作的,并打包成镜像格式
7.Docker Hub
- Image Repositories
- Automated Builds
自动构建,早期时做镜像,在本地docker build使用dockerfile来制作,也可以基于容器来做,在可写层已经做了很多的改动,可以把它做成一个image,自动时可以把dockerfile文件存放到automated builds中,由docker hub自动做,自动构建是联动的方式实现的,先在github中创建一个项目,里面存放的就是dockerfile,github仓库可以与docker hub仓库建立关联关系,docker hub仓库可以持续的监控github的仓库,dockerfile一push上github里就会自动的制作成镜像,并Push到docker hub中。如果要创建新的镜像可以在开发环境的主机上修改dockerfile后,push到github上,docker hub会知道它的
变成自动拖到docker hub的仓库中
- Webhooks
- Organizations
- GitHub and Bitbucket Itegration
8.获取镜像
docker pull <registry>[:<port>]/[<namespace>/]<name>:<tag> namespace就是那个用户的仓库 著名的镜像仓库:https://quay.io/ [root@node1 ~]# docker pull quay.io/coreos/flannel:v0.10.0-amd64 #指定服务器地址(端口默认443)/用户名/仓库名,再加冒号镜像名,不加是latest
9.镜像相互操作
镜像的生成途径
- dockerfile
- 基于容器制作
- docker hub automated builds
10.基于容器制作镜像
例如:把busybox的镜像,加一个data/html的目录,加的结果做成一个镜像
[root@node1 ~]# docker run --name b1 -it busybox / # mkdir -p /data/html / # echo dockerbusybox > /data/html/index.html [root@node1 ~]# docker commit -p b1 #上一个窗口不能退出,使用commit,p是中止,以防做时有人写入 sha256:d4d7fb7f7a8b53a8c6c3d4f2bf7e9940706d294bac23f5a464c67dea5a11cbb1 [root@node1 ~]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> d4d7fb7f7a8b About a minute ago 1.16MB [root@node1 ~]# docker tag d4d7fb7f7a8b reid/httpd:v0.1-1 #因为之前没有任何标签只能使用id来指定镜像,reid是docker hub上的一个账户 [root@node1 ~]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE reid/httpd v0.1-1 d4d7fb7f7a8b 15 minutes ago 1.16MB [root@node1 ~]# docker tag reid/httpd:v0.1-1 reid/httpd:latest #打第二个标签 [root@node1 ~]# docker image rm reid/httpd:v0.1-1 #删除标签,如同删除硬链接 Untagged: reid/httpd:v0.1-1
11.制作镜像同时打tag
描述:镜像定义窗口启动时默认要启动的程序,如果希望在创建镜像时,改变原来的默认的运行命令
[root@node1 ~]# docker inspect busybox|grep -A 5 Cmd "Cmd": [ "/bin/sh", 默认使用什么命令 "-c", "#(nop) ", "CMD [\"sh\"]" [root@node1 ~]# docker run --name t1 -it reid/httpd:v0.1-1 / # ls /data/ html [root@node1 ~]# docker commit -a "reid" -c 'CMD ["/bin/httpd","-f","-h","/data/html"]' -p b1 reid/httpd:v0.2 sha256:4f752241c109d0c1932cf2d0c3583d8c69d40606d97e58db24b0fefec8c9d555 注:-a作者信息,-c修改默认启动命令,-p制作时中止容器,基于b1制作,新的名称reid/httpd:v0.2 [root@node1 ~]# docker run --name t2 reid/httpd:v0.2 [root@node1 ~]# docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d7b4764d05a6 reid/httpd:v0.2 "/bin/httpd -f -h /d…" 25 seconds ago Up 23 seconds t2 [root@node1 ~]# docker inspect t2|grep IPAddress "SecondaryIPAddresses": null, "IPAddress": "172.17.0.6", "IPAddress": "172.17.0.6", [root@node1 ~]# curl 172.17.0.6 dockerbusybox
12.把镜像推送到docker hub
先在https://hub.docker.com/注册账号 --》 create repository --> 输入名称,如reid/httpd 本地和仓库的名称要保持一致
先登录
先登录 [root@node1 ~]# docker login -u docker42 Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded [root@node1 ~]# docker tag reid/httpd:v0.1-1 docker422018/httpd:v0.1-1 [root@node1 ~]# docker push docker42/httpd The push refers to repository [docker.io/docker422018/httpd] 4174c2b2e1e5: Pushed f9d9e4e6e2f0: Mounted from library/busybox v0.1-1: digest: sha256:635deb0c34604c2c5f40284793453b92c5f4b2b9a2b18a1fe33d33430bde06df size: 734 [root@node1 ~]# docker logout Removing login credentials for https://index.docker.io/v1/
13.镜像导入和导出
[root@node1 ~]# docker save -o myimages.gz reid/httpd:v0.1-1 reid/httpd:latest #-o压缩,可以接多个镜像 [root@node1 ~]# ls myimages.gz myimages.gz [root@node2 ~]# docker load -i myimages.gz #当使用docker run时,本地没有镜像还是会去下载 [root@node1 ~]# docker image ls