Docker基础教程
Docker与微服务
基础篇
Docker简介
Docker是基于Go语言实现的云开源项目。Docker之所以发展如此迅速,也是因为它对此给出了一个标准化的解决方案:系统平滑移植,容器虚拟化技术。
Docker的主要目标是“Build, Ship and Run Any App, Anywhere”,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次镜像,处处运行”。
VM vs Docker
- 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
- 容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
- 每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。
开发/运维(DevOps)
一次构建、随处运行
- 更快速的应用交付和部署
传统的应用开发完成后,需要提供一堆安装程序和配置说明文档,安装部署后需根据配置文档进行繁杂的配置才能正常运行。Docker化之后只需要交付少量容器镜像文件,在正式生产环境加载镜像并运行即可,应用安装配置在镜像里已经内置好,大大节省部署配置和测试验证时间。 - 更便捷的升级和扩缩容
随着微服务架构和Docker的发展,大量的应用会通过微服务方式架构,应用的开发构建将变成搭乐高积木一样,每个Docker容器将变成一块“积木”,应用的升级将变得非常容易。当现有的容器不足以支撑业务处理时,可通过镜像运行新的容器进行快速扩容,使应用系统的扩容从原先的天级变成分钟级甚至秒级。 - 更简单的系统运维
应用容器化运行后,生产环境运行的应用可与开发、测试环境的应用高度一致,容器会将应用程序相关的环境和状态完全封装起来,不会因为底层基础架构和操作系统的不一致性给应用带来影响,产生新的BUG。当出现程序异常时,也可以通过测试环境的相同容器进行快速定位和修复。 - 更高效的计算资源利用
Docker是内核级虚拟化,其不像传统的虚拟化技术一样需要额外的Hypervisor支持,所以在一台物理机上可以运行很多个容器实例,可大大提升物理服务器的CPU和内存的利用率。
前提条件
目前,CentOS 仅发行版本中的内核支持 Docker。Docker 运行在CentOS 7 (64-bit)上,要求系统为64位、Linux系统内核版本为 3.8以上。
查看内核:
- uname -r
- cat /etc/redhat-release
Docker的基本组成
- 镜像 image
Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。 - 容器 container
Docker 利用容器(Container)独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。(可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。) - 仓库 repository
仓库(Repository)是集中存放镜像文件的场所。(Docker公司提供的官方registry被称为Docker Hub:https://hub.docker.com/)
Docker安装
https://docs.docker.com/engine/install/centos/
- 确定你是CentOS7及以上版本
- 卸载旧版本
- yum安装gcc相关:yum -y install gcc gcc-c++
- 安装需要的软件包:yum install -y yum-utils
- 设置stable镜像仓库
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
- 更新yum软件包索引:yum makecache fast
- 安装DOCKER CE:yum -y install docker-ce docker-ce-cli containerd.io
- 启动docker:systemctl start docker
- 测试:docker version;docker run hello-world
- 卸载:systemctl stop docker ;yum remove docker-ce docker-ce-cli containerd.io;rm -rf /var/lib/docker;rm -rf /var/lib/containerd
阿里云镜像加速
https://promotion.aliyun.com/ntms/act/kubernetes.html
容器镜像服务-镜像加速器
Docker为什么比VM虚拟机快
- docker有着比虚拟机更少的抽象层
由于docker不需要Hypervisor(虚拟机)实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。 - docker利用的是宿主机的内核,而不需要加载操作系统OS内核
当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。进而避免引寻、加载操作系统内核返回等比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载OS,返回新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个docker容器只需要几秒钟。
常用命令
帮助类命令
- 启动:systemctl start docker
- 停止:systemctl stop docker
- 重启:systemctl restart docker
- 查看状态:systemctl status docker
- 开机启动:systemctl enable docker
- 查看概要信息:docker info
- 帮助文档:docker --help
- 具体命令帮助:docker 具体命令 --help
镜像命令
docker images
- 本地镜像列表(repository:镜像的仓库源,tag:镜像标签版本号,image id:镜像ID,created:镜像创建时间,size:镜像大小)
- 参数:-a:列出本地所有的镜像(含历史映像层);-q:只显示镜像ID
docker search [options] xxx
- 搜索镜像
- 参数:--limit:只列出N个镜像,默认25个
docker pull xx[:tag]
- 下载镜像,无tag则代表最新镜像,同:docker pull xx:latest
docker system df
- 查看镜像/容器/数据卷所占的空间
docker rmi xx镜像ID
- 删除单个镜像:docker rmi -f 镜像ID
- 删除多个:docker rmi -f 镜像1名:TAG 镜像2名:TAG
- 删除全部:docker rmi -f $(docker images -qa)
容器命令
拉取ubuntu镜像:docker pull ubuntu
- 新建+启动容器:docker run [options] image [command] [arg...]
options
- --name="容器新名字"
- -d 后台运行容器并返回容器ID,即启动守护式容器
- -i 以交互模式运行容器,通常与 -t 同时使用
- -t 为容器重新分配一个伪终端,-it 即启动交互式容器
- -P 随机映射端口
- -p 指定端口映射
- docker ps [options]
- 列出当前所有正在运行的容器
参数:
- -a:列出当前所有正在运行的容器+历史上运行过的
- -l:显示最近创建的容器
- -n:显示最近n个创建的容器
- -q:静默模式,只显示容器编号
- 退出容器
- exit:容器停止
- ctrl+p+q:容器不停止
- 启动已停止运行的容器
- docker start 容器ID或容器名
- 重启容器
- docker restart 容器ID或容器名
- 停止容器
- docker stop 容器ID或容器名
- 强制停止容器
- docker kill 容器ID或容器名
- 删除已停止的容器
- docker rm 容器ID
批量删除
- docker rm -f $(docker ps -a -q)
- docker ps -a -q | xargs docker rm
- 查看容器日志
- docker logs 容器ID
- 查看容器内运行的进程
- docker top 容器ID
- 查看容器内部细节
- docker inspect 容器ID
- 进入正在运行的容器并以命令行交互
- [推荐] docker exec -it 容器ID bashShell
重新进入docker attach 容器ID
attach 直接进入容器启动命令的终端,不会启动新的进程
用exit退出,会导致容器的停止。exec 是在容器中打开新的终端,并且可以启动新的进程
用exit退出,不会导致容器的停止。
- 从容器内拷贝文件到主机上
- docker cp 容器ID:容器内路径 目的主机路径
- 导入和导出容器
- docker export 容器ID > 文件名.tar(export 导出容器的内容留作为一个tar归档文件[对应import命令];import 从tar包中的内容创建一个新的文件系统再导入为镜像[对应export])
- cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
- commit
- docker commit 提交容器副本使之成为 一个新的镜像
- docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
示例ubuntu安装vim:
- docker pull ubuntu
- docker run -it ubuntu /bin/bash
- apt-get update #更新包管理器
- apt-get install vim
- exit
- docker commit -m="add vim" -a="sensen" 345c8360dc47 sensen/myubuntu:1.1
- docker images
Docker容器后台运行,就必须有一个前台进程。
容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出的。
虚悬镜像
仓库名、标签都是none的镜像(dangling image)
Docker镜像
一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。只有通过这个镜像文件才能生成Docker容器实例。
镜像分层
UnionFS 联合文件系统
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
centos镜像只有200M左右
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
镜像分层优点
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;
同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
Docker镜像层都是只读的,容器层是可写的。
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。
本地镜像发布到阿里云
https://promotion.aliyun.com/ntms/act/kubernetes.html
- 进入:容器镜像服务
- 选择个人实例
- 命名空间-设置命名空间
- 镜像仓库-创建镜像仓库
- 推送到阿里云:
docker login --username=xx registry.cn-hangzhou.aliyuncs.com
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/r1989/myubuntu:[镜像版本号]
docker push registry.cn-hangzhou.aliyuncs.com/r1989/myubuntu:[镜像版本号]
本地镜像发布到私有库
Docker Registry是官方提供的工具,可以用于构建私有镜像仓库。
- 下载镜像docker registry:docker pull registry
运行私有库Registry,相当于本地有个私有Docker hub
- docker run -d -p 5000:5000 -v /sensen/myregistry/:/tmp/registry --privileged=true registry(默认情况,仓库被创建在容器的/var/lib/registry目录下)
- 案例演示创建一个新镜像,ubuntu安装ifconfig命令
curl验证私服库上有什么镜像
- curl -XGET http://192.168.xx.xx:5000/v2/_catalog
将新镜像myubuntu:1.2修改符合私服规范的Tag
- 按照公式: docker tag 镜像:Tag Host:Port/Repository:Tag
- docker tag myubuntu:1.2 192.168.xx.xx:5000/myubuntu:1.2
修改配置文件使之支持http
- vim /etc/docker/daemon.json
- {
"registry-mirrors": ["https://xxx.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.xx.xx:5000"]
} - docker默认不允许http方式推送镜像,通过配置选项来取消这个限制。 修改完后如果不生效,建议重启docker
push推送到私服库
- docker push 192.168.xx.xx:5000/myubuntu:1.2
- curl验证私服库上有什么镜像2
- pull到本地并运行
Docker容器数据卷
Docker挂载主机目录访问如果出现:cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个--privileged=true参数即可
使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限。
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性:
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。
类似redis中的rdb和aof文件,将docker容器内的数据保存进宿主机的磁盘中。
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
特点:
- 数据卷可在容器之间共享或重用数据
- 卷中的更改可以直接实时生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
宿主vs容器之间映射添加容器卷
docker run -it --name=myu1 --privileged=true -v /tmp/myubuntu:/tmp/dockerData ubuntu /bin/bash
查看是否挂载成功:docker inspect
测试主机或docker修改数据、docker停止后主机修改数据,重启docker数据同步。
读写规则映射添加说明
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名(默认为rw)
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名(容器实例内部被限制,只能读取不能写)
卷的继承和共享
- docker run -it --privileged=true -v /mydocker/u:/tmp --name u1 ubuntu
- docker run -it --privileged=true --volumes-from u1 --name u2 ubuntu
Docker常规安装简介
步骤:
- 搜索镜像
- 拉取镜像
- 查看镜像
- 启动镜像
- 停止容器
- 移除容器
示例:
文档地址:https://hub-stage.docker.com/_/mysql
- docker search mysql
- docker pull mysql:8.0
- 新建mysql容器实例:docker run -d -p 3307:3306 --privileged=true -v /docker/mysql8/log:/var/log/mysql -v /docker/mysql8/data:/var/lib/mysql -v /docker/mysql8/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql8 mysql:8.0
- 新建my.cnf:vim /docker/mysql8/conf/my.cnf
- 重新启动mysql容器实例再重新进入并查看字符编码:docker restart mysql8;docker exec -it mysql8 bash;mysql -uroot -p;show variables like "character%";
- 建库表 create database db01;use db01;create table user(id int, name varchar(20));insert into user values(1, '森森');select * from user;
- 删除容器重新创建测试数据库仍存在
高级篇
Docker复杂安装
mysql主从复制
新建主服务器实例3307
- docker run -d -p 3307:3306 --privileged=true -v /docker/mysql-master/log:/var/log/mysql -v /docker/mysql-master/data:/var/lib/mysql -v /docker/mysql-master/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql-master mysql:8.0
新增my.cnf
vim /docker/mysql-master/conf/my.cnf
[mysqld] ## 设置server_id,同一局域网中需要唯一 server_id=101 ## 指定不需要同步的数据库名称 binlog-ignore-db=mysql ## 开启二进制日志功能 log-bin=mall-mysql-bin ## 设置二进制日志使用内存大小(事务) binlog_cache_size=1M ## 设置使用的二进制日志格式(mixed,statement,row) binlog_format=mixed ## 二进制日志过期清理时间。默认值为0,表示不自动清理。 expire_logs_days=7 ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。 ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致 slave_skip_errors=1062
- 修改后重启:docker restart mysql-master
- 进入master容器:docker exec -it mysql-master /bin/bash
master容器实例内创建数据同步用户
- CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
- GRANT REPLICATION SLAVE, REPLICATION CLIENT ON . TO 'slave'@'%';
- 新建从服务器容器实例3308
- docker run -d -p 3308:3306 --privileged=true -v /docker/mysql-slave/log:/var/log/mysql -v /docker/mysql-slave/data:/var/lib/mysql -v /docker/mysql-slave/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql-slave mysql:8.0
进入/docker/mysql-slave/conf目录下新建my.cnf
[mysqld] ## 设置server_id,同一局域网中需要唯一 server_id=102 ## 指定不需要同步的数据库名称 binlog-ignore-db=mysql ## 开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用 log-bin=mall-mysql-slave1-bin ## 设置二进制日志使用内存大小(事务) binlog_cache_size=1M ## 设置使用的二进制日志格式(mixed,statement,row) binlog_format=mixed ## 二进制日志过期清理时间。默认值为0,表示不自动清理。 expire_logs_days=7 ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。 ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致 slave_skip_errors=1062 ## relay_log配置中继日志 relay_log=mall-mysql-relay-bin ## log_slave_updates表示slave将复制事件写进自己的二进制日志 log_slave_updates=1 ## slave设置为只读(具有super权限的用户除外) read_only=1
- 修改完配置后重启slave实例:docker restart mysql-slave
- 在主数据库中查看主从同步状态:show master status;
- 进入mysql-slave容器
在从数据库中配置主从复制
- change master to master_host='127.0.0.1', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000003', master_log_pos=712, master_connect_retry=30;
- master_host:主数据库的IP地址;
master_port:主数据库的运行端口;
master_user:在主数据库创建的用于同步数据的用户账号;
master_password:在主数据库创建的用于同步数据的用户密码;
master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;
master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
master_connect_retry:连接失败重试的时间间隔,单位为秒。
- 查看从服务器状态:show slave status \G;
- 在从数据库中开启主从同步:start slave;
- 查看从数据库状态发现已经同步:show slave status \G;
- 主从复制测试
DockerFile解析
DockerFile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
https://docs.docker.com/engine/reference/builder/
构建步骤
- 编写dockerfile文件
- docker build 命令构建镜像
- docker run 依镜像运行容器实例
dockerfile内容基础知识
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按照从上到下,顺序执行
表示注释
- 每条指令都会创建一个新的镜像层并对镜像进行提交
执行dockerfile流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器作出修改
- 执行类似docker commit的操作提交一个新的镜像层
- docker再基于刚提交的镜像运行一个新容器
- 执行dockerfile中的下一条指令直到所有指令都执行完成
参考:https://github.com/docker-library/tomcat
Dockerfile常用保留字指令
- FROM:基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from
- MAINTAINER:镜像维护者的姓名和邮箱地址
RUN
- 容器构建时需要运行的命令
- shell格式:RUN yum -y install vim
- exec格式:RUN ['可执行文件', '参数1', '参数2']
- RUN是在 docker build时运行
- EXPOSE:当前容器对外暴露出的端口
- WORKDIR:指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
- USER:指定该镜像以什么样的用户去执行,如果都不指定,默认是root
- ENV:用来在构建镜像过程中设置环境变量
- ADD:将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
COPY:类似ADD,拷贝文件和目录到镜像中。将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。
- COPY src dest
- COPY ["src", "dest"]
- <src源路径>:源文件或者源目录
- <dest目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
- VOLUME:容器数据卷,用于数据保存和持久化工作
CMD:指定容器启动后的要干的事情
- Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
- CMD是在docker run 时运行;RUN指令是在docker build时运行
ENTRYPOINT:也是用来指定一个容器启动时要运行的命令
- 类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序
- 格式:ENTRYPOINT ["executeable", 'param1', 'param2', '...']
- 在执行docker run的时候可以指定 ENTRYPOINT 运行所需的参数。
- 如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
自定义Docker示例
编写Dokcerfile文件
FROM centos MAINTAINER zzyy<zzyybs@126.com> ENV MYPATH /usr/local WORKDIR $MYPATH #安装vim编辑器 RUN yum -y install vim #安装ifconfig命令查看网络IP RUN yum -y install net-tools #安装java8及lib库 RUN yum -y install glibc.i686 RUN mkdir /usr/local/java #ADD 是相对路径jar,把jdk-8u171-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置 ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/ #配置java环境变量 ENV JAVA_HOME /usr/local/java/jdk1.8.0_171 ENV JRE_HOME $JAVA_HOME/jre ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH ENV PATH $JAVA_HOME/bin:$PATH EXPOSE 80 CMD echo $MYPATH CMD echo "success--------------ok" CMD /bin/bash
- 构建:docker build -t 新镜像名字:TAG .
虚悬镜像
仓库名、标签都是none的镜像,俗称:dangling image
如Dockerfile:
FROM ubuntu
CMD echo "action is success"
docker build .
查看:docker image ls -f dangling=true
删除:docker image prune
Docker微服务
Docker网络
docker不启动时,默认的网络情况:ens33、lo、virbr0
在CentOS7的安装过程中如果有选择相关虚拟化的的服务安装系统后,启动网卡时会发现有一个以网桥连接的私网地址的virbr0网卡(virbr0网卡:它还有一个固定的默认IP地址192.168.122.1),是做虚拟机网桥的使用的,其作用是为连接其上的虚机网卡提供 NAT访问外网的功能。
docker启动后会增加名为docker0的虚拟网桥
查看docker网络模式:docker network ls
基本命令
docker network --help
查看网络:docker network ls
查看网络源数据:docker network inspect xx网络名字
删除网络:docker network rm xx网络名字
创建网络:docker network create xx网络名字
用途
- 容器间的互联和通信,以及端口映射
- 容器IP变动时可以通过服务名直接网络通信而不受影响
网络模式
- bridge模式:使用--network bridge指定,默认使用docker0
- host模式:使用--network host指定
- none模式:使用--network none指定
- container模式:使用--network container:NAME或者容器ID指定
容器实例内默认网络IP生产规则
启动两个容器实例
- docker run -it --name u1 ubuntu bash
- docker run -it --name u2 ubuntu bash
- docker inspect 容器ID或名字查看IP地址
- 关闭u2,新建u3,查看IP变化:docker inspect u3 | tail -n 20
结论:docker容器内的IP是有可能会发生改变的
bridge
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
1 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
2 docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址
3 网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配。
3.1 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
3.2 每个容器实例内部也有一块网卡,每个接口叫eth0;
3.3 docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。
通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。
host
直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8 (不可指定端口)
none
在none模式下,并不为Docker容器进行任何网络配置。 也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo。需要我们自己为Docker容器添加网卡、配置IP等。
docker run -d -p 8084:8080 --network none --name tomcat84 billygoo/tomcat8-jdk8
container
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
Alpine Linux 是一款独立的、非商业的通用 Linux 发行版,专为追求安全性、简单性和资源效率的用户而设计。 可能很多人没听说过这个 Linux 发行版本,但是经常用 Docker 的朋友可能都用过,因为他小,简单,安全而著称,所以作为基础镜像是非常好的一个选择,可谓是麻雀虽小但五脏俱全,镜像非常小巧,不到 6M的大小,所以特别适合容器打包。
- docker run -it --name alpine1 alpine /bin/sh
- docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh
- ip addr 验证共用搭桥
- 关闭alpine1,则alpine2网络消失
自定义网络
自定义桥接网络,自定义网络默认使用的是桥接网络bridge。
- docker network create ss_network
- docker network ls
新建容器加入上一步新建的自定义网络
- docker run -d -p 8081:8080 --network zzyy_network --name tomcat81 billygoo/tomcat8-jdk8
- docker run -d -p 8082:8080 --network zzyy_network --name tomcat82 billygoo/tomcat8-jdk8
互相ping测试
- docker exec -it tomcat81 bash
- ping tomcat82
结论:
自定义网络本身就维护好了主机名和IP的关系(IP和域名都能通);
Docker平台架构图解
从其架构和运行流程来看,Docker 是一个 C/S 模式的架构,后端是一个松耦合架构,众多模块各司其职。
Docker 运行的基本流程为:
- 用户是使用 Docker Client 与 Docker Daemon 建立通信,并发送请求给后者。
- Docker Daemon 作为 Docker 架构中的主体部分,首先提供 Docker Server 的功能使其可以接受 Docker Client 的请求。
- Docker Engine 执行 Docker 内部的一系列工作,每一项工作都是以一个 Job 的形式的存在。
- Job 的运行过程中,当需要容器镜像时,则从 Docker Registry 中下载镜像,并通过镜像管理驱动 Graph driver将下载镜像以Graph的形式存储。
- 当需要为 Docker 创建网络环境时,通过网络管理驱动 Network driver 创建并配置 Docker 容器网络环境。
- 当需要限制 Docker 容器运行资源或执行用户指令等操作时,则通过 Execdriver 来完成。
- Libcontainer是一项独立的容器管理包,Network driver以及Exec driver都是通过Libcontainer来实现具体对容器进行的操作。
Docker-compose容器编排
https://docs.docker.com/compose/compose-file/compose-file-v3/
Docker-Compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。
Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器。
安装流程
- curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
- chmod +x /usr/local/bin/docker-compose
- docker-compose --version
Compose核心概念
文件:docker-compose.yml
两要素:
- 服务service:一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器。
- 工程project:由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
使用步骤:
- 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
- 使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。
- 最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线
compose常用命令
docker-compose -h # 查看帮助
docker-compose up # 启动所有docker-compose服务
docker-compose up -d # 启动所有docker-compose服务并后台运行
docker-compose down # 停止并删除容器、网络、卷、镜像。
docker-compose exec yml里面的服务id # 进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps # 展示当前docker-compose编排过的运行的所有容器
docker-compose top # 展示当前docker-compose编排过的容器进程
docker-compose logs yml里面的服务id # 查看容器输出日志
docker-compose config # 检查配置
docker-compose config -q # 检查配置,有问题才有输出
docker-compose restart # 重启服务
docker-compose start # 启动服务
docker-compose stop # 停止服务
docker-compose.yml示例:
version: "3"
services:
microService:
image: zzyy_docker:1.6
container_name: ms01
ports:
- "6001:6001"
volumes:
- /app/microService:/data
networks:
- atguigu_net
depends_on:
- redis
- mysql
redis:
image: redis:6.0.8
ports:
- "6379:6379"
volumes:
- /app/redis/redis.conf:/etc/redis/redis.conf
- /app/redis/data:/data
networks:
- atguigu_net
command: redis-server /etc/redis/redis.conf
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: '123456'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_DATABASE: 'db2021'
MYSQL_USER: 'zzyy'
MYSQL_PASSWORD: 'zzyy123'
ports:
- "3306:3306"
volumes:
- /app/mysql/db:/var/lib/mysql
- /app/mysql/conf/my.cnf:/etc/my.cnf
- /app/mysql/init:/docker-entrypoint-initdb.d
networks:
- atguigu_net
command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
networks:
atguigu_net:
轻量级可视化工具Portainer
Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。
https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux
安装:docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
容器监控之CAdvisor+InfluxDB+Granfana
通过docker stats命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据,一般小公司够用了。但是,docker stats统计结果只能是当前宿主机的全部容器,数据资料是实时的,没有地方存储、没有健康指标过线预警等功能。
CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表
version: '3.1'
volumes:
grafana_data: {}
services:
influxdb:
image: tutum/influxdb:0.9
restart: always
environment:
- PRE_CREATE_DB=cadvisor
ports:
- "8083:8083"
- "8086:8086"
volumes:
- ./data/influxdb:/data
cadvisor:
image: google/cadvisor
links:
- influxdb:influxsrv
command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
restart: always
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
grafana:
user: "104"
image: grafana/grafana
user: "104"
restart: always
links:
- influxdb:influxsrv
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
environment:
- HTTP_USER=admin
- HTTP_PASS=admin
- INFLUXDB_HOST=influxsrv
- INFLUXDB_PORT=8086
- INFLUXDB_NAME=cadvisor
- INFLUXDB_USER=root
- INFLUXDB_PASS=root