Docker - 容器
一:容器简介
1.简介
容器是一种轻量级、可移植、并将应用程序进行的打包的技术,使应用程序可以在几乎任何地方以相同的方式运行
- Docker将镜像文件运行起来后,产生的对象就是容器
- 容器相当于是镜像运行起来的一个实例
- 容器具备一定的生命周期
- 可以借助docker ps命令查看运行的容器,如同在linux上利用ps命令查看运行着的进程那样
2.容器 与 虚拟机
- 容器和虚拟机一样,都会对物理硬件资源进行共享使用
- 容器和虚拟机的生命周期比较相似(创建、运行、暂停、关闭等等)
- 容器中或虚拟机中都可以安装各种应用,如redis、mysql、nginx等。也就是说,在容器中的操作,如同在一个虚拟机(操作系统)中操作一样
- 同虚拟机一样,容器创建后,会存储在宿主机上:linux上位于
/var/lib/docker/containers
容器并不是虚拟机,但它们有很多相似的地方
- 虚拟机的创建、启动和关闭都是基于一个完整的操作系统。一个虚拟机就是一个完整的操作系统
- 而容器直接运行在宿主机的内核上,其本质上以一系列进程的结合
- 容器是轻量级的,虚拟机是重量级的。首先容器不需要额外的资源来管理(不需要Hypervisor、Guest OS),虚拟机额外更多的性能消耗;其次创建、启动或关闭容器,如同创建、启动或者关闭进程那么轻松,而创建、启动、关闭一个操作系统就没那么方便了
- 也因此,意味着在给定的硬件上能运行更多数量的容器,甚至可以直接把Docker运行在虚拟机上
3.生命周期
虚拟机的生命周期
Docker的生命周期
二:容器生命周期管理
0.查看容器列表
选项 | 释义 |
---|---|
-a | 列出当前正在运行的容器+之前运行过的容器 |
-n=? | 显示最近创建的容器 |
-q | 只显示容器的编号 |
docker ps # 查看所有正在运行的容器
docker ps -a # 查看所有正在运行的容器(包括之前运行过的)
1.创建与启动容器
在 Docker 中,真正对外提供服务的还是容器
在Docker容器中,至少有1个应用程序运行在前台
语法
# 创建容器
docker create [选项] [镜像ID]|[镜像名称] [命令]
# 启动容器
docker start [选项] [镜像ID]|[镜像名称] [命令]
# 创建并启动容器
docker run [选项] [镜像ID]|[镜像名称] [命令]
# 这里的 [命令] 是镜像内部默认的命令:Cmd中的,可以用inspect查看
docker run 相当于 docker create + docker start –a # 前台模式
docker run -d 相当于 docker create + docker start # 后台模式
选项
选项 | 释义 |
---|---|
-d | 以守护进程方式运行 |
-e | 设置容器中的环境变量 |
-h | 指定容器内的主机名 |
-i | 保持标准输出打开 |
-p | 指定映射端口 [宿主主机端口号:容器内部端口号] |
-P | 随机映射端口 |
-t | 分配一个伪终端 |
-v | 挂载目录(数据卷)到容器 (使用 docker commit 时,挂载目录无法保存到镜像) |
--rm | 当容器生命周期结束时,自动删除该容器 |
--link | 链接到另一个容器 |
--name | 为启动的容器设置一个名字(也将名称解析到Docker DNS中) |
--network | 指定使用哪个网络(bridge、host、none、container) |
实例
docker run -d --name nginx -p 80:80 nginx
# 会运行在前台(不推荐)
docker run nginx:1.19.5
# 以守护进程的方式启动
docker run -d nginx:1.19.5
# 指定启动的名称(也将名称加入到Docker DNS中)
docker run -d --name nginx_bak nginx:1.19.5
# 容器生命周期结束后自动删除
docker run -d --rm nginx:1.19.5
# 查看
iptables -vnL
# 启动 并 进入容器
docker run -it centos /bin/bash
# 挂载
docker run -d --rm -v /root/django:/data /python:3.6.8
# 设置环境变量
docker run --name mysql_server -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.32
特点
1.检查本地是否有所需镜像(如果没有,就立即去相应的镜像仓库下载)
2.根据参数启动
2.暂停 与 取消暂停容器
容器可以被暂停,也可以恢复运行
# 暂停1个容器
docker pause [容器ID|容器名称]
# 恢复运行1个容器
docker unpause [容器ID|容器名称]
3.停止容器
docker 终止容器是首先向容器发送 SIGTERM
信号,等待一段时间超时后(默认 10 秒)
再发送 SIGKILL
信号 来终止容器
实例
# 关闭所有容器
docker stop $(docker ps -qa) # 停止所有的容器
# 先启动nginx
[root@localhost ~]# docker run -d --name nginx -p 80:80 nginx
87d4a352b7543be1aa5abaeafafbd2c7dbda236505b3159d975de1f158e04e23
# 查看已启动的容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
87d4a352b754 nginx "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp nginx
# 关闭该容器
[root@localhost ~]# docker stop nginx
nginx
# 再次查看已启动的容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 此时,可以直接用start再次启动该容器
[root@localhost ~]# docker start nginx
nginx
# 再一次查看已启动的容器(这里可以看到,启动的时间是第1次启动的时间,并不是再次启动的时间)
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
87d4a352b754 nginx "/docker-entrypoint.…" 3 minutes ago Up 16 seconds 0.0.0.0:80->80/tcp nginx
4.终止容器
强制并立即关闭一个或多个处于暂停状态或者运行状态的容器
选项 | 释义 |
---|---|
-s,--signal string | 指定发送给容器的关闭信号 (默认“KILL”信号) |
docker kill [选项] [容器ID|容器名称]
docker stop和docker kill的区别
# 一 前提知识点:
1 Linux其中两种终止进程的信号是:SIGTERM和SIGKILL
2 SIGKILL信号:无条件终止进程信号。
进程接收到该信号会立即终止,不进行清理和暂存工作。
该信号不能被忽略、处理和阻塞,它向系统管理员提供了可以杀死任何进程的方法。
3 SIGTERM信号:程序终结信号,可以由kill命令产生。
与SIGKILL不同的是,SIGTERM信号可以被阻塞和终止,以便程序在退出前可以保存工作或清理临时文件等。
# 二 docker stop 会先发出SIGTERM信号给进程,告诉进程即将会被关闭。在-t指定的等待时间过了之后,将会立即发出SIGKILL信号,直接关闭容器。
# 三 docker kill 直接发出SIGKILL信号关闭容器。但也可以通过-s参数修改发出的信号。
# 四 因此会发现在docker stop的等过过程中,如果终止docker stop的执行,容器最终没有被关闭。而docker kill几乎是立刻发生,无法撤销。
# 五 此外还有些异常原因也会导致容器被关闭,比如docker daemon重启、容器内部进程运行发生错误等等“异常原因”。
5.重启容器
重启一个或多个处于运行状态、暂停状态、关闭状态或者新建状态的容器
该命令相当于stop和start命令的结合
选项 | 释义 |
---|---|
-f | 强行删除容器(会使用 SIGKILL信号) |
-v | 同时删除绑定在容器上的数据卷 |
docker rm [选项] [容器ID|容器名称]
6.进入容器
在使用容器的过程中,难免需要进入容器进行排查问题
下面介绍一下进入容器的几种方式
1.attach
通过管道连接容器内的PID为1的进程
attach 是最早 docker 官方推出的进入容器的命令了,不过使用该命令有一个问题
当多个窗口同时使用该命令进入该容器时,所有的窗口都会同步显示
如果有一个窗口阻塞了,那么其他窗口也无法再进行操作,当所有窗口退出时,容器结束
docker attach nginx
缺点:
- 没有提供可执行命令的地方
- 当
attach
结束时,容器也跟着结束了(终止的是在前台运行的进程)
2.exec
既 attach 之后,exec 是官方推出的有一个新的进入容器的命令
这个命令相当于在容器中执行一个命令
在宿主主机上 通过exec的方式 在容器内执行某个命令(在外部执行内部的命令)
选项 | 释义 |
---|---|
-i | 打开标准输出 |
-t | 创建1个伪终端 |
docker exec -it [容器ID]
# 实例
docker exec 容器名称 bash
# 退出容器
exit
# 每天5点定时清理日志
00 05 * * * docker exec 容器名 > /eoor/django.log
3.nsenter
(这是Linux中的命令)创建1个管道,连接容器
需要配合 docker inspect
来使用(早期没有 exec 命令时,企业当中最长用的方式之一)
Docker 是用 golang 语言开发,所以它也支持 go 语言的摸版语法
nsenter --target $( docker inspect -f {{.State.Pid}}
nginxv1 ) --mount --uts --ipc --net --pid
4.ssh
在生产环境中排除了使用 docker attach 命令进入容器之后,相信大家第一个想到的就是 ssh
在镜像(或容器) 中安装 SSH Server,这样就能保证多人进入容器且相互之间不受干扰了,相信大家在当前的生产环境中(没有 使用 Docker 的情况)也是这样做的
但是使用了 Docker 容器之后不建议使用 ssh 进入到 Docker 容器内
5.总结
进入 docker container 中一般情况下有 4 种方式,最常用的是 exec
和 nsenter
这2种
Nsenter 和 exec 之间的区别?
- Exec 是 docker 自带的命令,Nsenter 是 Linux 提供的命令
- Exec 相当于在容器内执行一个命令,而 Nsenter 是仅仅进入容器之中而已
7.退出容器
# 容器停止并退出
exit
# 容器不停止 退出
Ctrl + P + Q
8.删除容器
普通删除
可以使用 docker rm
命令来删除处于终止或退出状态的容器
语法
docker rm 容器名
强制删除
强制删除一个正在运行的容器
docker rm 容器名 # 删除指定的容器(不能删除正在运行的容器)
docker rm -f 容器名 # 强制删除指定的容器
docker rm -f $(docker ps -qa) # 删除所有的容器
docker ps -qa | xargs dicker rm # 删除所有的容器(使用管道符)
实例
# 删除所有已停止的容器
docker rm $(docker ps -a -q)
# 删除所有容器(慎用)
docker rm -f $(docker ps -a -q)
三:其他常用命令
查看容器详情信息
用于查看本地一个或多个容器的详细信息
选项 | 释义 |
---|---|
-f | 利用特定Go语言的format格式输出结果 |
-s | 显示总大小 |
# 语法
docker inspect [选项] [容器ID]
# 实例
[root@localhost ~]# docker inspect 7537a7662db9
[
{
"Id": "7537a7662db9e42a2a881fc239245e632b885173dfd3eca36fdca91f46e7f657",
"Created": "2020-12-01T10:23:41.90270839Z",
"Path": "/docker-entrypoint.sh",
"Args": [
....
后台启动容器
# 命令 docker run -d 镜像名
[root@localhost ~]# docker run -d centos
6ab985f8e3b0bf5384389d291e3bdb94175a285204a6b054f541a59eeb2eaff9
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 问题:docker ps之后,发现centos容器停止了
常见的坑:
docker 容器使用后台运行,就必须要有1个前台进程
如果docker发现没有前台进程,就会自动停止
查看日志
选项 | 释义 |
---|---|
-tf | 显示日志 |
--tail | 要显示的日志条数 |
# 语法
docker logs -f -t --tail 10 容器ID
# 编写一段shell脚本
[root@localhost ~]# docker run -d centos /bin/sh -c "while true; do echo Darker; sleep 1; done"
e665be69f9129b3e962309f091a5e87af363254e270f4ab223379f70dde7da92
# 查看正在运行的容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e665be69f912 centos "/bin/sh -c 'while t…" 12 seconds ago Up 11 seconds angry_turing
# 查看容器的日志
[root@localhost ~]# docker logs -tf --tail 10 e665be69f912
2020-12-01T08:09:57.431354440Z Darker
2020-12-01T08:09:58.435476619Z Darker
2020-12-01T08:09:59.440251520Z Darker
2020-12-01T08:10:00.442683974Z Darker
2020-12-01T08:10:01.448639433Z Darker
2020-12-01T08:10:02.453106883Z Darker
2020-12-01T08:10:03.457659408Z Darker
2020-12-01T08:10:04.461011131Z Darker
2020-12-01T08:10:05.464084959Z Darker
查看容器中的进程信息
# 语法
docker top 容器ID
# 实例
[root@localhost ~]# docker top 7537a7662db9
UID PID PPID C STIME TTY TIME CMD
root 4855 4838 0 18:23 ? 00:00:00 nginx: master process nginx -g daemon off;
101 4905 4855 0 18:23 ? 00:00:00 nginx: worker process
容器重命名
# 语法
docker rename [容器ID] 容器的新名称
# 实例
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7537a7662db9 nginx "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp awesome_ride
[root@localhost ~]# docker rename 7537a7662db9 my_nginx
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7537a7662db9 nginx "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp my_nginx
从容器内拷贝文件到主机上
# 语法
docker cp [容器ID]:[容器内路径] [宿主主机路径]
docker cp [宿主主机路径] [容器ID]:[容器内路径]
# 查看当前主机目录
[root@localhost ~]# ls
anaconda-ks.cfg
# 启动 并 进入容器
[root@localhost ~]# docker run -it centos /bin/bash
# 查看容器内的目录(当前是在根目录)
[root@9575f94d0a03 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
# 在容器内创建1个文件
[root@9575f94d0a03 /]# touch darker.txt
# 退出该容器
[root@9575f94d0a03 /]# exit
exit
# 查看所有容器(为了找到刚才的容器ID)
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9575f94d0a03 centos "/bin/bash" 3 minutes ago Exited (0) 17 seconds ago wonderful_driscoll
e015ce3ec587 centos "/bin/bash" 5 minutes ago Exited (0) 5 minutes ago naughty_chaplygin
# 将刚刚在容器中创建的文件拷贝到主机上
[root@localhost ~]# docker cp 9575f94d0a03:/darker.txt /home
四:总结
练习
1.安装并启动mysql
# 拉取镜像
[root@localhost ~]# docker pull mysql:5.7.32
# 运行,并设置root密码
[root@localhost ~]# docker run --name mysql_server -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.32
# 查看已启动容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9ce38e811c19 mysql:5.7.32 "docker-entrypoint.s…" 9 seconds ago Up 8 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp mysql_server
# 进入该容器,进行操作(此时,localhost ~ 会变成该容器的id)
[root@localhost ~]# docker exec -it mysql_server bash
root@9ce38e811c19:/# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.7.32 MySQL Community Server (GPL)
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
# 此时,也可以通过Navicat等工具,远程连接该MySQL
ssh通道连接服务器的,MySQL账号密码用该MySQL容器的
2.安装并启动nginx,并打开指定网页
# 先创建1个目录,用于挂载
mkdir /test
# 在该目录下创建一个index.html
vim /test/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
# 运行nginx,端口映射 80:80 将宿主机的/test/挂载到/usr/share/nginx/html中
docker run -d -it --name nginx_service -v /test/:/usr/share/nginx/html -p 80:80 nginx
# 访问
curl 127.0.0.1:80/index.html