Docker
Docker 基础概念
Docker 存在的意义,是提供了一个标准化的操作系统运行环境,每个环境独立运行一个应用,他们之间相互隔离。
像 VMWare 这样的软件是提供了一个物理机器级别的虚拟化,通过这个软件,可以在一台电脑上虚拟出来多个物理硬件系统,在每一个虚拟机器中可以安装不同的操作系统。而 Docker 则是更轻量,是提供了一个操作系统级别的虚拟化。通过 Docker,可以在一台电脑上虚拟化出来多个操作系统内核,这样实现了不同的应用可以有一个独立的操作系统的运行环境,它们之间互不干扰。
Docker 的架构和 Maven 是一样的,都有官方的镜像文件地址,可以用阿里云镜像解决。(不会就去百度)
Docker 命令
Docker 服务命令
使用 systemctl 来控制 Docker 进程,这个 systemctl 是 systemd 的一个命令,它是 Linux 下的一款系统和服务管理器。
systemctl CONTROL docker
这里面可以填写的 CONTROL 命令是:start stop restart status enable(开机启动) disable(关闭开机启动)
Docker 镜像操作
docker image ls
docker images
查看镜像
docker images -q
只获取所有镜像的 ID,可以用于批量删除镜像
docker search NAME
在 Docker 仓库里面去搜索叫做 NAME 的镜像。
docker pull NAME:TAG
来直接获取叫做 NAME 版本为 TAG 的镜像,如果省略 TAG 的话,默认就是最新的版本了。
docker image rm NAME
删除叫做 NAME 的镜像。
Docker 容器操作
查看容器
docker ps -a
查看全部的容器(包括关闭了的)
docker ps -aq
返回所有容器的 ID
创建删除容器
docker run XXX
通过镜像创建一个容器并运行
参数:
- -i 保持容器运行
- -t 分配一个容器的输入终端,退出之后,会关闭容器。
- -d 在后台创建中断,通过
docker exec CONTAINER_NAME
进入容器中断操作,退出后不关闭容器 –name=XXX
给容器一个名字- 最后一个参数,就是创建容器的镜像名字
因此 -it 创建出来的是交互式容器,-id 创建出来的是守护式容器。
eg: docker run -id --name=Nginx002 nginx:latest
创建根据 nginx latest 镜像创建的名字为 Nginx002 的容器,并以守护模式运行,然后执行 docker exec -it Nginx002 /bin/bash
来进入守护模式运行的容器。
注意上面的 /bin/bash 是进入容器中,需要执行的初始化命令,/bin/bash 就是用来启动容器的 bash 终端的,用来操作这个容器。
docker rm NAME
根据容器名字或者 ID:Name
启动与关闭
docker start NAME
根据容器名字启动已经停止的容器。
docker stop NAME
…
详细信息
docker inspect NAME
查看 NAME 容器的具体信息。
数据卷设置
通过和宿主机的目录建立同步映射,来解决容器和宿主机以及容器和容器之间的通讯。
挂载目录
一个容器要挂载到宿主机的目录的时候,只能在创建的时候设置,不然就要去更改容器的配置文件才可以,所以在创建容器的时候,一定要思考好,挂载到那里才合适。
挂载目录的命令是在 run 的时候,加上 -v 宿主机目录:容器目录
即可。不存在会自动创建,存在就是原文件夹。
docker run -id --name=CONTAINER_NAME -v /Xorex/Nginx001:/Xorex/Nginx001 IMAGE_NAME
数据卷容器
就是建立一个容器,这个容器作为一个数据卷容器。其他的容器挂载到它身上,就等价于挂载到了数据卷容器挂载的目录里面了。优势是可以通过数据卷容器,很方便的管理数据挂载。
首先建立数据卷容器: docker run -id --name=CONTAINER_NAME -v /VOLUMNAME IMAGE_NAME
和上面直接挂载不同的是,没有了宿主目录,只写一个容器的目录(宿主目录交给 Docker 分配)
然后就是建立普通容器,挂载到数据卷容器上面,使用 --volumes-from VOLUM_DATA_CONTAINER_NAME
来挂载到对应名字的数据卷容器上面:
docker run -id --name=CONTAINER_NAME --volumes-from VOLUM_DATA_CONTAINER_NAME IMAGE_NAME
从而将创建的新容器,挂载到数据卷容器上面,也就等价于挂载到了它对应的宿主机目录上面。
基本部署
一些原则:
需要操作、改动、查看的东西,一定要设置挂载目录,并将对应的数据放入这些目录中,在宿主机操作,容器只负责运行。
尽量不要改动容器内的环境,不要下载安装其他东西。
MySQL 部署
1 | docker search mysql |
- -p prot 端口映射
- -v $PWD 是获取当前目录,用来拼接绝对路径。conf.d 数据库配置文件。 logs 数据库日志存放。 data 数据库表数据保存。
- -e env 环境变量,设置数据库的初始登录密码。
- \ 表示的是命令还没有输入完毕,符号后面不能有空格,直接回车继续输入指令。
部署完毕之后,就可以在 MySQL 容器里面直接操作,或者外部访问宿主机的 3306 端口对 MySQL 进行链接访问了。
如果是使用的阿里云服务器,记得在 网络安全-安全组 里面,将 3306 端口打开。
如果要修改配置文件,在容器中将 /etc/my.cnf
文件复制到挂载目录 /etc/mysql/conf.d
下面,然后在容器外就可以轻松修改了,改完记得重启容器应用。
Tomcat 部署
1 | docker run -id \ |
然后就可以访问服务器的 8080 端口,来对 Tomcat 进行访问了,好耶!
Nginx 部署
1 | docker run -id \ |
镜像
Dokcer 镜像原理
对于 Docker 的镜像来说,根据各种依赖,将镜像进行了大量的分层,来实现镜像文件的复用。
比如对于 Tomcat 镜像来说,它能跑起来是借助于 Tomcat 镜像(Tomcat 代码),以及父依赖 JDK 环境,以及 JVM 运行起来的父依赖 Rootfs 镜像(Linux 发行版系统)。
这些多层的镜像被外界看作为一个整体,叫做一个 Tomcat 镜像,所以看起来会很大。但是当你下载其他的镜像的时候,可能会有一些父依赖镜像已经下载过了,所以就可以节省空间,实现镜像的复用。
所以:
Docker 镜像的本质是一个分层的文件系统。
Docker 的 Centos 镜像只有 200mb,Centos 操作系统 ISO 镜像要几个 G 的原因是:Docker 借助分层文件系统,复用了宿主机的 Bootfs,因此 Docker 的 Centos 镜像只需要下载 Rootfs 和其他即可,相对来说节省很多空间。
Docker 的 Tomcat 镜像有 500mb 为什么比 Tomcat 安装包 70mb 大这么多:因为 Docker 的 Tomcat 还包括运行所依赖的父镜像 JDK 和 Rootfs 系统,所以加起来很大。而 Tomcat 安装包只包括自己本身,因此比较小。
(但其实 Docker 的分层要比上面描述的更加细致,可以通过 docker inspect IMAGE_NAME
看一看具体的分层情况)
制作镜像
容器转镜像
就是将已经有的运行容器转化为镜像,这个镜像可以以 tar 的形式来传播。
docker commit CONTAINER_NAME IMAGE_NAME:TAG
将已经生成的容器 CONTAINER_NAME 转化为,版本为 TAG 的镜像 IMAGE_NAME 。
docker save -o TAR_NAME IMAGE_NAME:TAG
将版本为 TAG 的镜像 IMAGE_NAME 压缩为 tar 文件:TAR_NAME 。
docker load -i TA2AME
将压缩文件 TAR_NAME 加载镜像。
需要注意的是,容器转镜像的时候,是不包括链接到宿主机的目录的!!!
DockerFile 生成镜像
DockerFile 是一个文本文件,包含了大量的 Docker 指令来生成一个镜像。
DockerFile
DockerFile 关键字表
关键字 | 作用 | 备注 |
---|---|---|
FROM | 指定父镜像 | 指定 dockerfile 基于那个 image 构建 |
MAINTAINER | 作者信息 | 用来标明这个 dockerfile 谁写的 |
LABEL | 标签 | 用来标明 dockerfile 的标签 可以使用 Label 代替 Maintainer 最终都是在docker image基本信息中可以查看 |
RUN | 执行命令 | 执行一段命令 默认是 /bin/sh 格式: RUN command 或者 RUN [“command” , “param1”,”param2”] |
CMD | 容器启动命令 | 提供启动容器时候的默认命令 和 ENTRYPOINT 配合使用.格式 CMD command param1 param2 或者 CMD [“command” , “param1”,”param2”] |
ENTRYPOINT | 入口 | 一般在制作一些执行就关闭的容器中会使用 |
COPY | 复制文件 | build 的时候复制文件到 image 中 |
ADD | 添加文件 | build 的时候添加文件到 image 中 不仅仅局限于当前 build 上下文 可以来源于远程服务 |
ENV | 环境变量 | 指定 build 时候的环境变量 可以在启动的容器的时候 通过 -e 覆盖 格式 ENV name=value |
ARG | 构建参数 | 构建参数 只在构建的时候使用的参数 如果有 ENV 那么 ENV 的相同名字的值始终覆盖arg的参数 |
VOLUME | 定义外部可以挂载的数据卷 | 指定 build 的 image 那些目录可以启动的时候挂载到文件系统中 启动容器的时候使用 -v 绑定 格式 VOLUME [“目录”] |
EXPOSE | 暴露端口 | 定义容器运行的时候监听的端口 启动容器的使用 -p 来绑定暴露端口 格式: EXPOSE 8080 或者 EXPOSE 8080/udp |
WORKDIR | 工作目录 | 指定容器内部的工作目录 如果没有创建则自动创建 如果指定/ 使用的是绝对地址 如果不是/开头那么是在上一条 workdir 的路径的相对路径 |
USER | 指定执行用户 | 指定 build 或者启动的时候 用户 在 RUN CMD ENTRYPONT 执行的时候的用户 |
HEALTHCHECK | 健康检查 | 指定监测当前容器的健康监测的命令 基本上没用 因为很多时候 应用本身有健康监测机制 |
ONBUILD | 触发器 | 当存在 ONBUILD 关键字的镜像作为基础镜像的时候 当执行 FROM 完成之后 会执行 ONBUILD的命令 但是不影响当前镜像 用处也不怎么大 |
STOPSIGNAL | 发送信号量到宿主机 | 该 STOPSIGNAL 指令设置将发送到容器的系统调用信号以退出。 |
SHELL | 指定执行脚本的shell | 指定 RUN CMD ENTRYPOINT 执行命令的时候 使用的 shell |
编写 DockerFile
将一个 SpringBoot 项目构建出一个镜像。
1 | FROM java:8 |
然后就是根据这个 DockerFile 自己生成一个 Docker 镜像。
docker build -f ./XXX.dockerfile -t IMAGE_NAME:TAG .
-f 表示指定文件位置, -t 表示后面执行生成的镜像的名字和版本号。(别忘了最后的 .
)
比如我写的:docker build -f /dockerfile -t app:1.0 .
然后就会生成一个叫做 app:1.0 的镜像啦!只需要将这个镜像跑在容器中,就成功部署了项目啦。(有可能会要求你去建立一个 .dockerignore 的文件,就建立一个就好了,内容写 *
)
还有,记得要 ADD 的东西,放到和 dockerfile 一个文件夹里面,不然可能会添加失败。
自定义 CentOS7
1 | FROM centos:7 |
Docker-Compose
这个用于编写 Docker 执行的文件的,适用于大规模复杂部署。因为自己的 ECS 怎么都连不上 Github 所以就不学了吧。
把讲义里面的东西还是贴一下把,万一以后用得到。
一、安装 Docker Compose
1 | Compose目前已经完全支持Linux、Mac OS和Windows,在我们安装Compose之前,需要先安装Docker。下面我 们以编译好的二进制包方式安装在Linux系统中。 |
二、卸载 Docker Compose
1 | 二进制包方式安装的,删除二进制文件即可 |
三、 使用 Docker Compose 编排 Nginx+SpringBoot 项目
- 创建 docker-compose 目录
1 | mkdir ~/docker-compose |
- 编写 docker-compose.yml 文件
1 | version: '3' |
- 创建./nginx/conf.d目录
1 | mkdir -p ./nginx/conf.d |
- 在./nginx/conf.d目录下 编写itheima.conf文件
1 | server { |
- 在~/docker-compose 目录下 使用docker-compose 启动容器
1 | docker-compose up |
- 测试访问
1 | http://192.168.149.135/hello |
Docker 底层原理
Docker 是使用 Go 语言,利用了 Linux 内核 的一个软件。也就是虚拟化本身,是 Linux 内核自己支持的,Docker 只是利用了这个特性。
总的来说,Docker 的镜像就是一个分层管理的文件系统和一些命令组成。Docker 开启的容器,对于宿主机来说就是一个进程,但是被命名空间和其他进程隔离。通过 Linux 内核 CGroups
系统管理容器能分配到的物理机器资源大小。
Namespace 命名空间
一个容器对应一系列的命名空间,通过不同容器的命名空间的隔离,实现了资源调用的隔离。主要有以下的命名空间的使用:
PID
Process ID 隔离进程
NET
NetWroking 隔离网络
IPC
InterPress Communication 共享内存
MNT
Mount 文件挂载
UTS
Unix TimeSharing System 隔离内核
等等等等。
Control Groups
Control Groups 又被称作为 CGroups,是 Linux 提供的针对进程的资源利用(CPU 内存 等)的统计和限制的一种技术。
CGroups 技术加入 Linux 内核让 Docker 容器分配到不同的资源成为可能,下面是 CGroups 起到的一些作用:
资源限制(Resource limiting):可以将组设置为不超过设定的内存限制。比如:内存子系统可以为进程组设定一个内存使用上限,一旦进程组使用的内存达到限额再申请内存,就会出发Out of Memory警告。
优先级(Prioritization):通过优先级让一些组优先得到更多的CPU等资源。
资源审计(Accounting):用来统计系统实际上把多少资源用到适合的目的上,可以使用cpuacct子系统记录某个进程组使用的CPU时间。
隔离(isolation):为组隔离命名空间,这样一个组不会看到另一个组的进程、网络连接和文件系统。
控制(Control):挂起、恢复和重启动等操作。
Union File System
联合文件系统,是 Linux 的一种轻量级高性能分层文件系统。
联合文件系统是实现Docker镜像的技术基础。Docker镜像可以通过分层来进行继承。例如,用户基于基础镜像(用来生成其他镜像的基础,往往没有父镜像)来制作各种不同的应用镜像。这些镜像共享同一个基础镜像层,提高了存储效率。此外,当用户改变了一个Docker镜像(比如升级程序到新的版本),则会创建一个新的层(layer)。因此,用户不用替换整个原镜像或者重新建立,只需要添加新层即可。用户分发镜像的时候,也只需要分发被改动的新层内容(增量部分)。这让Docker的镜像管理变得十分轻量级和快速。
镜像分层,相同内容复用!