Docker之容器
1 容器简介
容器(Container):容器是一种轻量级、可移植、并将应用程序进行的打包的技术,使应用程序可以在几乎任何地方以相同的方式运行
•Docker将镜像文件运行起来后,产生的对象就是容器。容器相当于是镜像运行起来的一个实例。
•容器具备一定的生命周期。
•另外,可以借助docker ps命令查看运行的容器,如同在linux上利用ps命令查看运行着的进程那样。
2 容器与虚拟机
•容器和虚拟机一样,都会对物理硬件资源进行共享使用。
•容器和虚拟机的生命周期比较相似(创建、运行、暂停、关闭等等)。
•容器中或虚拟机中都可以安装各种应用,如redis、mysql、nginx等。也就是说,在容器中的操作,如同在一个虚拟机(操作系统)中操作一样。
•同虚拟机一样,容器创建后,会存储在宿主机上:linux上位于/var/lib/docker/containers下
注意:容器并不是虚拟机,但它们有很多相似的地方
•虚拟机的创建、启动和关闭都是基于一个完整的操作系统。一个虚拟机就是一个完整的操作系统。而容器直接运行在宿主机的内核上,其本质上以一系列进程的结合。
•容器是轻量级的,虚拟机是重量级的。首先容器不需要额外的资源来管理(不需要Hypervisor、Guest OS),虚拟机额外更多的性能消耗;其次创建、启动或关闭容器,如同创建、启动或者关闭进程那么轻松,而创建、启动、关闭一个操作系统就没那么方便了。
•也因此,意味着在给定的硬件上能运行更多数量的容器,甚至可以直接把Docker运行在虚拟机上。
3 容器生命周期
3.1 虚拟机的生命周期
3.2 容器的生命周期
4 容器生命周期管理
4.1 容器查看
# 查看机器上正在运行的所有容器
docker ps
# 查看宿主机上所有的容器(包括停止的)
docker ps -a
# 查看最后一次运行的容器
docker ps –l
# 查看停止的容器
docker ps -f status=exited
4.2 容器创建 – docker create
# 作用:
利用镜像创建出一个Created 状态的待启动容器
# 命令格式:
docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
# 命令参数(OPTIONS):查看更多
-t, --tty 分配一个伪TTY,也就是分配虚拟终端bash
-i, --interactive 以交互模式运行容器,加入-t-i这两个参数,容器启动后会直接进入容器。分配一个伪终端
--name 为容器起名,如果没有指定将会随机产生一个名称
# 命令参数(COMMAND\ARG):
COMMAND 表示容器启动后,需要在容器中执行的命令,如ps、ls 等命令
ARG 表示执行 COMMAND 时需要提供的一些参数,如ps 命令的 aux、ls命令的-a等等
# 命令演示:
# ps -A 提前预设一个命令,容器一启动就会执行
# 当容器启动-->执行ps -A,命令一执行完,容器就停止了,因为它不是可以夯住的命令
docker create --name test-container centos ps -A
docker create -ti --name test-container2 centos /bin/bash
# 我们拉的centous镜像是纯净版,里面没有sshd服务端,如果启了一个centos7的容器,宿主机不能直接用ssh连接容器(进到容器做交互)
# 要么装一个sshd服务端,要么下载第三方集成了sshd服务端的镜像。
# 这里用的-t,并不是真正的进到容器,只是分配一个伪终端,相当于启一个bash窗口,和宿主机做交互
下面以redis和centos镜像先创建容器,再启动,验证容器是否会夯住或直接停止
# 以centos镜像创建容器,然后启动
# 以下4个命令都只是创建出容器
docker create --name test-container1 centos:centos7
docker create --name test-container2 centos:centos7 /bin/bash
docker create -ti --name test-container3 centos:centos7
docker create -ti --name test-container4 centos:centos7 /bin/bash
# docker start 启动容器
test-container1和test-container2,启动后容器停止了,因为没有可以夯住的命令
test-container3和test-container4,启动后容器夯住了,维持后台运行
# 总结:centos容器启动后默认运行 /bin/bash;创建时如果加了 -i或-t参数,运行bash的命令没有结束,容器就不会停止
# 注:/bin/bash的作用是表示载入容器后运行bash ,docker中必须要保持一个进程的运行,要不然整个容器启动后就会马上kill掉
------------------------------------------------------------------------------------------------------------------------
# 以redis镜像创建容器,然后启动
# 以下6个命令都只是创建出容器
# redis容器启动后的docker-entrypoint.sh脚本进程,启动了redis-server服务,因此不用-ti,启动redis容器就会夯住
docker create --name test1 redis # 容器启动,维持后台运行
docker create --name test3 redis ps -A # 容器启动后执行ps -A命令,命令一执行完,容器就停止了
docker create -ti --name test2 redis # 容器启动,维持后台运行
docker create -ti --name test4 redis ps -A # 容器启动后执行ps -A命令,命令一执行完,容器就停止了
docker create -ti --name test5 redis /bin/bash # 容器启动后运行bash,因为有-it参数,运行bash的命令没有结束,容器就不会停止
docker create --name test6 redis /bin/bash # 容器启动后运行bash,没有-it参数,执行bash后就终止了
# docker start 启动容器
test1、test2、test5, 启动后容器夯住了,维持后台运行
test3、test4、test6,启动后容器停止了
容器一直运行的原因
Docker 容器启动后,默认会把容器内部第一个进程,也就是pid=1的程序作为docker容器是否正在运行的依据。如果docker 容器pid=1进程挂了,那么docker容器便会直接退出。这样的话,如果我们在前台维持一个运行的进程,docker 容器就会一直处于运行的状态中。
centos前台跑的是/bin/bash, redis前台跑的是redis-server(通过docker-entrypoint.sh脚本),mysql前台跑的是mysqld,nginx前台跑的nginx
-以后如果自己制作的镜像,运行起容器,必须有个可以夯住的前台进程
-如果该进程结束,该容器也就结束了
-比如 docker run -it --name=myredis redis
创建并启动容器,并且进入到redis
docker run -it --name=mycontainer centos:centos7
创建并启动容器,进入到一个纯净的centos7操作系统
如果用exit退出bash窗口,就会结束bin/bash命令,并且该操作系统(容器)也就停止了
4.3 容器启动 – docker start
# 作用:
将一个或多个处于创建状态或关闭状态的容器启动起来
# 命令格式:
docker start [OPTIONS] CONTAINER [CONTAINER...]
# 命令参数(OPTIONS):
-a, --attach 将当前shell的 STDOUT/STDERR 连接到容器上
-i, --interactive 将当前shell的 STDIN连接到容器上
# 命令演示:
docker ps -a
docker start -a 65ebc
docker start test-container2
4.4 容器创建并启动 – docker run
# 作用:
利用镜像创建并启动一个容器
# 命令格式:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
# 命令参数(OPTIONS):查看更多
-t, --tty 分配一个伪TTY,也就是分配虚拟终端,表示容器启动后会进入其命令行
-i, --interactive 以交互模式运行容器,加入-t-i这两个参数,容器启动后会直接进入容器。分配一个伪终端
--name 为容器起名,如果没有指定将会随机产生一个名称
-d, --detach 创建一个守护进程在后台运行容器并打印出容器ID,不会自动登录容器,如果只加-i -t两个参数,创建后就会自动进入容器
--rm 当容器退出运行后,自动删除容器
# 命令参数(COMMAND\ARG):
COMMAND 表示容器启动后,需要在容器中执行的命令,如ps、ls 等命令
ARG 表示执行 COMMAND 时需要提供的一些参数,如ps 命令的 aux、ls命令的-a等等
# 命令演示:
# 注意,docker run 镜像, 如果本地没有该镜像,会先pull最新版镜像,再执行docker run
docker run --name test1 centos:centos7 # 创建并启动test1,启动后容器就停止了
docker run --name test2 centos:centos7 /bin/bash # 创建并启动test2,启动后容器就停止了
docker run -ti --name test3 centos:centos7 # 创建并启动test3,启动后运行/bin/bash交互(根路径下),exit退出后,容器就停止了
docker run -ti --name test4 centos:centos7 /bin/bash # 创建并启动test4,启动后运行/bin/bash交互(根路径下),exit退出后,容器就停止了
docker run -ti --name test5 redis # 创建并启动test5,启动后进入到redis前端,exit退出后,容器就停止了
docker run -ti --name test6 redis /bin/bash # 创建并启动test6,启动后运行/bin/bash交互(/data路径下),exit退出后,容器就停止了
docker run -d --name t1 centos:centos7 # 创建并启动t1,启动后容器就停止了
docker run -di --name t2 centos:centos7 # 创建并启动t2,启动后容器维持后台运行
docker run -d --name t3 redis # 创建并启动t3,启动后容器维持后台运行
docker run -dti --name t4 redis # 创建并启动t4,启动后容器维持后台运行
4.5 docker run 与 docker create + docker start
docker run 相当于 docker create + docker start –a 前台模式
docker run -d 相当于 docker create + docker start 后台模式
4.6 容器暂停 – docker pause
# 作用:
暂停一个或多个处于运行状态的容器
# 命令格式:
docker pause CONTAINER [CONTAINER...]
# 命令参数(OPTIONS):
无
# 命令演示
docker ps -a
docker pause test-container2
docker ps -a # 容器是Pause状态
4.7 容器取消暂停 – docker unpause
# 作用:
取消一个或多个处于暂停状态的容器,恢复运行
# 命令格式:
docker unpause CONTAINER [CONTAINER...]
# 命令参数(OPTIONS):
无
# 命令演示:
docker unpause test-container2
docker ps -a # 处于运行状态
4.8 容器关闭 – docker stop
# 作用:
关闭一个或多个处于暂停状态或者运行状态的容器
# 命令格式:
docker stop [OPTIONS] CONTAINER [CONTAINER...]
# 命令参数(OPTIONS):
-t, --time int 关闭前,等待的时间,单位秒(默认 10s)
# 命令演示:
docker stop -t 1 容器id
4.9 容器终止 – docker kill
# 作用:
强制并立即关闭一个或多个处于暂停状态或者运行状态的容器
# 命令格式:
docker kill [OPTIONS] CONTAINER [CONTAINER...]
# 命令参数(OPTIONS):
-s, --signal string 指定发送给容器的关闭信号 (默认“KILL”信号)
# 命令演示:
docker kill test-container2
4.10 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重启、容器内部进程运行发生错误等等“异常原因”。
4.11 容器重启 – docker restart
# 作用:
重启一个或多个处于运行状态、暂停状态、关闭状态或者新建状态的容器
该命令相当于stop和start命令的结合
# 命令格式:
docker restart [OPTIONS] CONTAINER [CONTAINER...]
# 命令参数(OPTIONS):
-t, --time int 重启前,等待的时间,单位秒(默认 10s)
实则是关闭前等待的时间
4.12 容器删除 – docker container rm
# 作用:
删除一个或多个容器
# 命令格式:
docker container rm [OPTIONS] CONTAINER [CONTAINER...]
或者 docker rm [OPTIONS] CONTAINER [CONTAINER...]
# 命令参数(OPTIONS):
-f, --force 强行删除容器(会使用 SIGKILL信号)
-v, --volumes 同时删除绑定在容器上的数据卷
# 命令演示
docker rm -f 容器id 容器名
docker rm 8379 7380 1023 # 可以放多个id,批量删除
docker rm `docker ps -a -q` # 删除所有容器
5 容器信息查看
5.1 容器详细信息 – docker container inspect
多个容器互通(多个机器通信)的几种方式:
方式一:ip地址(局域网,默认网段172.17.0.x ),都连到一个网关172.17.255.255(宿主机虚拟出的网卡)。django项目连mysql容器,直接连容器ip。
方式二:端口映射(映射到宿主机,通过宿主机通信)
方式三:通过主机名
# 作用:
查看本地一个或多个容器的详细信息
# 命令格式:
docker container inspect [OPTIONS] CONTAINER [CONTAINER...]
或者 docker inspect [OPTIONS] CONTAINER [CONTAINER...]
# 命令参数(OPTIONS):
-f, --format string 利用特定Go语言的format格式输出结果
-s, --size 显示总大小
# 命令演示
docker container inspect 容器id
docker inspect --format='{{.NetworkSettings.IPAddress}}' 容器ID # 仅查看ip地址
5.2 容器日志信息 – docker logs
# 作用:
查看容器的日志信息
# 命令格式:
docker logs [OPTIONS] CONTAINER
# 命令参数(OPTIONS):
--details 显示日志的额外信息
-f, --follow 动态跟踪显示日志信息
--since string 只显示某事时间节点之后的
--tail string 显示倒数的行数(默认全部)
-t, --timestamps 显示timestamps时间
--until string 只显示某事时间节点之前的
# 注意:
容器日志中记录的是容器主进程的输出STDOUT\STDERR
5.3 容器重命名 – docker rename
# 作用:
修改容器的名称
# 命令格式:
docker rename CONTAINER NEW_NAME
# 命令参数(OPTIONS):
无
6 容器运行时操作
6.1 容器连接 – docker attach
# 作用:
将当前终端的STDIN、STDOUT、STDERR绑定到正在运行的容器的主进程上实现连接
# 命令格式:
docker attach [OPTIONS] CONTAINER
# 命令参数(OPTIONS):
--no-stdin 不绑定STDIN
6.2 容器中执行新命令 – docker exec
# 作用:
在容器中运行一个命令
# 命令格式:
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
# 命令参数(OPTIONS):
-d, --detach 后台运行命令
-i, --interactive 即使没连接容器,也将当前的STDIN绑定上
-t, --tty 分配一个虚拟终端
-w, --workdir string 指定在容器中的工作目录
-e, --env list 设置容器中运行时的环境变量
# 以守护进程方式,启动了centos容器,后台运行
docker run -dti --name test1 centos:centos7
# 执行-ti 命令,运行bash,新建一个bash跟容器进行交互
docker exec -ti test1 /bin/bash
进入容器的几种方式(并不是真进入)
第一种:docker exec -it 容器id /bin/bash
要后台运行中的容器才能利用bash做交互
-it 分配一个bash,如果是跑的centos容器,它只是类似于一个操作系统,通过查看它的进程,id1这个进程应该是系统sys,而容器里显示的是bash,也就是/bin/bash这个命令执行的进程。
exec真正的作用是在容器内执行命令,如docker exec 容器id ls ==>执行ls命令
只不过正好 /bin/bash命令创建了bash,可以跟宿主机做交互
第二种:ssh连接(容器内部装sshd服务端,它会监听22端口)
问题:bash到底是t分配的,还是/bin/bash命令创建的?
7 其他操作
7.1 退出当前容器
exit
docker run -it # 创建并启动时直接进入容器,相当于一个终端在运行,exit退出后,这个终端就停止了,即容器停止了
docker run -d # 创建并启动挂在后台运行,相当于一个终端在运行,再用exec连进去,又分配了一个伪终端,用exit退出,退出的是伪终端的bash,而容器并不会停止
7.2 文件拷贝
应用:如果项目就放在容器内跑,需要把项目依赖的文件拷贝到容器内
# 从宿主机拷贝到容器内部
docker cp 文件/目录 容器名/id:容器目录
docker cp lqz.txt 690f:/home # 把lqz.txt文件拷贝到id为690f的容器的/home路径下
# 从容器内部拷贝到宿主机
docker cp 容器名/id:容器目录 目标目录
docker cp 690f:/home/lqz.txt /app # 把id为690f的容器内home目录下的lqz.txt文件拷贝到宿主机的app目录下
7.3 目录挂载
我们可以在创建容器的时候,将宿主机的目录与容器内的目录进行映射,这样我们就可以通过修改宿主机某个目录的文件从而去影响容器。
创建容器 添加-v参数 后边为 宿主机目录:容器目录,例如:
docker run -di --name=mycentos -v /usr/local/myhtml:/usr/local/myhtml centos:centos7
-v:表示目录映射关系(前者是宿主机目录,后者是映射到宿主机上的容器目录),可以使用多个-v做多个目录或文件映射。注意:最好做目录映射,在宿主机上做修改,然后共享到容器上。因为容器删除后,目录里的数据就没有了,需要把数据映射到宿主机上保存。
如果你共享的是多级的目录,可能会出现权限不足的提示。这是因为CentOS7中的安全模块selinux把权限禁掉了,我们需要添加参数 --privileged=true 来解决挂载的目录没有权限的问题。
7.4 端口映射
应用:在云服务器下载redis,mysql镜像,跑起容器,跟宿主机做端口映射;进到redis容器内,存入数据-->本地客户端远程连6377端口,能够拿到容器内的数据,相当于通过云服务器(宿主机)访问到容器内6379端口的redis。
服务端根本不用安装redis或mysql,只用跑容器,客户端远程访问服务器-->映射到容器的端口。
# redis启动,docker exct 容器id pwd 查看进入路径,是在data目录下,centos进入是在根路径下
docker run -di -p 6377:6379 redis:latest
# 了解:/usr/local/bin/docker-entrypoint.sh
redis容器启动后的docker-entrypoint.sh进程(启动redis-server服务的进程),在这个路径下
-p:表示端口映射,前者是宿主机端口,后者是容器内的映射端口(如:把容器的80端口映射到宿主机的80端口,访问宿主机80端口就是访问容器的80端口)。可以使用多个-p做多个端口映射。
7.5 应用部署
1 MySQL部署
# 在容器内部署mysql
# -e表示环境变量,MYSQL_ROOT_PASSWORD 是root用户的登陆密码
# 它是往容器的环境变量(env)中加了key:val,即“MYSQL_ROOT_PASSWORD=123456”,mysql启动时去环境变量获取。这种方式比密码放到项目配置文件更安全。
# -p代表端口映射,格式为宿主机映射端口:容器运行端口
# 创建容器
docker run -di --name=mysql -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
# 官方提供的,它多了-v目录挂载
docker run --name some-mysql -v /my/own/datadir:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
2 Nginx部署
# 在容器内部署Nginx,如果宿主机80端口被占用了,可以换一个,如8080:80
docker run -di --name=mynginx -p 80:80 nginx
3 Redis部署
docker run -di --name=myredis -p 6377:6379 redis
操作步骤
-1 mkdir /reids /redis/conf /redis/data
-2 vim /redis/conf/redis.conf
# 宿主机配置文件
bind 0.0.0.0
daemonize NO # 不以后台进行
protected-mode no # 严格模式
requirepass 123456 # redis密码
-3 创建并运行容器
# 1、做了多个-v目录挂载,把redis配置文件和数据路径做了映射,redis配置了持久化,set数据会在data目录生成文件保存
# 2、redis-server /etc/redis/redis.conf 启动命令,以容器内部此路径下的配置文件启动
# 3、--appendonly yes 配置数据持久化
docker run -p 6379:6379 --name myredis -v /redis/conf/redis.conf:/etc/redis/redis.conf
-v /redis/data:/data -di redis redis-server /etc/redis/redis.conf --appendonly yes
-4 本地window机器上远程连接到了docker里的redis
-5 cmd窗口下:
redis-cli -h 10.0.0.200 -p 6379
-6 认证:
auth 123456
-7 写入数据:
set name lqz
-8 保存数据:
save或者是bgsave # redis容器配置文件没有配置数据持久化,重启容器后,数据就没有了
-9 在宿主机的/redis/data路径下就能看到一个文件
-10 不管重启多少次redis容器,数据都还在
-11 删除这个redis容器,宿主机上保存了配置文件和数据,新启的redis容器只要文件挂载到宿主机,就能用之前的配置和数据
8 环境变量相关
# 启动容器时,加入-e 参数
docker run -di --name=python -e name=zl -e age=18 python:3.6
# 进入容器
docker exec -ti python /bin/bash
# 查看环境变量
root@2ad974090bfd:/# env
name=zl
age=18
存在于环境变量中
环境变量应用
# django项目,settings.py中配置mysql参数
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'luffy',
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'luffy',
# 'PASSWORD': 'Luffy123?',
'PASSWORD':os.environ.get('MYSQL_ROOT_PASSWORD') 从环境变量中以MYSQL_ROOT_PASSWORD为key取值
'CHARSET': 'utf8',
}
}
# 启动django项目容器时,把mysql密码写入环境变量
docker run -di --name=mydjango -e MYSQL_ROOT_PASSWORD=Luffy123? django2.0:v1