制作镜像的方法:
方法一:
commit
使用commit制作镜像使基于一个现有的容器
第一步:启动容器
[root@ken1 ~]# docker run -d httpd
第二步:修改网站首页文件
[root@ken1 ~]# docker exec -it 3cf31d57a61569c09c8024 bash
root@3cf31d57a615:/usr/local/apache2# pwd
/usr/local/apache2
root@3cf31d57a615:/usr/local/apache2# ls
bin build cgi-bin conf error htdocs icons include logs modules
root@3cf31d57a615:/usr/local/apache2# cd htdocs/
root@3cf31d57a615:/usr/local/apache2/htdocs# ls
index.html
root@3cf31d57a615:/usr/local/apache2/htdocs# echo "this is for testing commit" > index.html
root@3cf31d57a615:/usr/local/apache2/htdocs# exit
exit
[root@ken1 ~]# curl 192.168.163.5:88
this is for testing commit
第三步:进行commit提交
[root@ken1 ~]# docker commit -p 3cf31d57a61569c09c8 nginx-com:v1
sha256:5de6e803346c00b4373ad2b49b9caf0dbe12f23a105d8a47c6e6aaca465ff6e6
[root@ken1 ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx-com v1 5de6e803346c 4 seconds ago 178MB
现在就可以把配置好的环境发送给其他人使用
第四步:把镜像制作成压缩包
[root@ken1 ~]# docker image save nginx-com:v1 > nginx-com.tar
[root@ken1 ~]# ls
anaconda-ks.cfg busybox1.31-v2.tar httpd_img.tar.gz nginx-game.tar test1
busybox1.31.tar docker-speend.sh nginx-com.tar test
第五步:进行发送
[root@ken1 ~]# scp nginx-com.tar 192.168.163.134:/root
root@192.168.163.134's password:
nginx-com.tar 100% 178MB 37.2MB/s 00:04
第六步:其他人进行使用
[root@ken-node3 ~]# docker image load < nginx-com.tar
9f5d674a9055: Loading layer [==================================================>] 7.168kB/7.168kB
Loaded image: nginx-com:v1
[root@ken-node3 ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx-com v1 5de6e803346c Less than a second ago 178MB
[root@ken-node3 ~]# docker run -d -p 87:80 nginx-com:v1
515ec3c0d991ea617dfa243096538d78ba323b1b96c2e8ab13f5d61f1d5ea45d
[root@ken-node3 ~]# curl 192.168.163.134:87
this is for testing commit
方法二:
Dockefile
Dockefile详解
Dockerfile编写注意项
"#"井号进行备注
指令参数,指令的大小写不敏感,但是规范来写都是大写!
第一个非注释行必须是FROM指令
编写Dockerfile必须在一个目录下进行,这个目录称之为 工作目录(WORKSPACE)
Dockerfile文件命令的首字母必须大写
制作镜像所要用的文件必须放在工作目录或者工作目录的子目录之下,不能放在父目录
可以通过隐藏文件 .dockeringnore 来指定不要放入到镜像中的文件,一行是一个文件,可以用通配符
基于dockerfile做镜像,本质上还是基于一个现有的镜像做新镜像
dockerfile常用指令
1.FROM指令
作用:指定使用哪个基础镜像
格式:
FROM 镜像名 注册表/镜像名:tag
例如:
FROM busybox
2.ENV
作用:设置环境变量
格式:
1.ENV 变量名=变量值
2.ENV 变量名 变量值
例如:
ENV name=ken age=18
引用变量:$name $age
3.LABEL
作用:设置标签,注释
格式:
LABEL key=value
例如:
LABEL author=ken
4.RUN
作用:执行命令
格式:
RUN CMD
多个命令:
方法一:
RUN CMD1;CMD2
方法二:
RUN CMD1&&CMD2
注意:
1.因为docker镜像是分层机制,应当尽量减少层次,所以如果在创建镜像的时候需要执行多个命令,建议使用一个RUN 指令,执行多个命令。
2.RUN 指令默认是在shell中环境中执行,docker镜像当中的shell类型默认为/bin/sh/ -c
5.COPY
作用:复制文件到镜像中
格式:
COPY src dest/
注意:
源文件路径用相对路径,目标一般用绝对路径
也可以通配符
源文件必须在工作目录或者工作目录的子目录中
目标路径可以不存在,会自动创建
如果源文件是一个目录,会自动递归复制目录下的文件到目标位置,但是目录自身不会复制
如果复制多个文件,或者源文件中用了通配符,那么目标路径必须以 / 为结尾
6.WORKDIR
作用:指定工作目录
格式:
WORKDIR path
例如:
WORKDIR /ken
7.EXPOSE 80
作用:暴露容器端口
格式:
EXPOSE PORT
例如:
EXPOSE 80/tcp
注意:这里声明暴露端口并不是说在启动容器的时候,容器会自动暴露相关的端口,而是需要管理员使用-P 选型进行端口暴露。
8.VOLUME
作用:声明需要映射的数据卷
格式:
VOLUME path
例如:
VOLUME /usr/share/nginx/html/
注意:如果在构建镜像时使用volume声明了需要暴露的数据卷路径,在启动容器的时候回自动和宿主机的一个目录进行绑定!docker manaagerment volume
9.ADD
作用:和copy相似,也是复制文件到镜像中,可以在网上下载文件到镜像中,也可以自动复制tar.gz包到镜像中并实现自动解决
格式:
ADD sec dest
例如:
ADD web.tar.gz /usr/share/nginx/html/
10.CMD 注意!CMD和ENTRYPOINT执行的命令都是pid为1的命令
作用:执行命令,一个Dockerfile中可以有多个CMD指令,但是只有最后一个CMD指令生效
三种格式:
格式1:
CMD com –>是在shell中执行相关的cmd,默认类型为/bin/sh -c
例如:
CMD cat test –> /bin/sh -c cat test
格式2:
CMD [“com”,”para1″,”para2″]
例如:
CMD [“cat”,”test”] –>cat test
格式三:
CMD [“para1″,”para2”] –>需要和ENTRYPOIN指令一起使用,CMD的选项会被当做参数传递给ENTRYPOINT指令
11.ENTRYPOINT
作用:也是执行命令
格式:
格式1:
ENTRYPOINT cat test –> /bin/sh -c cat test
格式二:
ENTRYPOINT [“com”,”para1″,”para2″]
12,ONBUILD
作用:定义触发器
格式:
ONBUILD cmd
例如:
ONBUILD yum install lrzsz -y
13、dockerfile中RUN,CMD,ENTRYPOINT的区别
- 使用 RUN 指令安装应用和软件包,构建镜像。
- 如果 Docker 镜像的用途是运行应用程序或服务,比如运行一个 * * * *
MySQL,应该优先使用 Exec 格式的 ENTRYPOINT 指令。CMD 可为 ENTRYPOINT 提供额外的默认参数,同时可利用 docker run 命令行替换默认参数。 - 如果想为容器设置默认的启动命令,可使用 CMD 指令。用户可在 docker run 命令行中替换此默认命令。
演示1:使用nginx镜像来演示上述所有指令
第一步:编写dockerfile
[root@localhost ~]# mkdir /nginx
[root@localhost ~]# cd /nginx
[root@localhost nginx]# vim Dockerfile
#this is for test nginx
FROM nginx:latest
LABEL author=ken
ENV path=/usr/share/nginx/html/ pack=nginx-1.12.2.tar.gz
WORKDIR $path
COPY jd1 $path
RUN touch testnginx
ADD https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/at-sysvinit-3.1.13-24.el7.x86_64.rpm ./
ADD $pack ./
EXPOSE 80
VOLUME $path
ONBUILD ADD https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/at-sysvinit-3.1.13-24.el7.x86_64.rpm ./
CMD ["-g","daemon off;"]
ENTRYPOINT ["nginx"]
第二步:构建镜像
[root@localhost nginx]# docker build -t nginx:v1 .
第三步:查看镜像信息
[root@localhost nginx]# docker image ls
[root@localhost nginx]# docker history nginx:v1
第四步:使用创建的镜像启动容器
工作目录:
数据卷:/var/lib/docker/volume/
端口:
[root@localhost nginx2]# docker run -d -P nginx:v2
错误日志:
[root@localhost nginx]# docker logs 2db0a5411551
2019/08/15 03:18:30 [emerg] 1#1: unexpected end of parameter, expecting ";" in command line
nginx: [emerg] unexpected end of parameter, expecting ";" in command line
演示2:制作LAMP架构镜像并上线wordpress
第一步:拉取centos7镜像
并按照如下的dockerfile初始化镜像
FROM centos:7
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
第二步:编写制作LAMP架构的dockerfile
FROM local/c7-systemd
COPY local.repo /etc/yum.repos.d/
COPY wordpress /var/www/html/
RUN yum -y install httpd mariadb-server php php-mysql; yum clean all; systemctl restart mariadb httpd;systemctl enable mariadb httpd.service
EXPOSE 80 3306
CMD ["/usr/sbin/init"]
1.使用第一步创建出来的镜像
2.把local.repo文件发送到镜像中,因为镜像文件没有mariad数据库
local.repo文件内容
[local]
name=local
enabled=1
gpgcheck=0
baseurl=https://mirrors.aliyun.com/centos/7/os/x86_64/
3.把配置好的wordpress安装包复制到网站根目录下
4.下载LAMP架构
5.暴露80 和3306 端口
6.启动
第三步:运行容器
[root@ken-node3 centos]# docker run -d -v /sys/fs/cgroup/:/sys/fs/cgroup/ -p 888:80 --privileged centos-wordpress:v1
–privileged 让容器能够获得更多特权,否则在容器内部不能使用systemctl,会报如下的错
Failed to get D-Bus connection: Operation not permitted
第四步:进入容器创建数据库
[root@ken-node3 centos]# docker exec -it f80ed6fb67b3 bash
[root@f80ed6fb67b3 /]# ls /var/www/html/
index.php wp-activate.php wp-config-sample.php wp-links-opml.php wp-register.php
license.txt wp-admin wp-config.php wp-load.php wp-settings.php
readme.html wp-app.php wp-content wp-login.php wp-signup.php
wordpress wp-blog-header.php wp-cron.php wp-mail.php wp-trackback.php
wordpress-3.3.1-zh_CN.zip wp-comments-post.php wp-includes wp-pass.php xmlrpc.php
[root@f80ed6fb67b3 /]# mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 2
Server version: 5.5.60-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> create database ken;
Query OK, 1 row affected (0.00 sec)
MariaDB [(none)]> grant all on *.* to ken@'localhost' identified by '123';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> exit
Bye
第五步:浏览器访问
数据卷volume功能特性
数据卷 是一个可供一个或多个容器使用的特殊目录,实现让容器中的一个目录和宿主机中的一个文件或者目录进行绑定。数据卷 是被设计用来持久化数据的
对于数据卷你可以理解为NFS中的哪个分享出来的挂载点,指宿主机共享的目录。
主要有如下的功能和特性
容器中数据的持久存储
容器间的资源共享
容器的迁移(分布式)
对数据卷的修改会立马生效
对数据卷的更新,不会影响镜像
数据卷默认会一直存在,即使容器被删除 (注意docker自主管理的会被删除,容器删除前一定要对数据卷进行备份)
容器底层技术:
1.cgroup
实现了资源的使用限额,CPU,内存,以及磁盘
2,namespace
实现了资源隔离
PID,UTS,USER,NETWORK,MOUNT,IPC
实现数据卷
三种方式
1.绑定本机的特定目录
2.docker 自管理,docker会随机绑定主机的一个目录
3.基于一个现有的容器
1.绑定本机的特定目录 bind mount volume
[root@ken1 ~]# docker run -v /ken1:/var/www/html -d -P httpd
-v 指定使用数据卷
/ken1:/var/www/html #/ken1是宿主机的一个目录,/var/www/html是容器内的一个目录,如果说容器内的这个目录不存在的话,shi是会自动创建!
优势:
1.易于管理
2.可以实现数据的持久化
3.如果宿主机宕了,容器还是无法访问,可以使用NFS进行共享,多个宿主机进行负载均衡。
2.docker自管理的 docker manaagerment volume
这个和bind mount volume区别是用户无法再去管理本地的一个目录。docker会自己绑定宿主机下的一个目录
[root@ken1 ken1]# docker run -d -v /usr/local/apache2/htdocs -d -P httpd
可以通过下面的命令进行查看
[root@ken1 ken1]# docker container inspect 1365d65ead56
注意:
1.在删除容器的时候,是默认不会删除docker managerment volume中的数据卷的,如果想要在删除容器的时候顺带删掉相关的数据卷,需要加上选项-v
2.如果在删除容器的时候没有使用-v就会遗留下来数据卷,这样的数据卷叫做孤儿卷,即每人管理的卷
如果处理孤儿卷?
解决方案:
第一步:查看卷
[root@ken1 ken1]# docker volume ls
DRIVER VOLUME NAME
local 986d19ec31801a630dc5209724560b074b025eacdb7cdf4fbbe3d5e6cc7f0771
local d846455965a7bc208478bf7f6cf2f178263fe455c573504572d4a87f299800a1
local f0d96791e2a60a6edf9b6550625bf568520988ffbaffcfa6353e924b4530dc1c
local fa7bcf028a50a168d8b531eaff2dc74e6207421a5b3347430909d75eb4ad76a4
第二步:删除相应的孤儿卷
[root@ken1 ken1]# for i in `docker volume ls | grep -v "DRIVER" | awk '{print $2}'`; do docker volume rm $i ;done
在删除容器的时候加上-v
[root@ken1 ken1]# docker container rm -f -v a5e91fa77abe1a5
注意:
如果使用-v, 相应的数据卷也会被删掉,如果是在生产环境当中,应当做好数据备份工作!
3.基于一个容器
[root@ken1 ken1]# docker run -d --volumes-from 1e9a4c3b0bc30295d httpd
–volumes-from是基于一个现有的容器进行数据共享,这个参数后面应当跟上相应的容器ID或者容器名
数据卷的生命周期管理
1.备份
2.迁移
3.恢复
4.销毁
1.备份
备份只需要备份相应的数据卷即可,例如:
[root@ken1 ken1]# docker run -d -v /ken:/var/www/html httpd
再上面的额例子中我们只需要做好/ken这个目录下的文件备份即可!
2.恢复
只需要重启一个容器,并且绑定ken下面备份的数据即可
3.迁移
把ken下面备份好的数据,发送到相应的节点即可,并使用bind mount volume方式运行容器即可
4.销毁
情况一:bind mount volumes
这种情况是绑定宿主机的一个目录,如果想要删除数据,只需要删掉宿主机的目录即可
情况二:docker managerment volume
需要在删除容器的时候加上选择-v
情况三:基于一个容器
分为两种情况:
1,如果是docker自管理,删除容器时使用-v
2.宿主机特定目录,需要删除宿主机上的特定目录
验证:数据卷被其他容器使用是否能够删掉
第一步:创建一个新的容器
[root@ken1 ken1]# docker run -d -v /data httpd
第二步:查看数据卷
[root@ken1 ken1]# docker inspect 3b1ce4b5f96150e866f322a600f93cd
...
/var/lib/docker/volumes/b0cfa7ae0abe933392c3e649f3d0bec0185c8357c9673ebc0322920cdab8235e/_data
第三步:基于现有容器在创建一个容器并绑定数据卷
[root@ken1 ken1]# docker run -d --volumes-from 3b1ce4b5f96150e866 httpd
第四步;查看第二个容器的数据卷
发现数据卷和第一个容器使用的数据卷是一致,说明两个容器现在共用一个数据卷
"Name": "b0cfa7ae0abe933392c3e649f3d0bec0185c8357c9673ebc0322920cdab8235e",
第五步:查看数据卷
[root@ken1 ken1]# docker volume ls
DRIVER VOLUME NAME
local b0cfa7ae0abe933392c3e649f3d0bec0185c8357c9673ebc0322920cdab8235e
第六步:删除第一个容器并加上-v选择
[root@ken1 ken1]# docker rm -f -v 3b1ce4b5f961
3b1ce4b5f961
[root@ken1 ken1]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
70df334b3f25 httpd "httpd-foreground" 2 minutes ago Up 2 minutes 80/tcp wonderful_shamir
39d5f620493b httpd "httpd-foreground" 9 minutes ago Up 9 minutes 80/tcp goofy_herschel
c42a2a22c533 httpd "httpd-foreground" 12 minutes ago Up 12 minutes 80/tcp admiring_wilbur
1e9a4c3b0bc3 httpd "httpd-foreground" 24 minutes ago Up 23 minutes 80/tcp blissful_haslett
a6304e984f93 httpd "httpd-foreground" About an hour ago Up About an hour 0.0.0.0:32778->80/tcp brave_varahamihira
[root@ken1 ken1]# docker volumes ls
docker: 'volumes' is not a docker command.
See 'docker --help'
[root@ken1 ken1]# docker volume ls
DRIVER VOLUME NAME
local b0cfa7ae0abe933392c3e649f3d0bec0185c8357c9673ebc0322920cdab8235e
验证总结:
两个容器如果共享了一个数据卷的话,删除一个容器的时候即使加上-v选线的话,即使删除源容器的话数据卷并不会被删除。
volume 生命周期管理
1.备份
因为 volume 实际上是 host 文件系统中的目录和文件,所以 volume 的备份实际上是对文件系统的备份。
[root@ken1 ~]# docker run -d -v /ken:/usr/share/nginx/html nginx-game:v1
在这里只需要备份/ken目录下的文件即可
2.恢复
volume 的恢复也很简单,如果数据损坏了,直接用之前备份的数据拷贝到 /ken就可以了。
3.迁移
如果我们想使用httpd,这就涉及到数据迁移,方法是:
docker stop 当前容器。
启动新版本容器并 mount 原有 volume。
[root@ken1 ~]# docker run -d -v /ken:/var/www/html httpd
当然,在启用新容器前要确保新版本的默认数据路径是否发生变化。
4.销毁
可以删除不再需要的 volume,但一定要确保知道自己正在做什么,volume 删除后数据是找不回来的。
docker 不会销毁 bind mount,删除数据的工作只能由 host 负责。对于 docker managed volume,在执行 docker rm 删除容器时可以带上 -v 参数,docker 会将容器使用到的 volume 一并删除,但前提是没有其他容器 mount 该 volume,目的是保护数据,非常合理。
如果删除容器时没有带 -v 呢?这样就会产生孤儿 volume,好在 docker 提供了 volume 子命令可以对 docker managed volume 进行维护。
容器 bbox 使用的 docker managed volume 可以通过 docker volume ls 查看到。
因为没有使用 -v,volume 遗留了下来。对于这样的孤儿 volume,可以用 docker volume rm 删除
如果想批量删除孤儿 volume,可以执行:
docker volume rm $(docker volume ls -q)
volume container 的数据归根到底还是在 host 里,有没有办法将数据完全放到 volume container 中,同时又能与其他容器共享呢?
当然可以,通常我们称这种容器为 data-packed volume container。其原理是将数据打包到镜像中,然后通过 docker managed volume 共享。