通过docker,我们交付的东西不再只是代码、配置文件、数据库定义等,而是整个应用程序运行环境:“OS+各种中间件、 类库+应用程序代码”。它所需的全部环境只是一台仅仅安装了兼容版本的Linux内核和二进制文件最小化的宿主机。主要特点是:
- 原生的Linux容器格式
- 使用Linux内核的namespace,能够隔离文件系统、进程、网络
- 文件系统隔离。每个容器有自己的root文件系统
- 网络隔离。不同容器间的网络默认是互相隔离的
- 资源隔离。使用Linux内核的Cgroup实现硬件资源分配
- 写时复制。提升了文件系统性能
- 日志。STDOUT、STDERR、STDIN都会记录日志
- 交互式shell。给容器提供了shell

docker run
- -i 交互模式运行容器,通常是-it一起使用
- -t 给容器分配输入终端,通常是-it一起使用
- 单独使用-d 会让容器在后台运行并马上退出控制台,同时返回容器id,docker run默认的cmd参数是/bin/bash,执行完此cmd参数后就关闭了。可以让cmd参数是一个 驻留在进程中长期运行的命令(例如tail -f /dev/null ),或者使用-itd解决启动失败的问题
- -p 主机端口:容器内端口
- --name 指定容器名,唯一,用来替代容器id
- -e 指定环境变量
- --env-file 可以是单个文件,也可以是多个文件
- --rm 一般用在开发调试过程中短期运行,等价于在容器推出后执行docker rm -v,即在退出容器时自动清理容器和挂载卷,所以与-d选项互斥
- -v
- --mount type=bind,source=宿主目录,target=容器目录
docker ps
- docker ps 显示所有正在运行的容器
- docker ps -a 显示所有容器,包括未运行的
- docker ps -l 显示最近创建的容器
- docker ps -a -q 此参数表示只显示容器ID
docker exec
docker attach可以attach到一个已经运行的容器的stdin,然后进行命令执行的动作。要注意从这个stdin中exit,会导致容器的停止
- d 表示只在内部执行某个命令,而不进入,例如
docker exec -d demo touch /etc/new_config_file
表示在此容器内创建文件 - exit退出容器
docker logs
- -f 实时查看内部日志
- -f --tail 10 实时打印最新10条
- -ft 同时打印时间
- Ctrl + c 退出日志
- 结合日志驱动实现自定义的日志打印
镜像类型
dangling类型:Repository和tag都为空
docker image ls -f dangling=true
查看
docker image prune
清空
更多常用命令
指令 | 描述 | eg |
---|---|---|
search | 从镜像仓库搜索镜像 | docker search nginx |
pull | 从镜像仓库拉取 | docker pull nginx:latest |
ls | 查看本地镜像 | docker image list |
images | 和list一样,不过后面跟镜像名,可以筛选 | docker images |
rmi | 从本地删除镜像(指定IMAGE ID) | docker rmi -f $(docker images -q) |
build | 从Dockerfile构建镜像 | docker build -t imageName:tagName dockerfileDir |
history | 查看镜像分层 | docker image history nginx |
push | 推送 | - |
prune | 移除未使用、未引用的镜像 | - |
tag | 标记目标镜像生成新版本的镜像 | docker tag nginx:1.11 nginx:v1 |
export | 导出容器为tar | docker export 容器id > nginx.tar |
import | 导入tar为容器 | docker image import nginx.tar nginx:1.11 |
save | 保存镜像为tar | docker image save nginx:1.11 > nginx1.11.tar |
load | 加载tar为镜像 | docker load < nginx1.11.tar |
run | 启动镜像为容器 | docker container run -itd --cpus 1 --name nginx02 (使用一个核) docker container run -itd --memory 512m --name nginx02(限制512m内存) |
ps | 列出容器, -a表示包括未运行的 | docker ps -a |
start | 启动容器 | docker start 容器名或id |
stop | 关闭容器 | docker stop 容器名或id |
restart | 重启容器 | docker start 容器名或id |
rm | 移除容器,示例命令表示移除所有容器 | docker rm -f $(docker ps -q -a) |
inspect | 查看容器详情 | docker inspect 容器名或id或镜像名:标签 |
exec | 进入容器 | docker exec -it 容器名或id bash |
logs | 查看内部日志 | docker logs 容器名或id |
kill | 杀掉运行中的容器 | docker kill $(docker ps -a -q) |
top | 查看某运行容器中的进程,不进入容器内部即可查出 | docker top demo |
stats | 查看某运行容器中的资源统计信息 | docker stats demo |
volume数据卷挂载容灾
保证数据存在于数据卷而不是容器中。在容器中的挂载点保存文件时,宿主机也能看到对应的映射文件
ls /var/lib/docker 查看image,containers,image存储位置
有两种挂载模式,第一种volume(推荐)
docker run -it -v my-volume:/mydata alpine sh
若不指定-v,则自动在/var/lib/docker/volumes创建一个挂载点(挂载点的名称没有可读性)。上述命名了一个挂载点,容器内的/mydata目录挂载在了/var/lib/docker/volumes/my-volume/_data目录。如果主机是空的而container中的目录有内容,那么docker会将container目录中的内容拷贝到主机中,但是如果主机中已经有内容,则会将container中的目录覆盖
第二种bind mount
host机器的目录路径必须为全路径,如果主机上的目录不存在,docker会自动创建该目录,如果container中的目录不存在,docker会自动创建该目录,无论container是否有数据被挂载的目录都会被host上的目录覆盖掉
ls /var/lib/docker/volumes/
docker volume ls
docker volume create nginx-vol
docker volume inspect nginx-vol
docker run -itd --privileged --name=nginx-test --mount src=nginx-vol,dst=/usr/share/nginx/html nginx
此时/usr/share/nginx/html中的文件夹与宿主主机cd /var/lib/docker/volumes/nginx-vol/_data文件夹相同。可在Dockerfile中使用VOLUME指令来给镜像添加一个或多个数据卷。--privileged表示容器拥有root权限
docker volume inspect my-volume #查看挂载目录和类型
四种网络模式
使用docker network ls查看所有网络
Host:使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好
Container: 通过为一个容器指定--net container:otherContainerName来依赖于另一个容器的网络,可以在被依赖的容器的网络中使用netstat -antp看到依赖的容器的端口详情
None: 基本用不上
Bridge: 依赖docker0这个网络接口,Docker默认使用bridge网络模式,每次启动镜像,它的容器的IP地址会变化。docker network create --subnet=172.20.0.0/16 --gateway 172.20.0.1 extnetwork
创建自定义的网络模式,然后docker run时指定--net extnetwork --ip 172.20.0.2即可分配自定义的网络,推荐使用自定义网络自动分配网络ip,例如docker network create extnetwork
。使用docker network rm extnetwork
删除。如果不指定网络模式,那么容器默认使用bridge模式的bridge网络,如果多个容器处于不同的bridge网络中,需要解决多个bridge网络之间的互连问题。一开始使用--link来连接网络,后来使用docker network connect sub_net_a1 sub_net_b2
解决,使用docker exec sub_net_a1 ping sub_net_b2
看是否可以连通
重要的点
不同容器间的访问,还可以通过宿主机的IP进行连接,注意不能是127.0.0.1,因为在容器中的127.0.0.1指的是本身所处的网络而不是宿主机的网络
例子
创建网络,例如lnmp处于同一个网络下
docker network create lnmp

注意数据库主机名就是数据库容器名
https://www.bilibili.com/video/av49731612?p=10
docker desktop
挂载时先到setting -> resources -> file sharing里勾上盘符,否则会"Unhandled exception: Drive has not been shared"
Dockerfile
解决项目依赖。bulid时把Dockerfile文件所处目录下的文件全都打包成镜像,Dockerfile每行命令生成1个临时镜像,放入缓存中(不需要缓存使用--no-cache),层层推进,最后生成一个最终的镜像。每个指令都使用大写。#表示注释
指令 | 作用 | eg |
---|---|---|
FROM | 依赖的镜像,第1个指令必须为FROM | - |
RUN | 构建镜像时需要内部执行的命令,默认使用bash模式(适合shell变量语法时),否则使用数组模式(不支持shell变量语法)例如RUN [ "apt-get", " install", "-y", "nginx" ] | RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME' |
EXPOSE | 运行容器后对外暴露的端口号 | - |
WORKDIR | 进入容器后的默认工作目录,ENTRYPOINT和/或CMD指定的程序会在这个目录下执行 | - |
ENV | 设置容器的环境变量,容器内使用env查看 | ENV RVM_PATH=/home/rvm RVM_ARCHFLAGS="-arch i386" |
COPY | build时拷贝宿主机的文件到镜像里 | - |
ADD | 和COPY类似。多了下载链接和自动解压tar包的功能 | - |
VOLUME | 指定容器内某些目录文件能被挂载到宿主机 | - |
CMD | 容器启动时内部执行的命令,和RUN的语法一样,注意CMD的命令会被docker run之后的指定参数全部替换 | |
ENTRYPOINT | 和CMD类似,此命令作为命令前缀,可用于接收docker run指定的要执行的命令参数或CMD中的命令参数,例如docker run指定了-g "daemon off;",若ENTRYPOINT 是/usr/sbin/nginx ,则会拼接为["/usr/sbin/nginx", "-g", "daemon off;"] |
|
LABEL | 为镜像添加元数据,通过docker inspect查看镜像中的标签信息 | LABEL location="New York" type="Data Center" role="Web Server" |
多阶段构建最小化镜像
基础镜像选择:
①scratch,这个版本是空镜像,当你的dockerfile文件里面不需要任何命令时使用
②Alpine,只有5M,但这个版本使用的标准库与大多数发行版不同,它使用的是 musl libc,这个库相比于 glibc 更小、更简单、更安全,但是与大家常用的标准库 glibc 并不兼容。有些官方会给出Alpine版本的基础镜像让我们依赖,例如golang:alpine,可以依赖这个来BUILD,然后用空镜像来RUN。对于没有alpine基础镜像的,需要使用诸如RUN apk add build-base
这样的命令保证编译环境不存在问题
docker build
例如本地构建
docker build -t="jamtur01/static_web:v1" .
git仓库构建(Dockerfile的目录要对应好,最好放在项目根目录)
docker build -t="jamtur01/static_web:v1" \ git@github.com:jamtur01/docker-static_web
构建失败调试
因为构建过程每个步骤都返回了一个id,可以用docker run命令来基于这次构建到目前为止已经成功的最后一步创建一个容器,然后执行失败步骤的命令来查看错误
docker push
同样,镜像仓库也支持从github等仓库导入,需要绑定,且需要仓库有Dockerfile文件
docker-compose
docker-compose的容器编排使得内部有关的容器都在同一个network下,所以可以互相通信,如果外部的容器需要访问,则需要指定-net为同一个network,注意如果不通过,默认在当前目录下识别docker-compose.yml的文件。如果是自定义路径,可以用以下方式启动
docker-compose -f "$COMPOSE_FILE_PATH" config &&
docker-compose --env-file="$ENV_FILE_PATH" -f "$COMPOSE_FILE_PATH" up
进入其中的一个容器使用以下方式
docker-compose -f "$COMPOSE_FILE_PATH" exec mongodb bash
只启动其中一个容器
docker-compose -f "$COMPOSE_FILE_PATH" up -d mongodb
网友评论