Docker
参考
本文由于平时用作个人总结,参考了许多文章但因时间较久难以对应寻找,如有引用请见谅并联系我添加引用。
Dokcer概述
Motivation
-
环境管理复杂
-> (一个应用牵涉到太多环境配置 若开发和生产环境都需要一一配置 不仅效率极低而且容易出错且难以跨平台 难以管理) -> Docker相当于将应用及其运行环境一起打包交付成镜像 且非常轻量级 -
云计算时代 硬件管理问题解决 中间件相关问题依然存在
虚拟化手段的变化 (虚拟化手段用于满足用户按需使用以及保证可用性和隔离性)
用户只需运行环境而非OS
->更加轻量级
的LXC - Linux Container -
Docker相比LXC的移动性 - LXC缺少标准化的描述手段和
容器的可迁移性
导致其构建出的环境难于迁移和标准化管理 Docker在这个问题上做出实质性的革新 是docker最独特的地方
Docker简介
-
Docker 是一个开源的应用容器引擎 让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中 然后发布到任何流行的 Linux或Windows机器上 也可以实现
虚拟化
容器是完全使用沙箱
机制 相互之间不会有任何接口 -
是 PaaS 提供商 dotCloud 开源的一个基于
LXC
(Linux Container 一种内核虚拟化技术 ) 的高级容器引擎 源代码托管在 Github 上 基于go语言并遵从Apache2.0协议开源 -
使用C/S架构 使用远程API来管理和创建Docker容器 Docker 容器通过 Docker 镜像来创建 容器与镜像的关系类似于面向对象编程中的对象与类
与传统虚拟化技术区别
-
传统虚拟机是虚拟一套硬件 在其上运行完整OS 再安装环境运行新的应用
-
Docker容器直接运行在宿主机上
没有自己的内核
也没有虚拟硬件(不准确地说可以理解为作为宿主机的进程运行 -
容器间互相隔离 有一个属于自己的文件系统
Docker
典型场景
- Automating the packaging and deployment of applications(使应用的打包与部署自动化)
- Creation of lightweight, private PAAS environments(创建轻量、私密的PAAS环境)
- Automated testing and continuous integration/deployment(实现自动化测试和持续的集成/部署)
- Deploying and scaling web apps, databases and backend services(部署与扩展webapp、数据库和后台服务)
则对于DevOps
- 应用更快速高效的交付和部署(打包成镜像
- 更便捷的升级和扩缩容
- 更简单运维
- 更高效计算资源利用
局限
- Docker是基于Linux 64bit的 无法在32bit的linux/Windows/unix环境下使用
- LXC是基于cgroup等linux kernel功能的 因此container的guest系统只能是linux base的
- 隔离性相比KVM之类的虚拟化方案还是有些欠缺 所有container公用一部分的运行库
- 网络管理相对简单 主要是基于namespace隔离
- cgroup的cpu和cpuset提供的cpu功能相比KVM的等虚拟化方案相比难以度量(所以dotcloud主要是按内存收费)
Docker对disk的管理比较有限
- container随着用户进程的停止而销毁 container中的log等用户数据不便收集
基础架构(重要)
Docker中三个基础概念
- 镜像 - image 相当于一个root文件系统 包含了一些运行环境 是一个模版
- 容器 - container 是image的实例 可以被
创建、启动、暂停、停止、删除
- 仓库 - 存放镜像的仓库 分为公有仓库和私有仓库 官方DockerHub
架构
C/S架构 使用远程API来管理和创建Docker容器 Docker 容器通过 Docker 镜像来创建
- Client - Docker 客户端通过命令行或者其他工具使用 Docker SDK与 Docker 的守护进程通信
- Host - 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器
- Docker Registry 中可以包含多个仓库(Repository) 每个仓库可以包含多个标签(Tag)每个标签对应一个镜像
工作原理
-
Docker Client 通过Socket 访问 Docker Server
-
Docker Server 接收到Docker Client的指令 执行
Docker安装
安装前面主要是配置了其依赖包和设置默认仓库等
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
sudo yum install -y yum-utils
sudo yum-config-manager \
--add-repo \
https://docker.mirrors.ustc.edu.cn
# https://registry.docker-cn.com
# http://hub-mirror.c.163.com
# https://download.docker.com/linux/centos/docker-ce.repo # 默认镜像拉取地址 # 可以设为国内镜像
sudo yum install docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
卸载
sudo yum remove docker-ce docker-ce-cli containerd.io
# 镜像、容器、自定义配置文件等并不会随着Docker的卸载自动删除,需要执行一下命令手动删除:
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
原理
核心实现技术 都是Linux内核技术
- 命名空间 namespace
- 控制组 cgroup
- 联合文件系统 UnionFS chroot
Docker是利用Namespace做资源隔离
用Cgroup做资源限制
利用Union FS做容器文件系统
的轻量级虚拟化技术
Docker容器的本质还是一个直接运行在宿主机上面的特殊进程 其文件系统是隔离后的 操作系统内核共享宿主机OS
命名空间 - Namespace
Linux 为我们提供的内核级别环境隔离的方法 用于分离进程树、网络接口、挂载点以及进程间通信等资源
使其中进程实现类似隔离的作用
Linux 的命名空间机制提供了七种不同的命名空间
这七个资源隔离选项分别对应七种系统调用 传入上表中的参数 调用clone函数来完成 我们能在创建新的进程时设置新进程应该在哪些资源上
与宿主机器进行隔离
docker run or start时都会在createSpec方法中创建一个用于进程隔离的Spec 在setNamespaces方法中不仅会设置进程相关的命名空间 还会设置与用户、网络、IPC 以及 UTS 相关的命名空间 所有命名空间相关的设置 Spec 最后都会作为 Create函数的入参在创建新的容器时进行设置
控制组 - Cgroup
通过 Linux 的命名空间为新创建的进程隔离了文件系统、网络并与宿主机器之间的进程相互隔离 但是 Docker 容器中的进程仍然能够访问或者修改宿主机的其他目录(命名空间并不能够为我们提供物理资源上的隔离
比如CPU、内存、IO)
=> Control Groups 能够隔离宿主机器上的物理资源
每一个CGroup是一组被相同的标准和参数限制的进程
(所有的资源控制都是以 CGroup 作为单位实现的,每一个进程都可以随时加入一个 CGroup 也可以随时退出一个 CGroup)
在早期版本中 可通过 libcgroup tools
来管理 cgroup 在 RedHat7 后 已经改为通过 systemctl
来管理
systemd
在 Linux 中的功能就是管理系统的资源 为了管理的方便衍生出了一个叫 Unit
的概念 可以表示抽象的服务、网络的资源、设备、挂载的文件系统等 Linux 将 Unit
的类型主要分为 12 种 Cgroup
中主要使用的是 slice, scope and service 三种类型
Linux实现CGroup(一切皆文件)
关于 docker 具体的限制可以在 sys/fs/cgroup/cpu/docekr/ 等文件夹来查看
启动Docker容器时 Docker会为这个容器创建一个与容器标识符相同的CGroup(每个子系统下都会创建 cpu memory等子目录)
想要控制 Docker 某个容器的资源使用率就可以在 docker 这个父控制组下面找到对应的子控制组并且改变它们对应文件的内容 也可以在启动Docker容器时指定参数去修改文件中的内容
每一个 CGroup 下面都有一个 tasks 文件 其中存储着属于当前控制组的所有进程的 pid 资源限制针对组中所有进程
容器停止后 该文件夹也会移除
示例
$ systemd-cgls # 查看CGroup的信息
# 创建一个叫 toptest 的服务 在名为 test 的 slice 中运行
$ systemd-run --unit=toptest --slice=test top -b
Running as unit toptest.service.
$ systemctl status toptest # 查看其状态
$ systemctl set-property toptest.service CPUShares=600 MemoryLimit=500M # 对toptest服务进行资源限制
$ cat /proc/对应的pid/cgroup # 一切皆文件 本质就是写了该文件
# 这时在 /sys/fs/cgroup/memory/test.slice 和 /sys/fs/cgroup/cpu/test.slice 目录下 多出了一个叫 toptest.service 的目录 在其目录下 cat toptest.service/cpu.shares 可以发现里面的 CPU 被限制了 600.
# Docker 和我们上面做的操作基本一致 具体需要限制哪些资源就是在 `docker run` 里指定
# 示例
docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash
Docker文件系统
应该说Docker容器的文件系统是由rootfs(挂载)和union(分层、联合挂载)发展而来的
rootfs
开始说了Namespace隔离了容器间和容器间和宿主机间的文件系统 是通过Mount Namespace
Mount Namespace
除了在修改时需要进程对文件系统挂载点的认证 还需要显式声明需要挂载的目录 Linux中有一个叫 chroot
的命令 可以改变进程的根目录到指定的位置 而 Mount Namespace
正是基于 chroot 的基础上发展出来的
容器的独立文件系统 就叫做容器镜像 更专业的名字叫 rootfs
包含了一个操作系统所需要的文件、配置和目录 但不包含系统内核 ** 在 Linux 中 文件和内核是分开存放的 操作系统只有在开启启动时才会加载指定的内核 这也就意味着所有的容器都会共享宿主机上操作系统的内核**
- 有了rootfs 打包封装了依赖和应用本身 解决了环境配置问题
- 有了rootfs 解决了可重用性问题 (通过引入分层概念 每次针对rootfs修改 只保存增量的内容)
UnionFS
层级的想法来自Linux的UnionFS
=> UnionFS是一种分层、轻量级、高性能的文件系统 支持对文件系统的修改作为一次提交来一层层地叠加 同时可以将不同目录挂载到同一个虚拟文件系统下
(最主要的功能) - 即主要用于把多个文件系统联合到同一个挂载点的文件系统服务
不同的环境有不同的UnionFS 如 AUFS、Overlay2(centos7)
AUFS
Advanced UnionFS 即UnionFS的升级版 它能够将不同文件夹中的层联合(Union)到了同一个文件夹中 这些文件夹在 AUFS 中称作分支 整个联合的过程被称为联合挂载
- 所有镜像层和容器层的内容都存储在 /var/lib/docker/aufs/diff/ 目录中
- 每一个镜像层或者容器层都是 /var/lib/docker/ 目录下的一个子文件夹
- /var/lib/docker/aufs/layers/ 中存储着镜像层的元数据 每一个文件都保存着镜像层的元数据
- 最后的 /var/lib/docker/aufs/mnt/ 包含镜像或者容器层的挂载点 最终会被 Docker 通过联合的方式进行组装
Overlay2
centos7的docker默认存储引擎
结构
Docker文件位置
主要
-
container 容器
-
image 镜像 存放元数据
-
如果实现了多种UnionFS 则image文件夹下会有对应的多个文件夹
-
imagedb用于存储image的每一层的引用
-
- layerdb用于存储最底层的层id 层之间的关联是通过 chainID 的方式保存的
- overlay2 存放每个镜像下包含的lowerdir
真实的 rootfs 位置
则总的过程是
- 在
image/overlay2/imagedb/content/sha256/
根据 image id 查看该 image 具有所有的层ID - 然后根据最底层ID和上一层ID通过 sha256 计算得到更上一层的ID 依次类推 关联所有的层 最后通过每一层的
cache-id
将元数据和真实的 rootfs 层数据对应起来了
镜像原理
联合文件系统是Docker镜像的基础
Docker中的每一个镜像都是由一系列只读
的层组成的 Dockerfile 中的每一个命令都会在已有的只读层上创建一个新的层
即Docker run创建容器时 就会在镜像的最上层添加一个可写层
也就是容器层 所有对于运行时容器的修改都是对容器层的修改 可以用docker history查看镜像的组成层
一个镜像可以创建多个容器
Docker示意图
面试问题
-
容器是如何进行隔离的?
在创建新进程时,通过 Namespace 技术,如 PID namespaces 等,实现隔离性。让运行后的容器仅能看到本身的内容。
比如,在容器运行时,会默认加上 PID, UTS, network, user, mount, IPC, cgroup 等 Namespace.
-
容器是如何进行资源限制的?
通过 Linux Cgroup 技术,可为每个进程设定限制的 CPU,Memory 等资源,进而设置进程访问资源的上限。
-
简述下 docker 的文件系统?
docker 的文件系统称为 rootfs,它的实现的想法来自与 Linux unionFS 。将不同的目录,挂载到一起,形成一个独立的视图。并且 docker 在此基础上引入了层的概念,解决了可重用性的问题。
在具体实现上,rootfs 的存储区分根据 linux 内核和 docker 本身的版本,分为
overlay2
,overlay
,aufs
,devicemapper
等。rootfs(镜像)其实就是多个层的叠加,当多层存在相同的文件时,上层的文件会将下层的文件覆盖掉。 -
容器的启动过程?
- 指定 Linux Namespace 配置
- 设置指定的 Cgroups 参数
- 切换进程的根目录
-
容器内运行多个应用的问题?
首先更正一个概念,我们都说容器是一个单进程的应用,其实这里的单进程不是指在容器中只允许着一个进程,而是指只有一个进程时可控的。在容器内当然可以使用 ping,ssh 等进程,但这些进程时不受 docker 控制的。
容器内的主进程,也就是 pid =1 的进程,一般是通过 DockerFile 中 ENTRYPOINT 或者 CMD 指定的。如果在一个容器内如果存在着多个服务(进程),就可能出现主进程正常运行,但是子进程退出挂掉的问题,而对于 docker 来说,仅仅控制主进程,无法对这种意外的情况作出处理,也就会出现,容器明明正常运行,但是服务已经挂掉的情况,这时编排系统就变得非常困难。而且多个服务,在也不容易进行排障和管理。
所以如果真的想要在容器内运行多个服务,一般会通过带有
systemd
或者supervisord
这类工具进行管理,或者通过--init
方法。其实这些方法的本质就是让多个服务的进程拥有同一个父进程。但考虑到容器本身的设计 就是希望容器和服务能够同生命周期 所以这样做 有点背道而驰的意味
Docker命令
Docker本身
# 启动docker:
systemctl start docker
# 停止docker:
systemctl stop docker
# 重启docker:
systemctl restart docker
# 查看docker状态:
systemctl status docker
# 开机启动:
systemctl enable docker
systemctl unenable docker
# 查看docker概要信息
docker info
# 查看docker帮助文档
docker --help
总结
帮助命令
docker version # docker版本信息
docker info # docker 相关信息
docker help # docker 帮助
docker `command` --help # 具体命令的帮助
镜像命令(重要)
-
查看镜像
docker images
Usage: docker images [OPTIONS] [REPOSITORY[:TAG]] List images Options: -a, --all Show all images (default hides intermediate images) -q, --quiet Only show image IDs [root@wanglingdu ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest d1165f221234 5 months ago 13.3kB # 仓库源 标签 镜像id 创建时间 大小
-
搜索镜像
docker search
Usage: docker search [OPTIONS] TERM
Search the Docker Hub for images
Options:
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print search using a Go template
--limit int Max number of search results (default 25)
--no-trunc Don't truncate output
[root@wanglingdu ~]# docker search mysql -f stars=5000
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 11213 [OK]
-
拉取镜像
docker pull
Usage: docker pull [OPTIONS] NAME[:TAG|@DIGEST] Pull an image or a repository from a registry Options: -a, --all-tags Download all tagged images in the repository [root@wanglingdu ~]# docker pull mysql Using default tag: latest latest: Pulling from library/mysql # 拉取命令不指定tag 默认最新版 33847f680f63: Pull complete # 分层 docker image的核心 联合文件系统 5cb67864e624: Pull complete 1a2b594783f5: Pull complete b30e406dd925: Pull complete 48901e306e4c: Pull complete 603d2b7147fd: Pull complete 802aa684c1c4: Pull complete 715d3c143a06: Pull complete 6978e1b7a511: Pull complete f0d78b0ac1be: Pull complete 35a94d251ed1: Pull complete 36f75719b1a9: Pull complete Digest: sha256:8b928a5117cf5c2238c7a09cd28c2e801ac98f91c3f8203a8938ae51f14700fd # 签名 Status: Downloaded newer image for mysql:latest docker.io/library/mysql:latest # 真实地址 docker pull mysql = docker.io/library/mysql:latest
-
删除镜像
docker rmi
Usage: docker rmi [OPTIONS] IMAGE [IMAGE...] # IMAGE 可以是镜像名:tag 或者直接镜像id Remove one or more images Options: -f, --force Force removal of the image # 强制删除 --no-prune Do not delete untagged parents # 不删除未标签的父元素 # 删除全部 docker rmi -f $(docker images -aq)
容器命令
前提是有镜像 此处以centos镜像为例
-
创建容器 会自动启动容器并进入(without -d)
docker run
(非常重要)Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] Run a command in a new container # -i 选项指示 docker 要在容器上打开一个标准的输入接口 -t 指示 docker 要创建一个伪tty终端 连接容器的标准输入接口 之后用户就可以通过终端进行输入 由于默认COMMAND为/bin/bash因此用户的输入是基于 bash shell 执行的 --name=“cname" Set Container name -i, --interactive Keep STDIN open even if not attached -t, --tty Allocate a pseudo-TTY # 指定docker容器向宿主机开放映射的端口 -p, --publish list Publish a container's port(s) to the host # -p 主机端口:容器端口 -P, --publish-all Publish all exposed ports to random ports -d, --detach Run container in background and print container ID -e, --env list Set environment variables -h, --hostname string Container host name # 示例 常用 docker run -dit -p 8080:8080 --name="centos1" centos /bin/bash
-
查看容器 docker ps
docker ps # 查看所有运行中的容器 docker ps -a # 查看所有的容器
-
启动容器(停止的) docker start
Usage: docker start [OPTIONS] CONTAINER [CONTAINER...] Start one or more stopped containers Options: -a, --attach Attach STDOUT/STDERR and forward signals --detach-keys string Override the key sequence for detaching a container -i, --interactive Attach container's STDIN # docker restart # 重启一个正在运行的容器
-
停止容器(运行中的) docker stop
Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...] Stop one or more running containers Options: -t, --time int Seconds to wait for stop before killing it (default 10) # 也可以docker kill 强制结束
-
进入容器(运行中的) docker exec
Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...] Run a command in a running container Options: -d, --detach Detached mode: run command in the background -i, --interactive Keep STDIN open even if not attached -t, --tty Allocate a pseudo-TTY docker exec -it id /bin/bash # docker attach id # 跟exec的区别是不会启动新的终端 而是用容器当前在用的终端 不会启动新的进程
-
退出容器(不一定停止) exit
exit # 直接退出容器 此时若没有指定后台运行 那么容器会自动停止 # 也可以crtl + p + q 退出 不会停止容器
-
删除容器 (停止的)docker rm
Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...] Remove one or more containers Options: -f, --force Force the removal of a running container (uses SIGKILL) -v, --volumes Remove anonymous volumes associated with the container
常用其他命令
-
容器日志 docker logs
Usage: docker logs [OPTIONS] CONTAINER Fetch the logs of a container Options: --details Show extra details provided to logs -f, --follow Follow log output --since string Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes) -n, --tail string Number of lines to show from the end of the logs (default "all") -t, --timestamps Show timestamps --until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)
-
查看容器内进程信息 docker top
Usage: docker top CONTAINER [ps OPTIONS] Display the running processes of a container
-
查看容器的元数据信息
docker inspect
Usage: docker inspect [OPTIONS] NAME|ID [NAME|ID...] Return low-level information on Docker objects Options: -f, --format string Format the output using the given Go template -s, --size Display total file sizes if the type is container --type string Return JSON for specified type
-
容器和宿主机互相拷贝数据
docker cp
Usage: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|- docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH Copy files/folders between a container and the local filesystem Use '-' as the source to read a tar archive from stdin and extract it to a directory destination in a container. Use '-' as the destination to stream a tar archive of a container source to stdout. Options: -a, --archive Archive mode (copy all uid/gid information) -L, --follow-link Always follow symbol link in SRC_PATH
-
容器挂载目录到宿主机上
(相当于会同步)在run的时候 -v 去指定 -
查看容器状态命令(cpu、内存等使用情况)
docker stats
端口映射及数据卷挂载
单独提出来说一说 我个人感觉比较重要
端口映射
新建一个容器时 指定宿主机和容器的端口映射 即通过宿主机的端口访问容器的指定端口 之前实现了外网的访问(服务器防火墙开启端口以及服务器安全组设置)
docker run -p 宿主机端口 : 容器端口 示例 3344 : 80 即如果容器部署应用在80端口 那么服务器外网ip:3344 就能访问该应用
数据卷挂载
在容器内部批量处理文件之类的比较麻烦 要是能够像端口映射一样 在外部处理 更好处理 所以引入挂载 两个路径之间同步
部署应用测试
部署Nginx
docker pull nginx
docker run -dit --name nginx01 -p 3344:80 nginx
# 测试
curl localhost:3344
# 通过3344端口可访问了
部署Tomcat
步骤本质没什么区别
docker pull tomcat:9.0
docker run -dit --name tomcat01 -p 3355:80 tomcat
# 测试
# 通过3355端口可访问Tomcat默认页
这里需要注意一个点时 拉取的镜像默认的webapps目录下没有项目 是因为最小化拉取的镜像 将webapps.dist文件夹下的拷贝过来即可
部署ES + Kibana
ElasticSearch
使用的端口比较多、也比较耗内存 数据一般需要挂载到安全目录 --net somework 网络配置
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.14.0
# 测试
curl localhost:9200
# 因为占用内存 可以在run的时候 指定-e选项配置一些环境 比如这 -e ES_JAVA__OPTS="-Xms64m -Xmx512m"
Kibana用于连接ES 要学习Docker网络原理
部署Portainer
一个Docker图像化界面管理工具 提供一个后台面板操作
docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
一般不使用
Docker镜像
镜像
镜像是一种轻量级、可执行的独立软件包
(独立的文件系统) 用来打包软件运行环境和软件 它包含运行某个软件所需的所有内容 包括代码、运行时库、环境变量和配置文件
应用打包为镜像 就可以直接运行 一般从远程库、其他人拷贝、通过DockerFile制作
镜像加载原理
原理部分已经说了镜像实际上是独一个独立的文件系统(rootfs) 由一层一层的文件系统联合挂载而来(是UnionFS)
- Docker镜像的最底层是bootfs 与典型的Linux系统相同 包含boot加载器和内核
- Linux刚启动时会加载bootfs boot加载器加载内核完毕后 内存使用权由bootfs转到内核 同时卸载bootfs
- bootfs之上即rootfs 原理部分已说 chroot或者说mount namespace 到了指定目录
提交镜像
前面已经说了run时新增了个容器层 所有修改都是针对容器层 那么如何提交作为一个新的镜像?
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
# 若指定的不是REPOSITORY而直接是目标镜像名 则提交到本地
Create a new image from a container's changes
Options:
-a, --author string Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")
-c, --change list Apply Dockerfile instruction to the created image
-m, --message string Commit message
-p, --pause Pause container during commit (default true)
容器数据卷
Motivation
容器中的数据在容器删除后也会丢失 -> 持久化数据到本地
防止删除容器数据丢失 或者删库跑路!
实现 : Docker容器中的数据 与本地进行同步
-> 数据卷技术 将容器内的目录挂载到宿主机的指定路径
总结:容器的持久化和同步操作 而且容器间可以数据共享(同一个
使用数据卷
docker run -v 主机目录: 容器内目录 # 可以挂载多个目录
测试mysql
docker run -d -p 3307:3306 -v /home/wld/myspace/mysql/conf:/etc/mysql/conf.d -v /home/wld/myspace/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
# 然后就可以通过指定的3307端口从外网连接数据库
# 两边文件会同步
# 删除容器 本地目录也不会丢失
连接上后创建一个testDocker目录
服务器直接有了这个目录
容器中也有了这个目录
具名和匿名挂载
# 匿名挂载 -v 容器内路径
# 具名挂载是指 -v volume_name:docker_path 最好使用具名挂载
# 指定路径挂载 -v /host_path: docker_path
通过docker volume 查看数据卷 圈起来的是匿名挂载的
docker volume inspect volume_name 指定查看对应名字数据卷的详细信息(包括实际挂载目录 没有指定时默认是/var/lib/docker/volumes/ 下
-v /宿主机路径:容器路径:ro / rw 设定只读或读写权限
若只读只能通过宿主机操作
通过DockerFile挂载
构建DockerFile的时候 用VOLUME命令 指定几个目录名 会自动匿名挂载到/var/lib/docker/volumes/ 下
相当于不用手动地去挂载 让构建的镜像自定义了几个需要挂载的目录 VOLUME [“/volume01”, “/volume02”]
数据卷容器
一个容器挂载到宿主机指定位置 跟另一个容器挂载到该容器的指定位置没什么本质差别
只是使用–volumes-from 指令去实现而已 即A 挂载数据卷到宿主机某个位置 B容器使用该命令 docker run -dit --volumes-from A 则一同挂载了(只挂载数据卷) A就称为数据卷容器 专门用于指定挂载目录的
就算容器A删掉了 数据应依旧存在 本质应该是用了这个命令那么就是挂载到A挂载的宿主机本地目录 本地没删 那么就有
数据卷容器的生命周期一直到没有容器使用它
DockerFile
DockerFile 是用于构建镜像的命令脚本文件
构建镜像步骤
- 编写dockerfile
- 指令大写
- 从上到下执行 一条指令一层
- docker build
- docker run
- docker push
DockerFile指令
CMD和ENTRYPOINT的区别在于CMD只有最后一个会生效
可被替代 ENTRYPOINT可追加
实战部署项目
FROM centos
RUN yum -y install vim
ADD apache-tomcat-9.0.50.tar.gz /usr/local
ADD jdk-8u301-linux-x64.tar.gz /usr/local
ENV JAVA_HOME /usr/local/jdk1.8.0_301
ENV CLASS_PATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.50
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin:$CATALINA_HOME/lib
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.50/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.50/bin/logs/catalina.out
通过Dockerfile build 容器
创建容器 映射9090端口 挂载目录
docker run -dit -p 9090:8080 -v /home/wld/build/test:/usr/local/apache-tomcat-9.0.50/webapps/test -v /home/wld/build/testlogs:/usr/local/apache-tomcat-9.0.50/logs customcat
可以通过外网访问9090端口 默认的ROOT项目了
然后在宿主机
修改test项目 将之改变为一个web项目 (添加/WEB-INF/web.xml index.jsp) 即可通过项目名访问
发布到DockerHub
- DockerHub注册
- 命令行登录
- docker push (push之前要将镜像打标签)
Docker网络
Docker如何处理容器和宿主机间、容器间网络访问的?
原理 Docker0
服务器的网卡
只要安装了Docker 服务器就会多出docker0网卡 地址是172.17.0.1 使用桥接模式 使用evth-pair技术(一对虚拟网络设备接口 充当桥梁 连接各种虚拟网络设备)
以后每开一个容器 就会多出一对网卡(一个在服务器 一个在容器中) 会分配该网段的一个地址给该容器
原理图
可以通过--link
(run的时候) 直接通过容器名 ping通另一容器(可以这样做 但不推荐)
tomcat03可以ping通tomcat02 反之不行 本质实现是在tomcat03容器中的/etc/hosts文件中直接将其写死
自定义网络
docker网络模式
- bridge 桥接 (默认 )
- none 不配置网络
- host 和宿主机共享网络
- container 容器内网络互通(使用少)
容器互联
Usage: docker network COMMAND # 容器网络相关命令 可以自定义网络等
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
# 示例
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 cusnetwork
# 创建容器时指定网络
docker run -d -P --name tomcat-net-01 cusnetwork tomcat
这时候网络内的多个容器可以互相ping通 且可以使用容器名直接ping 不用使用–link
好处 不同的集群使用不同的网络 保证集群安全和健康
网络连通
同一网段的容器已经可以互联了 如果想容器连通另一网络的容器 使用connect命令
Usage: docker network connect [OPTIONS] NETWORK CONTAINER
Connect a container to a network
Options:
--alias strings Add network-scoped alias for the container
--driver-opt strings driver options for the network
--ip string IPv4 address (e.g., 172.30.100.104)
--ip6 string IPv6 address (e.g., 2001:db8::33)
--link list Add link to another container
--link-local-ip strings Add a link-local address for the container
本质上是将该容器直接同时放到另一网络即可
(一个容器两个ip
SpringBoot项目部署Docker
-
项目
-
打包应用
-
编写Dockerfile
示例
FROM java:8 COPY *.jar /app.jar CMD ["--server.port=8080"] EXPOSE 8080 ENTRYPOINT ["java", "-jar", "/app.jar"]
-
把jar和dockerfile上传到服务器 构建镜像
-
发布运行