一、Docker 部署以及镜像和容器的基本操作
序言
Docker 入门系列文章是根据视频教程全程实操的记录,基本上按照本系列文章操作,就能掌握 Docker 基本入门技巧。由于纯属个人笔记,难免存在错误和不详尽之处。欢迎交流批评指正。
1. 准备环境
准备 Linux 服务器,推荐 CentOS 7,64位、系统内核版本为 3.10 以上
[root@k8s-master ~]# uname -r
3.10.0-1160.53.1.el7.x86_64
2. 配置 docker 镜像源
最大的公开的镜像仓库是 Docker Hub:
https://hub.docker.com 国外的镜像源会被墙,推荐使用阿里云:
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
3. 安装docker
Docker 版本分为 CE(社区版,免费)和EE(企业版,安全CE)。我们安装社区版。
执行如下命令安装:
yum install docker-ce -y
如果之前安装过其他源的 docker,可能会冲突,安装失败,先卸载旧版本,执行命令:
sudo yum remove docker docker-common docker-selinux docker-engine
启动 docker 守护进程
systemctl start docker
设置 docker 守护进程开机自动启动
systemctl enable docker
查看 docker 版本
docker --version
或者
docker -v
查看 docker 详细信息
docker info
4. docker 镜像的操作
在线搜索 docker 镜像
docker search [镜像名]
注意:
判断镜像是否是官方的:official 栏显示 OK 则是官方镜像。
关于 docker 的内核问题:
我们下载的 centos、或者 ubuntu 的 docker 镜像,没有系统内核,只有运行需要的 lib 库等软件和文件。镜像使用的内核是宿主机的内核。所以同一台宿主机上的 docker 使用的内核都是一样的,都是宿主机的内核。 所以,如果宿主机系统为 centos,想在上面使用 docker 为 ubuntu 的特性,是无法实现的。
docker 下载镜像
docker pull [镜像名]
示例:
docker pull centos
关于 docker 镜像标签:如果不手动设置标签,镜像的标签默认为 latest :
[root@k8s-master ~]# docker images | grep centos
centos latest 5d0da3dc9764 5 months ago 231MB
查看本地宿主机上的所有镜像:docker images。每个镜像都有唯一的ID
[root@k8s-slave1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.aliyuncs.com/google_containers/kube-proxy v1.23.4 2114245ec4d6 13 days ago 112MB
rancher/mirrored-flannelcni-flannel v0.16.3 8cb5de74f107 4 weeks ago 59.7MB
rancher/mirrored-flannelcni-flannel-cni-plugin v1.0.1 ac40ce625740 5 weeks ago 8.1MB
centos latest 5d0da3dc9764 5 months ago 231MB
registry.aliyuncs.com/google_containers/pause 3.6 6270bb605e12 6 months ago 683kB
kubernetesui/metrics-scraper v1.0.7 7801cfc6d5c0 8 months ago 34.4MB
镜像导出
docker save -o [镜像压缩包的名称] centos:latest
说明:导出的镜像默认使用 tar 包的形式。
例如:
docker save -o centos.tar centos:latest
镜像导入
docker load --input centos.tar
或者
docker load < centos.tar
删除镜像(image)和删除容器(containers)
docker rmi [镜像名或者镜像ID]
强制删除:
docker rmi -f [镜像名或者镜像ID]
注意:
如果该镜像已经启动了容器,则该命令是无法删除镜像的。系统会提示该镜像启动过那个容器,并且给出该容器的ID,删除该容器后才能删除镜像。生产环境千万不要轻易执行强制删除命令!!!
5. docker 容器的操作
启动容器并输出 Hello world
docker run centos /bin/echo "Hello world"
注意:
该命令输出的 Hello world 是容器输出的,而不是宿主机输出的。该命令方式下,容器执行完 echo 这个任务后就终止运行了。
启动容器并命名
docker run --name [自定义的容器名称] -t -i [镜像名] /bin/bash
说明:
-t 是 tty,是指分配一个伪终端。-i 是 标准输入,因为要登陆进容器内部。该命令执行时会检查指定的[镜像名]在本地是否存在,如果不存在,就会到公共仓库中去下载。然后再启动容器,接着给该容器分配一个文件系统,挂在镜像的上面。最后还要给容器分配一个 IP 地址。
示例:
docker run --name mycentos -t -i centos /bin/bash
容器退出
执行 exit 命令退出容器,容器也终止了。
再次启动容器
先执行
docker ps -a
查看之前容器启动时的名称或者 ID ,再执行
docker start [容器名]
或者
docker start [容器ID]
就能启动刚才的容器了。
关闭容器
docker stop [容器名]
或者
docker stop [容器ID]
查看容器详细配置
docker inspect [容器名]
让一个容器结束运行后自动删除
docker run --rm [镜像名] /bin/echo "hehe"
执行完该命令后,使用命令 docker ps -a 看不到刚刚运行过的用于输出 hehe 的容器
删除容器:
docker rm [容器名或者容器ID]
二、种进入 Docker 容器的方法
1. 使用 attach 命令连接容器
docker attach [容器名] 或者 [容器ID]
attach 命令有如下缺点:
1.1 当你从多个终端同时使用 attach 命令连接到同一个容器后,多个终端显示的操作是同步的。也就是说你从A终端操作什么命令,在B终端也显示一样的命令和结果。同理,你在某个终端针对该容器的某个操作阻塞了或者异常了,那么其他的终端也同样不可操作了。
1.2 在 attach 的连接方式下使用 exit 退出容器后,该容器也会终止运行。
2. 使用 nsenter 命令连接容器
使用该命令连接容器,用 exit 命令退出容器后,容器不会终止运行。
2.1 nsenter 命令包含在 util-linux 里面,所以使用之前要先安装。
yum install -y util-linux
2.2 使用 nsenter 命令连接容器,需要获取容器的 PID。
可以使用 inspect 命令获取容器的详情:
docker inspect [容器名]或者[容器ID]
获取 docker 的第一个进程的 PID:
docker inspect --format "{{.State.Pid}}" mycentos
通过该 PID 连接容器:
nsenter --target [容器第一个进程的PID] --mount --uts --ipc --net --pid
写一个连接容器的脚本,命名为 docker_login.sh,脚本内容如下:
#!/bin/bash
#此脚本用来登录任意容器。使用方法:./docker_login [容器名]或者[容器ID]
docker_in(){
NAME_ID=$1
PID=$(docker inspect --format "{{.State.Pid}}" $NAME_ID)
#nsenter --target $PID --mount --uts --ipc --net --pid
nsenter --target $PID --mount --uts --ipc --net --pid /bin/bash
#nsenter --target $PID --mount --uts --ipc --net --pid /bin/bash 2>/dev/null
#nsenter --target $PID --mount --uts --ipc --net --pid /bin/bash >/dev/null 2>&1
#nsenter --target $PID --mount --uts --ipc --net --pid /bin/bash >/dev/null 2>&1 &
if (test $? -ne 0)
then
nsenter --target $PID --mount --uts --ipc --net --pid /bin/sh
fi
}
docker_in $1
3. 使用 exec 命令连接容器
docker exec -it [容器名] /bin/bash
使用该命令连接容器,exit 退出后容器仍然继续运行。
说明:
为什么使用 exec 和 nsenter 命令连接容器再退出就不会导致容器终止,而使用 attach 连接容器再退出,容器就终止运行了呢?
因为前两个命令都是另外启动一个新的 bash 来连接容器,当退出容器时,终止的只是它们建立的 bash,而容器原来的 bash 进程还在。相应的,attach 使用的是容器启动后的 bash,所以退出该 bash ,容器也就终止了。
总结:
脚本的方式适合单节点上的容器维护,缺点是每台主机上都放个脚本,增加维护成本。最简单最常用的方式其实是 exec ,一个命令,语法也很简单。三种 docker 的连接方式,选择哪个还是要看使用场景。
三、Docker 网络映射和数据卷管理
先复习一下 docker 的基本操作:
1. 使用镜像启动一个容器,并且容器在后台运行
命令:
docker run -d -P [镜像名]
示例:
docker run -d -P nginx
参数说明:
-d 是让容器在后台运行。
-P 是随机的端口映射。命令的执行结果,会返回启动的容器的完整 ID(64位数字和字母组成)。示例中,会自动将宿主机的一个随机端口映射到生成的容器中的80端口(nginx 的默认端口是 80)。
2. 查看容器日志
命令:
docker logs [容器名或者ID]
3. 启动容器并设置指定的映射端口
命令:
docker run -d -p [宿主机的端口]:[容器的端口] --name [给新容器指定名称] [镜像名或者ID]
示例:
docker run -d -p 3333:80 --name nginx-demo nginx
参数说明:
-p 用来设置指定的映射端口。做了端口映射之后,通过访问宿主机IP+映射到宿主机的端口,就能访问到docker中的服务。
4. 查看容器映射了哪些端口
命令:
docker port nginx-demo
5. 启动容器并设置指定的IP和映射端口
命令:
docker run -d -p [宿主机IP]:[宿主机端口]:[容器端口]
说明:
这个命令适用于宿主机存在多个 IP 地址的情况。
6. 启动容器并指定容器的端口,但不指定宿主机的端口
命令:
docker run -d -p [宿主机IP]::[容器端口]
说明:
这个命令适用于宿主机存在多个 IP 地址的情况。
7. 启动容器并指定容器使用的协议
命令:
docker run -d -p [宿主机端口]:[容器端口]:udp
说明:
-p 默认使用的是 tcp 协议。可以指定使用 udp 协议。
接下来本篇文章要讲的核心内容来了
8. 容器的数据存储
必须知道的常识:
容器的数据默认都存储在容器的卷里面,如果容器删除,数据也就没有了。
容器技术提供了一种方式,可以将宿主机的卷挂载到容器里面,这样就可以将容器的数据保存到宿主机上。
挂载参数是 -v,有两种使用方式:
【方式一】
-v /data
意思是:将宿主机的某目录挂载到容器的 /data 目录下。如果镜像(或者容器)中默认没有 /data 目录,挂载完成后会自动在容器中创建该目录。
登录容器,查看 /data 的磁盘挂载情况:
问题:
宿主机的哪个卷挂载到容器上了呢?
验证:
先在容器的 /data 目录创建一个文件 hehe。回到宿主机,使用 inspect 命令查看容器的详细信息,在 Mount 这段信息中找到 Source 这个部分。
进入 Source 后面的路径,可以查看到刚才创建的文件 hehe 。
进入宿主机的目录 /var/lib/docker/volumes/,通常可以看到该目录下有很多卷。每一个与宿主机进行了卷挂载的容器,它挂载的卷都在这个目录下。即 使用命令 docker inspect [容器名]或[容器ID] | grep Source 查到的路径名称与这里的目录名称是可以匹配上的。如下图所示:
结论:
挂载宿主机的卷到容器但不指定具体是哪个卷,这个时候系统会随机在宿主机的目录 /var/lib/docker/volumes/ 里面找一个卷挂载到容器上。
【方式二】
-v src:dst
意思是:将宿主机的目录 src 挂载到容器的 dst 目录下。这是更好的使用方式。
示例:
-> 在宿主机本地创建一个目录用于挂载给容器:
mkdir /data/docker-volume-nginx
-> 启动容器并挂载刚才创建的目录到容器的目录 /data 下:
docker run -d --name nginx-test2 -v /data/docker-volume-nginx/:/data nginx
-> 进入刚才创建的目录,在里面创建一个文件 mmm:
touch mmm
-> 登录容器,在 /data 目录中,看到刚才在宿主机中创建的目录 mmm:
sh /data/shell/docker_in.sh nginx-test2
具体操作过程如下截图所示:
四、Docker 数据卷容器实践
数据卷挂载应用场景:
开发测试环境和生产环境。
开发测试环境主要是用来挂载代码目录。生产环境主要是用来实现容器数据持久化,防止容器关闭时数据不可访问或者容器被删除时数据丢失。
1. 开发测试环境挂载数据卷
开发人员通常喜欢用办公电脑 Windows 系统来编写代码,那么怎样将本地的代码快速同步到 docker 环境中进行测试和打包?
以 VMware 为例,VMware 虚拟机的菜单中包含将办公电脑跟 Linux 虚拟机进行磁盘共享的功能,设置完该共享,然后再按照《Docker 入门私人笔记(三)》中将宿主机跟容器共享数据卷的方法设置共享即可。然后就实现了将办公机的本地磁盘跟 docker 数据卷共享。
2. 生产环境挂载数据卷
思路:
并不需要将每个容器都跟宿主机的磁盘配置共享(挂载数据卷)。而是在宿主机上启动一个容器,专门用来实现宿主机和容器的磁盘共享,可以称之为数据卷容器。
如果其他任何容器想实现跟宿主机做磁盘共享,只需在启动时使用 --volumes-from 参数调用数据卷容器即可。
说简单些,数据卷容器所做的事情只有一个:执行宿主机跟容器挂载数据卷的命令。其他容器来调用数据卷容器时,就等于在调用挂载数据卷的命令而已。
优势:
- 简化容器配置(不必在每个容器内进行挂载数据卷);
- 降低维护成本(当数据卷不再需要时也不用卸载)。
步骤:
2.1 启动一个专门用来挂载数据卷的容器:数据卷容器
命令:
docker run -d --name [自定义容器名] -v [宿主机的路径]:[容器的路径] [镜像名]
示例:
docker run -d --name volume-demo -v /data:/data nginx
验证:
登录数据卷容器 volume-demo 的目录 /data,确认能看到宿主机的目录 /data 中的文件即可。
2.2 启动一个新容器,调用数据卷容器的配置
命令:
docker run -d --name [自定义容器名] --volumes-from [专门挂载数据卷的容器名] [镜像名]
示例:
docker run -d --name nginx-volume-demo --volumes-from volume-demo nginx
验证:
登录新容器 nginx-volume-demo,确认跟数据卷容器 volume-demo 一样共享了宿主机的目录 /data 并且能看到里面的文件即可。
说明:
数据卷容器的运行状态,不影响引用它的容器的状态。以上面的示例来说明,即 数据卷容器 volume-demo 如果关闭,容器 nginx-volume-demo 的数据卷挂载完全不受影响。
另外,如果容器 nginx-volume-demo 重启,数据卷会自动挂载,无需重新挂载。
缺点:
调用数据卷容器只能按照数据卷容器的的挂载配置去挂载数据卷,即挂载目录固定。
五、手动构建 Docker 镜像
本文核心内容:基于现有容器手动创建一个镜像。
以创建一个 nginx 的镜像为例。步骤如下。
1. 使用镜像 centos 启动一个容器
docker run --name mynginx -it centos /bin/bash
2. 登录容器内安装 nginx
在阿里云的源中找到 epel 的地址
https://mirrors.aliyun.com/epel/
在容器内执行安装:
rpm -ivh https://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
安装nginx:
yum install -y nginx
注意:
- 在镜像中执行完在线安装之后,要执行 yum clean all,把没用的软件包和数据都清理掉,可以降低容器的大小(已验证)。
- 需要配置 nginx 在前台运行。因为 nginx 默认是在后台运行,容器启动之后马上又会退出(未验证)。具体操作方法是:
编辑 nginx 配置文件,vi /etc/nginx/nginx.conf,在里面增加一行配置:
daemon off;
这样 nginx 就能在前台运行了。
3. 将容器提交为一个本地镜像
命令:
docker commit -m "[备注]" [使用的容器的ID或者容器名] [自定义的镜像名]:[标签]
示例:
docker commit -m "My nginx" 5382f6e3d987 mynginx:v1
4. 验证:使用新创建的 nginx 镜像启动一个容器
命令:
docker run -d -p [宿主机的端口]:[容器的端口] [刚创建的镜像名]:[标签] [容器内执行的命令]
示例:
docker run -d -p 91:80 mynginx:v1 nginx
注意:
该命令的最后一个字段不是容器名或者标签等等,而是要在容器中执行的命令。