容器 export和import tar rootfs 自己做跟rootfs作为容器base

1  概述

镜像包含启动容器所需的文件系统和内容,可以理解为打包的文件,用于创建并启动docker容器。

镜像的生成途径有三个:

1.基于dockerfile实现,镜像制作的程序文件

2.基于容器实现,启动容器后,将新的操作制作为新镜像

3.基于当前系统制作docker镜像    见文章末

4.docker hub automated builds【

Set up Automated Builds | Docker Documentation

自动化构建,就是使用docker hub连接一个包含dockerfile文件的github仓库或者bitbucket仓库,docker hub则会自动构建镜像,通过这种方式构建出来的镜像会被标记为automated build,也称之为受信构建(trusted build),这种构建方式构建出来的镜像,其他人在使用时可以自由的查看dockerfile内容,知道该镜像是怎么来的,同时,由于构建过程是自动的,所以能够确保仓库中的镜像都是最新的。具体构建步骤如下:

添加仓库

首先登录到docker hub,点击右上角的create,然后选择create automated build

则新进入到的页面,选择link account按钮,然后,选择连接github,在连接方式选择页面,我们选择第一种连接方式

选择完成后,按照引导登录github,完成授权操作,授权完成

构建镜像

授权完成后,再次点击右上角的create按钮,选择create automated build,在打开的页面中选择github

这里展示了刚刚关联的github上的仓库,只有一个docker,然后点击进去

填入镜像的名字以及描述,然后点击create按钮

如此之后,我们的镜像就算构建成功了,一旦github仓库中的dockerfile文件有更新,docker hub上的镜像构建就会被自动触发,不用人工干预,从而保证镜像始终都是最新的。

接下来,用户可以通过如下命令获取镜像:docker pull wuboMichael/helloworld

获取到镜像之后,再运行即可。

镜像文件采用分层构建机制,最底层为bootfs,上面为rootfs,rootfs上还可以有多层。位于最下层的镜像文件为父镜像(parent image),最底层为基础镜像(base image,rootfs为这一层,这一层必须存在).最上层为“可读写”层,其下的均为“只读”层

其中:

bootfs:用于系统引导的文件系统,包含bootloader和kernel,容器启动完成后会被卸载以节约内存资源,可以理解为容器引擎,不是宿主机操作系统

rootfs:位于bootfs之上,表现为docker容器的根文件系统;

传统模式中,系统启动时,内核挂载rootfs时会首先将其挂载为只读模式,完整性自检完成后将其重新挂载为读写模式

docker中,rootfs由内核挂载为只读模式,而后通过“联合挂载”技术额外挂载一个“可写”层。联合挂载,需要文件系统支持,目前支持最好的文件系统为Aufs(advanced multi-layered unification filesystem),高级多层统一文件系统,用于为linux文件系统实现”联合挂载“,docker 最初使用aufs作为容器文件系统层,目前还作为存储后端之一来支持,目前没有基层到linux内核,需要对内核打补丁才能使用aufs。docker的分层镜像,除了aufs,还支持btrfs,devicemapper和vfs。在ubuntu系统下,docker默认支持ubuntu的aufs,这也是为什么很多底层镜像都是ubuntu的原因,因为ubuntu更好的支持aufs.而centos7用的是devicemapper.但是,devicemapper在性能上有问题。linux 在3.18版本后把overlayfs整合到内核里,docker-ce目前在centos7上支持的文件系统为overlay,使用overlay作为docker的后端存储机制,如果是按照extras源里的docker包,版本1.12,后端的存储为devicemapper文件系统

2  Regeistry介绍

Registry用于保存docker镜像,包括镜像的层次结构和元数据,Registry由Repository和Index两个组件组成

启动镜像时,docker daemon会试图从本地获取相关的镜像,本地镜像不存在时,将从registry中下载该镜像并保存到本地。

registry是一个无状态,高可扩展的服务端应用程序,可以用于存储和分发docker 镜像。docker 的registry里,index是一个重要组件,让用户可以查询搜索到相关的镜像,同时index支持认证功能。

registry分为两种:

公共的registry,如docker hub,

私有化docker registry,自己搭建的registry。

通过应用程序包docker-distribution.x86_64 来实现私有registry搭建,在extras仓库中。这个软件没有web页面,也不支持认证。可以通过nginx配置反代,在nginx上实现认证

或者通过harbor这个软件才实现私有化仓库搭建,这个软件有vmware公司维护,企业级的容器registry,是在docker-distribution基础上添加功能实现的。建议用harbor创建私有registry(仓库)。

3  Repository介绍

Repository是指由某特定的docker镜像的所有迭代版本组成的镜像仓库,一个Registry内部有多个Repository.其中,Repository可风味“顶层仓库”和“用户仓库”,用户仓库名称格式为“用户名/仓库名”。

每个仓库可以包含多个Tag(标签),每个标签对象对应一个镜像,可以手动打标签,如果和官方有冲突,以本标签地为准,统一镜像可以有多个标签,tag不一样,但是image id一样,便签配置命令如下,把busybox的镜像latest版本,再打一个标签为sunny01,则busybox同时有两个标签,image id一样

 docker tag busybox:latest busybox:sunny01

4  Index介绍

用于维护用户账号,镜像的校验以及公共名称空间的信息

相当于为registry提供了一个可以完成用户认证等功能的检索接口

5  docker hub功能介绍

docker hub支持如下组件

image repositories:镜像仓库

automated builds:当修改原码仓库时自动构建镜像,只需要上传dockerfile就会构建镜像

webhooks:自动构建的属性之一,当成功推送一个文件到仓库后webhooks触发一个动作

organizations:工作组

github and bitbucket integration:和github整合起来,在github上开发,定义webhooks,当监控到github有新的推送后,自动执行构建镜像,完成镜像构建。

使用docker hub之外的第三方仓库,推送镜像,需要指定如下信息

向那个仓库的那个端口,哪个名称空间推送镜像,镜像名称和标签是什么,其中port默认为5000,命令如下

docker pull  <registry>[:<prot>]/[<namespace>/]<name>:<tag>

Docker 之 基于容器的镜像制作_powerx_yc的博客-CSDN博客

Docker容器运行已经不是简单的通过Docker daemon来启动,而是集成了containerd、runC等多个组件。Docker服务启动之后,我们也可以看见系统上启动了dockerd、docker-containerd等进程,本文主要介绍新版Docker(1.11以后)每个部分的功能和作用。
0?wx_fmt=jpeg

下面就来介绍下独立分拆出来的其他几个模块。

Containerd  
containerd是容器技术标准化之后的产物,为了能够兼容OCI标准,将容器运行时及其管理功能从Docker Daemon剥离。理论上,即使不运行dockerd,也能够直接通过containerd来管理容器。(当然,containerd本身也只是一个守护进程,容器的实际运行时由后面介绍的runC控制。)

最近,Docker刚刚宣布开源containerd。从其项目介绍页面可以看出,containerd主要职责是镜像管理(镜像、元信息等)、容器执行(调用最终运行时组件执行)。
0?wx_fmt=png

containerd向上为Docker Daemon提供了gRPC接口,使得Docker Daemon屏蔽下面的结构变化,确保原有接口向下兼容。向下通过containerd-shim结合runC,使得引擎可以独立升级,避免之前Docker Daemon升级会导致所有容器不可用的问题。

Docker、containerd和containerd-shim之间的关系,可以通过启动一个Docker容器,观察进程之间的关联。首先启动一个容器,
 

[root@jettoloader k3s-ansible-master]# yum install psmisc
[root@jettoloader k3s-ansible-master]# ps -ef | grep docker
root     30589     1  0  2021 ?        02:30:19 /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store consul://172.16.10.21:8500 --cluster-advertise 172.16.10.21:2375

pid=30589

[root@jettoloader k3s-ansible-master]# pstree -l -a -A 30589
dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store consul://172.16.10.21:8500 --cluster-advertise 172.16.10.21:2375
  |-containerd --config /var/run/docker/containerd/containerd.toml --log-level info
  |   |-containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/304fdae4c7094db09a646a95b85917ae05582491d762d6edd29f986e7b6c324a -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
  |   |   |-tini -- /entrypoint.sh
  |   |   |   `-entrypoint.sh /entrypoint.sh
  |   |   |       |-sleep 1
  |   |   |       |-start_hbase.sh /opt/bin/start_hbase.sh
  |   |   |       |   `-java -Dproc_master -XX:OnOutOfMemoryError=kill -9 %p -XX:+UseConcMarkSweepGC -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:PermSize=128m -XX:MaxPermSize=128m -XX:ReservedCodeCacheSize=256m -Dhbase.log.dir=/opt/hbase/bin/../logs -Dhbase.log.file=hbase.log -Dhbase.home.dir=/opt/hbase/bin/.. -Dhbase.id.str= -Dhbase.root.logger=INFO,console -Dhbase.security.logger=INFO,RFAS org.apache.hadoop.hbase.master.HMaster start
  |   |   |       |       `-235*[{java}]
  |   |   |       `-start_opentsdb. /opt/bin/start_opentsdb.sh
  |   |   |           `-java -XX:+UseConcMarkSweepGC -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -enableassertions -enablesystemassertions -classpath /usr/local/share/opentsdb/*.jar:/usr/local/share/opentsdb:/usr/local/share/opentsdb/bin:/usr/local/share/opentsdb/lib/asm-4.0.jar:/usr/local/share/opentsdb/lib/async-1.4.0.jar:/usr/local/share/opentsdb/lib/asynchbase-1.8.2.jar:/usr/local/share/opentsdb/lib/commons-jexl-2.1.1.jar:/usr/local/share/opentsdb/lib/commons-logging-1.1.1.jar:/usr/local/share/opentsdb/lib/commons-math3-3.4.1.jar:/usr/local/share/opentsdb/lib/guava-18.0.jar:/usr/local/share/opentsdb/lib/jackson-annotations-2.9.5.jar:/usr/local/share/opentsdb/lib/jackson-core-2.9.5.jar:/usr/local/share/opentsdb/lib/jackson-databind-2.9.5.jar:/usr/local/share/opentsdb/lib/javacc-6.1.2.jar:/usr/local/share/opentsdb/lib/jgrapht-core-0.9.1.jar:/usr/local/share/opentsdb/lib/kryo-2.21.1.jar:/usr/local/share/opentsdb/lib/log4j-over-slf4j-1.7.7.jar:/usr/local/share/opentsdb/lib/logback-classic-1.0.13.jar:/usr/local/share/opentsdb/lib/logback-core-1.0.13.jar:/usr/local/share/opentsdb/lib/minlog-1.2.jar:/usr/local/share/opentsdb/lib/netty-3.10.6.Final.jar:/usr/local/share/opentsdb/lib/protobuf-java-2.5.0.jar:/usr/local/share/opentsdb/lib/reflectasm-1.07-shaded.jar:/usr/local/share/opentsdb/lib/slf4j-api-1.7.7.jar:/usr/local/share/opentsdb/lib/tsdb-2.4.0.jar:/usr/local/share/opentsdb/lib/zookeeper-3.4.6.jar:/etc/opentsdb net.opentsdb.tools.TSDMain --port=4242 --staticroot=/usr/local/share/opentsdb/static --cachedir=/tmp --auto-metric
  |   |   |               `-41*[{java}]
  |   |   `-9*[{containerd-shim}]
  |   `-15*[{containerd}]
  |-docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 4242 -container-ip 172.17.0.2 -container-port 4242
  |   `-7*[{docker-proxy}]
  `-15*[{dockerd}]

虽然pstree命令截断了命令,但我们还是能够看出,当Docker daemon启动之后,dockerd和docker-containerd进程一直存在。当启动容器之后,docker-containerd进程(也是这里介绍的containerd组件)会创建docker-containerd-shim进程,其中的参数304fdae4c7094db09a646a95b85917ae05582491d762d6edd29f986e7b6c324a就是要启动容器的id。最后docker-containerd-shim子进程,已经是实际在容器中运行的进程(既sleep 1000)。

docker-containerd-shim另一个参数,是一个和容器相关的目录[root@jettoloader k3s-ansible-master]# ls -al /var/run/docker/containerd/304fdae4c7094db09a646a95b85917ae05582491d762d6edd29f986e7b6c324a/,里面的内容有:

[root@jettoloader k3s-ansible-master]# ls -al /var/run/docker/containerd/304fdae4c7094db09a646a95b85917ae05582491d762d6edd29f986e7b6c324a/
total 4
drwxr-xr-x 2 root root  100 Jan 17 15:15 .
drwx------ 4 root root  160 Nov 15 17:09 ..
prwx------ 1 root root    0 Jan 17 15:54 init-stderr
prwx------ 1 root root    0 Nov 15 17:10 init-stdout
-rw------- 1 root root 4096 Jan 17 15:15 .init-stdout.sw

其中包括了容器配置和标准输入、标准输出、标准错误三个管道文件。

RunC  
OCI定义了容器运行时标准,runC是Docker按照开放容器格式标准(OCF, Open Container Format)制定的一种具体实现。

runC是从Docker的libcontainer中迁移而来的,实现了容器启停、资源隔离等功能。Docker默认提供了docker-runc实现,事实上,通过containerd的封装,可以在Docker Daemon启动的时候指定runc的实现。

我们可以通过启动Docker Daemon时增加--add-runtime参数来选择其他的runC现。下面就让我们看下这几个模块如何工作。

容器导出到rootfs, 此时,标准包所需的容器数据已经准备完毕,接下来我们需要创建配置文件:

[root@jettoloader aaa]# mkdir rootfs 
[root@jettoloader aaa]# docker export $(docker create petergrace/opentsdb-docker:latest) | tar -C rootfs -xvf -

[root@jettoloader aaa]# ls rootfs/
bin  data  dev  entrypoint.sh  etc  home  lib  media  mnt  opentsdb-plugins  opt  proc  root  run  sbin  srv  sys  tini  tmp  usr  var

此时会生成一个名为config.json的配置文件,该文件和Docker容器的配置文件类似,主要包含容器挂载信息、平台信息、进程信息等容器启动依赖的所有数据。

最后,可以通过runc命令来启动容器:

[root@jettoloader aaa]# runc spec

[root@jettoloader aaa]# ls
config.json  rootfs

最后,可以通过runc命令来启动容器,执行之后,我们可以看见容器已经启动:

[root@jettoloader aaa]# runc run busybox
/ # ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 sh
    8 root      0:00 ps aux


[root@jettoloader k3s-ansible-master]# runc list
ID          PID         STATUS      BUNDLE           CREATED                          OWNER
busybox     26539       running     /root/work/aaa   2022-01-17T07:50:18.917471987Z   root

注意,runc必须使用root权限启动。

此时,事实上已经可以不依赖Docker本身,如果系统上安装了runc包,即可运行容器。

当然,也可以使用docker-runc命令来启动容器:

从这里可以看到标准化的重要性。

总结  

从Docker 1.11之后,Docker Daemon被分成了多个模块以适应OCI标准。拆分之后,结构分成了以下几个部分。

0?wx_fmt=jpeg

其中,containerd独立负责容器运行时和生命周期(如创建、启动、停止、中止、信号处理、删除等),其他一些如镜像构建、卷管理、日志等由Docker Daemon的其他模块处理。

Docker的模块块拥抱了开放标准,希望通过OCI的标准化,容器技术能够有很快的发展。

导入

从网络地址导入

docker import https://example.com/container.tar

从本地导入

docker import /path/to/exampleContainer.tgz

基于当前系统制作docker镜像

1:通过tar 备份目录
tar -cvpf /home/exampleContainer.tar --directory=/ --exclude=proc --exclude=sys --exclude=dev --exclude=run /


2:导入镜像
cat exampleContainer.tar | docker import - exampleContainer

1.export命令导出的tar文件略小于save命令导出的

2.export命令是从容器(container)中导出tar文件,而save命令则是从镜像(images)中导出
3.基于第二点,export导出的文件再import回去时,无法保留镜像所有历史(即每一层layer信息,不熟悉的可以去看Dockerfile),不能进行回滚操作;而save是依据镜像来的,所以导入时可以完整保留下每一层layer信息。如下图所示,nginx:latest是save导出load导入的,nginx:imp是export导出import导入的。

建议

可以依据具体使用场景来选择命令

  • 若是只想备份images,使用save、load即可
  • 若是在启动容器后,容器内容有变化,需要备份,则使用export、import

Docker、Containerd、RunC...:你应该知道的所有_高效开发运维的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值