一、Docker打包容器并跨服务器传输重建加载load镜像Unable to find image :latest
使用docker就是因为docker可以快速进行多服务器部署,所以需要对部署好的环境进行打包复制并快速在其它的服务器上进行重建。
其实使用起来非常简单,使用docker export从运行的容器中导出文件,,使用import命令生成镜像批量传至目标服务器然后在目标服务器上进行load加载镜像即可,过程如下:
#查看容器并备份容器 user@u25:~# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4da5b8faf1a0 nginx "nginx -g 'daemon of…" 45 hours ago Up 18 hours 0.0.0.0:80->80/tcp nginx 2af5436df1e2 deluxo/php7.1-fpm "docker-php-entrypoi…" 2 days ago Up 17 hours 0.0.0.0:9000->9000/tcp php user@u25:~# docker export 2af5436df1e2 >php_kermit.tar user@u25:~# docker export 4da5b8faf1a0 > nginx_kermit.tar user@u25:~# ll -h |grep _kermit -rw-r--r-- 1 root root 123M Nov 8 11:49 nginx_kermit.tar -rw-r--r-- 1 root root 794M Nov 8 11:50 php_kermit.tar #生成镜像文件 user@u25:~# cat nginx_kermit.tar php_kermit.tar | docker import - kermit_nginx_php:demo sha256:9fe17159411e655a200dec3a0c989451f3c268cea5f02c6797d2fb1f716ec49f #备份镜像 user@u25:~# docker save kermit_nginx_php > kermit_nginx_php_save.tar user@u25:~# ll -h | grep kermit -rw-r--r-- 1 root root 916M Nov 8 12:37 kermit_nginx_php_save.tar -rw-r--r-- 1 root root 123M Nov 8 11:49 nginx_kermit.tar -rw-r--r-- 1 root root 794M Nov 8 11:50 php_kermit.tar #通过scp命令传输到另一台服务器: kermit@n28:~$ scp kermit_nginx_php_save.tar root@111.14.36.97:/root/ kermit_nginx_php_save.tar 100% 916MB 181.8MB/s 00:05 #在另一台服务器上安装docker,并导入镜像 kermit@u27:~# docker load <kermit_nginx_php_save.tar 6cba44dfc730: Loading layer [==================================================>] 960MB/960MB Loaded image: kermit_nginx_php:demo #这里显示的就是一个镜像,看来一次只能打包一个容器成镜像 kermit@u27:~# docker images REPOSITORY TAG IMAGE ID CREATED SIZE kermit_nginx_php demo 9fe17159411e About an hour ago 125MB
从上面显示来看,最后显示的是一个镜像,说明在原docker服务上面打包时一次只能打包一个容器成镜像,不能支持多个容器一起打包成一个。
我在使用上面的方式load镜像之后启动时报错:Unable to find image 镜像名称:latest locally docker: Error response from daemon: pull access denied for 镜像名称, repository does not exist or may require docker login.不知道是为什么。
有可能有是我使用的两个容器进行的打包,后来我使用了以下的做法重新做了一套成功了。两种方式暂时先都放这里吧,回头再看。成功的方式使用如下:
#另一种方式: user@u25:/data01/nginx# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4da5b8faf1a0 nginx "nginx -g 'daemon of…" 47 hours ago Up 20 hours 0.0.0.0:80->80/tcp nginx 2af5436df1e2 deluxo/php7.1-fpm "docker-php-entrypoi…" 2 days ago Up 19 hours 0.0.0.0:9000->9000/tcp php #1. 把当前的容器提交为一个镜像 user@u25:/data01/nginx# docker commit nginx kermit_nginx sha256:098b1d0148802062ac09affee44a671ff7eaf1ea88f8ef0251b9542e21e2f979 #2.将镜像存为tar文件 user@u25:/data01/nginx# docker save kermit_nginx > kermit_nginx2.tar user@u25:/data01/nginx# #3.将镜像文件通过scp传输到目标服务器 kermit@u18:~$ scp ./kermit_nginx2.tar root@111.14.36.97:/root/kermit_nginx2.tar kermit_nginx2.tar #4.在另一台服务器上加载镜像 kermit@u27:~# docker load -i kermit_nginx2.tar b67d19e65ef6: Loading layer [==================================================>] 72.5MB/72.5MB 6eaad811af02: Loading layer [==================================================>] 57.54MB/57.54MB a89b8f05da3a: Loading layer [==================================================>] 3.584kB/3.584kB c8f904504379: Loading layer [==================================================>] 10.75kB/10.75kB Loaded image: kermit_nginx:latest #5.在此镜像上去启动程序,执行成功
除此之外,有必要了解一下:docker save和docker export两个方法的区别:
对于Docker Save方法,会保存该镜像的所有历史记录,Docker Export不会保留历史记录,没有commit历史。
docker save保存的是镜像(image),docker export保存的是容器(container);
docker load用来载入镜像包,docker import用来载入容器包,两者都会恢复为镜像;
docker load不能对载入的镜像重命名,而docker import可以为镜像指定新名称。
从这里可以对上面的两个方法进行对比。第一个方法先进行export,再进行import 然后进行save,而第二个方法是commit之后直接save。从上面对两方法的了解可以看到docker save和docker load是对应的,第一个方法里的export和import感觉没有必要,因此第二个方法看起来更合理。
二、Docker在容器未启动的情况下如何修改容器中的文件
docker容器在启动后进入容器中修改了部分文件,之后重启容器失败,此时有点束手无策,因为不启动容器就不能exec进入容器修改文件,但不修改正确文件又不能启动容器,陷入了死循环。好像没有办法。
但docker不会这么笨的,另外虽然docker容器没有启动,但docker整个都安装在本地磁盘上,它肯定能支持在磁盘上找到其对应位置直接修改文件。不错,docker就是可以直接在系统上修改其文件内容。虽然docker容器无法启动,但是docker inspect命令依然可以使用,我们利用这个命令找到它的一些执行信息,其中就有GraphDriver的相关信息:
"GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/over..." "MergedDir": "/var/lib/docker/overlay2/df23df45.../merged" "UpperDir": "/var/lib/docker/overlay2/df23df45.../diff" "WorkDir": "/var/lib/docker/overlay2/df23df45.../work" }, "Name": "overlay2"
Docker的graph driver主要用于管理和维护镜像,包括把镜像从仓库下载下来,到运行时把镜像挂载起来可以被容器访问等,都是graph driver做的。涉及的docker命令有Docker pull/push/export/import/load/save/build。graph driver的功能基本上是对docker的image定义的实现,而OCI的image-spec是基于docker的image spec的,所以理论dockergraph driver做的事情,都应该被image-spec的实现所覆盖。目前docker支持的graph driver有:Overlay/Aufs/Devicemapper/Btrfs/Zfs/Vfs,这些driver各有优劣。从上面的GraphDriver信息中可以看到当前的docker是用Overlay2作为graph driver的。
对于Overlay driver,其它的这里就不多涉及了,可以了解一下它的关键目录:/var/lib/docker/overlay,即上面的GraphDriver信息中的MergedDir、UpperDir、WorkDir。这个目录中存放的是镜像的每一层layer解压后的结果,以及基于每一个镜像生成容器后,对镜像合并挂载后的目录和对应的init目录。这里的id就是cache-id和mount-id。我们启动镜像时挂载的目录以及镜像中的文件都可以在这里找到。里面又分几个子目录,正是和GraphDriver信息中的MergedDir、UpperDir、WorkDir一一对应。
/var/lib/docker/overlay/<id>/merged:这是所有镜像层合并后的结果,就是容器中进程看到的结果
/var/lib/docker/overlay/<id>/upper:这是上面的只读层,用户挂载的upper层目录
/var/lib/docker/overlay/<id>/work:文件系统的工作基础目录。
对于overlay2,其UpperDir就是我们挂载的程序目录所在的位置,因此容器挂了无法启动,此时我们可以进入inspect命令结果中的UpperDir目录 :/var/lib/docker/overlay2/df23df45.../diff 里找到程序进行修改。