Docker基本概念
Docker的基本组成
1.镜像(image)
Docker 镜像(Image)就是一个只读的模板,当于是一个root文件系统,也相当于容器的“源代码。
镜像是轻量级可执行的独立软件包,它包含运行某个软件所需要的所有内容,包括代码,运行时库,环境变量和配置文件
2.容器(container)
1 从面向对象角度
容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。
镜像是静态的定义,容器是镜像运行时的实体。
容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。
每个容器都是相互隔离的、保证安全的平台
2 从镜像容器角度
可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
3.仓库(Repository)
是集中存放镜像文件的场所。
仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
最大的公开仓库是 Docker Hub(https://hub.docker.com/),
存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云 、网易云等
·
Docker工作原理
Docker 是一个 C/S 模式的架构,后端是一个松耦合架构,众多模块各司其职。Docker守护进程运行在主机上,然后通过Socket连接从客户端访问,守护进程从客户端接收命令并管理运行在主机上的容器
docker运行的基本流程为
1.用户使用docker client 与docker deamon建立通信,并发送请求给后者
2.docker daemon作为docker架构中的主体部分,首先提供docker server的功能使其可以接收docker client的请求
3.docker engine指定docker内部的一系列工作,每一项工作都是以一个job的形式的存在
4.job的运行过程中,当需要容器镜像时,则从docker registry中下载镜像,并通过镜像管理驱动graph driver将下载镜像以Graph的形式存储。
5.当需要为docker创建网络环境时,通过网络管理驱动NetWork driver创建并配置docker容器网络环境
6.当需要限制docker容器运行资源或执行用户指令等操作时,则通过exec driver来完成
7.libcontainer时一项独立的容器管理包,network driver以及exec driver都是通过libcontainer来实现具体对容器进行的操作
镜像加载原理
UnionFS联合文件系统
UFS是一种分层、轻量级并且高性能的文件系统,支持对文件系统的修改作为一次提交来一层层叠加,同时可以将不同目录挂载到同一个虚拟文件系统下,docker镜像可以通过分层来进行继承,基于基础镜像可以制作各种具体的应用镜像
加载原理
bootfs:主要包含bootloader和kernel,bootloader主要是引导加载kernel,linux刚启动会加载bootfs文件系统,在docker最底层是bootfs,这一层与我们典型的linux系统是一样的,包含boot加载器和内核,当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。(意思是当linux启动后,容器的启动都是直接建立在linux机的bootfs之上,所有容器的启动不再单独再次运行bootfs,而是用linux机的?)
rootfs:在bootfs之上。是各种不同操作系统的标准发行版本,如centos
对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接使用Host和kernel,自己只需要提供rootfs就可以了(不同的linux发行版,bootfs基本是一样的,rootfs才有差别)
镜像就相当于能调用底层linux的东西都去使用它,比如bootfs,只加载必要的rootfs和其他,因此精简
分层原理
分层结构最大的好处就是资源共享,
所有docker镜像都起源于一个基础镜像层,当进行修改或增加新内容时,就会在当前镜像层上创建新的镜像层
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合
docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
docker镜像都是只读的,当容器启动的时候,一个新的可写层被加载到镜像的顶部,即基础下载的镜像是不会改变的,当我们运行的容器都是可以修改的容器层+不可修改的镜像层,对外发布可以将这两个打包成一个整体的镜像
为什么docker比虚拟机更快
(1)docker有着比虚拟机更少的抽象层
由于docker不需要Hypervisor(虚拟机)实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。
(2)docker利用的是宿主机的内核,而不需要加载操作系统OS内核
当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。进而避免引寻、加载操作系统内核返回等比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载OS,返回新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个docker容器只需要几秒钟。
安装部署
yum安装
1.卸载旧版本docker
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
3.yum 安装gcc相关
yum -y install gcc
yum -y install gcc-c++
4.安装需要的软件包
sudo yum install -y yum-utils
5.设置stable镜像仓库
#官网上的地址是国外的,非常慢,是个坑,一般需要换到国内的替代地址
#经常会报TCP链接重置或者连接超时的错误
#sudo yum-config-manager \
# --add-repo \
# https://download.docker.com/linux/centos/docker-ce.repo
#可以用国内阿里云的地址替代
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
6.更新yum软件包索引
yum makecache fast
7.安装docker ce
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
8.启动docker
systemcl start docker
#测试是否正常
docker version
9.卸载docker
systemctl stop docker
yum remove docker-ce docker-ce-cli contaninerd.io docker-compose-plugin
rm -rf /var/lib/docker
rm -rf /var/lib/containerd
Docker配置
配置阿里云镜像
首先注册阿里云账户,注册容器镜像服务,生成自己的阿里云镜像地址
sudo mkdir -p /etc/docker
# 将EOF前面的内容反写进入deamon.json
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://dwi14745.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
本地包部署
1.下载包
https://download.docker.com/linux/static/stable/x86_64/
# 1.下载包
https://download.docker.com/linux/static/stable/x86_64/
# 2.解压包
tar -zxvf docker-19.03.9.tgz
# 3.复制所有文件到/usr/bin
cp docker/* /usr/bin/
# 4.配置docker,service添加配置内容
vim /etc/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
[Install]
WantedBy=multi-user.target
# 5.给执行权限
chmod +x /etc/systemd/system/docker.service
# 6. 设置daemon-reload
systemctl daemon-reload
# 7.启动docker
systemctl start docker
修改docker默认存储路径
docker默认将/var/lib/docker作为存储路径,若要调整,如下
#1.创建daemon.json配置文件,默认没有这个文件,需要添加
vim /etc/docker/daemon.json
# 添加如下
{
"data-root": "/data"
}
# 保存后重启服务
systemctl restart docker
# 查看是否调整成功
docker info
Docker常用命令
帮助启动命令
#启动docker
systemctl start docker
#停止docker
systemctl stop docker
#重启docker
systemctl restart docker
#查看docker状态
systemctl status docker
#开机启动
systemctl enable docker
#查看docker版本,可验证是否安装docker成功
docker version
#系统信息
docker info
#所有命令,详细信息还可以查看官方文档
docker --help
#查看所有服务
docker service ls
镜像命令
#查看已经下载的镜像
docker images
#从官方库搜索镜像
docker search xxx
#下载镜像
docker pull xxx[:TAG]
#查看镜像/容器/数据卷所占用的空间
docker system df xxx
#删除某个镜像
docker rmi xxx
#删除全部
docker rmi -f $(docker iamges -qa)
#将镜像达成tar包
docker save [镜像id]>./xxx.tar
#加载本地镜像
docker load < xxx.tar
# 修改镜像
docker tag ubuntu:latest myubuntu:latest
容器命令
#查看dockers下容器所占用的内存与cpu情况
docker stats xxx
#查看容器日志
docker logs [容器名/容器id]
#设置容器自启动
docker update [容器id] --reastart=always
#将容器内的目录复制到当前路径, 录入nginx
docker container cp nginx:/etc/nginx
#交互形式进入容器内部,exec退出容器终端不会导致容器停止
# 通过attach也可以进入容器内部,但是退出会导致容器停止,不建议用
docker exec -it [容器id]
# 查看容器中文件结构的更改
docker diff [id]
# 查看端口映射
docker port [id]
#查看容器配置信息
docker inspect [容器id]
#查看所有节点,只显示id,hostname,addr,state
docker inspect $(docker node ls -q) --format='{{.ID}} {{.Description.Hostname}} {{.Status.Addr}} {{.Status.State}} '
#查看容器进程
docker top [id]
将镜像启动成容器
#一、新建容器:docker [container] create
#--name="name" 容器名字
#-d 后台运行方式
#-it 使用交互方式运行
#-p 指定容器的端口
#-p ip:主机端口:容器端口
#-p 主机端口:容器端口【常用】
#-p 容器端口
#-P 随机指定端口
#-e 传递环境变量
docker create -it ubuntu:latest//新建的容器处于停止状态,需要启动
#启动容器(根据容器ID启动)
docker start 容器id
#二、新建容器并启动
# docker [container] run
#-d:指后台运行
#-p:指定端口映射先写外部端口再写内部端口
#--name:指定容器运行起来后的名字
#-v:可以映射文件,用途很广,比如可以将当前目录映射到/usr/share/nginx/html
#-i:以交互模式运行容器,通常与 -t 同时使用
#-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用
#-e:设置环境变量
#当利用run创建启动容器时,docker在后台的标准操作
#1.检查本地是否存在指定的镜像,不存在就从共有仓库下
#2.利用镜像创建一个容器,并启动该容器
#3.分配一个文件系统给容器,并在只读的镜像层外挂载一层可读写层
#4.从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
#5.从网桥的地址池配置一个IP地址给容器
#6.执行用户指定的应用程序
#7.执行完毕后容器被自动终止
#对于创建的bash容器,当用户使用exit退出bash进程后,容器也会自动退出,这是因为当其中应用退出后,容器的使命完成,也就没有继续运行的必要了,下面会启动并进入容器
docker run -it ubuntu:18.04 /bin/bash //指定运行bash应用,不会运行其他无关进程
#'pwd'指当前目录, 将当前目录映射到指令目录,这样可以将一些静态文件放在外面,在外面修改文件(因为是映射 的)里面的文件就会跟着变化,这个映射还会用于其他一些数据的保存,比如mysql的data目录也可以映射到外面,防止数据丢失,最后需要接的参数是镜像的名字,如果有具体的版本最好不要省略,省略就是latest最新版,如果镜像一直在全新的构建的话,latest会不断更新,如果有一个正在使用的稳定版本,可以指定到这个版本吧
docker run -d -p 88:80 --name mynginx -v 'pwd' :/usr/share/nginx/html nginx:1.13
#当docker run 时无法正常执行容器而出错退出,可以查看退出的错误代码
# 125:docker deamon执行出错,例如指定了不支持的docker命令参数
# 126:指定命令无法执行,例如权限出错
# 127:容器内命令无法找到
#三、守护态运行,使用该后台运行就必须需要有一个前台进程,docker发现没有应用就会自动停止
docker run -d ubuntu /bin/sh
#以后台运行的方式启动,并且把容器外的3355端口和容器内的8080端口做映射
docker run -d -p 3355:8080 --name tomcat1 tomcat
#启动容器,并且通过-e设置单点分布,以及容器的最大占用内存,以es为例
docker run -d --name es1 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
停止容器
#一、暂停容器:docker pause
#处于paused状态的容器,可以用docker unpause回复到运行
docker pause test
#二、终止容器:docker stop
#该命令会首先想容器发送SIGTERM信号,默认等待10秒后,再发送SIGKILL信号来终止容器
#还可以通过docker kill 直接发送SIGKILL信号来强行终止容器
docker stop 容器id
#强制停止当前容器
docker kill 容器id
#直接停止容器并退出
exit
#容器不停止退出
Ctrl + P + Q
#三、重启容器:docker restart
#该命令会将一个运行的容器先终止再重新启动
docker restart b27a32
操作容器
#1.attach,进入容器正在执行的终端,不会启动新的进程
#多个窗口同时attach到一个容器时,所有窗口都会同步显示,当某个窗口因命令阻塞时,其他窗口也无法操作
# 退出容器后容器将停止,不建议使用该命令,多用exec
docker attach xxx
#2.exec,进入容器后开启一个新的终端,可以在里面操作
docker exec -it b27a32 /bin/bash
#3.本地路径的data复制到test容器的/tmp路径下
docker [container] cp data test:/tmp/
#查看统计信息,cpu状态
docker stats [id]
#查看日志
docker logs -f -t --tail [id]
删除容器
#docker [container] rm
#-f:是否强行终止并删除一个运行的容器
#-l:删除容器的连接,但保留容器
#-v:删除容器挂载的数据卷
#默认下docker rm只能删除已经处于终止或退出状态的容器,并不能删除运行中的容器
#如果要删除运行中的容器,可以添加-f参数,docker会先发送SIGKILL信号,终止其中应用,之后强行删除
docker rm b27a32
docker ps -a -q|xargs docker rm //通过管道符删除所有容器
#更新配置
#限制总配额为1秒,容器所占用时间为10%
docker update --cpu-quota 1000000 b27a32
docker update --cpu-period 100000 b27a32
将容器提交成为镜像
docker镜像都是只读的,当容器启动的时候,一个新的可写层被加载到镜像的顶部,即基础下载的镜像是不会改变的,当我们运行的容器都是可以修改的容器层+不可修改的镜像层,对外发布可以将这两个打包成一个整体的镜像
#提交容器成为一个新的副本
docker commit
#命令和git原理类似
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG]
导入和导出容器
导出后的tar文件可传输到其他机器上,然后再通过导入命令导入到系统中,实现容器的迁移
使用import将丢弃所有历史记录和元数据信息,但可以重新指定标签等元数据信息
镜像中的docker load也可以导入,存储的文件保存记录完整,体积更大
//1.导出容器,指导出一个已经创建的容器到一个文件,不管此时这个容器的状态
//将容器id ce5开头的导出到test1.tar
docker export -o test1.tar ce5
//将容器id e81开头的导出到test2.tar
docker export e81 >test2.tar
//将镜像打包
docker save xxx >./test.war
//2.导入容器
docker import test2.tar - test/ubuntu:1.0
集群相关
#生成集群绑定命令
#复制该命令在其他从服务器中执行即可添加集群,使用portainer的话可以在swarm下看到主机的ip,节点信息
docke swarm join-token worker
#强制脱离集群
docker swarm leabe --force
仓库命令
#1 登录私库
docker login registry.xxx.com:5000 -u demo -p xxx
# 2pull镜像
docker pull registry.xxx.com:5000/demo/xxx-ui:20220510
# 3给镜像重新打标签
docker tag registry.xxx.com:5000/demo/xxx-ui:20220510 192.168.35.43:5000/xxx-ui:20220510
# 4将镜像上传到本地仓库
docker push 192.168.35.43:5000/xxx-ui:20220510
镜像分层概念
什么是镜像
镜像是轻量级,可执行的独立软件包,包含运行某个软件所需要的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码,运行时需要的库,环境变量和配置文件等),这个打包好的环境就是镜像
分层的镜像
UnionFS(联合文件系统)
Union是一种分层,轻量级并且高性能的文件系统,支持对文件系统的修改作为一次提交来一层层叠加,同时可以将不同目录挂载到同一个虚拟文件系统下
Union是docker镜像的基础,镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来
docker镜像加载原理
为什么docker镜像采用分层结构
容器卷
docker 容器中产生的数据可以同步到本地,这就是卷技术,可视为目录的挂载,将容器的目录挂载到linux上
通过容器数据卷技术可以对容器进行持久化和同步的操作,容器间也是可以数据共享的
DockerFile
dockerFile简介
dockerfile是构建docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本
构建三部曲
1.编写Dockerfile文件
2.docker build命令构建镜像
3.docker run 依镜像运行容器实例
dockerfile构建过程解析
1.每条保留字指令要求大写,且后面跟随至少一个参数
2.指令从上到下依次执行
3. #表示注释
4. 每条执行都会创建一个新的镜像层并对镜像进行提交
dockerfile常用保留字指令
FROM
基础镜像,当前新镜像是基于哪镜像,制定一个已经存在的镜像作为模板,dockerfile第一条指令必须是FROM
MAINTAINER
镜像维护者的姓名和邮箱地址
RUN
容器构建时需要运行的命令,分为shell格式和exec模式
RUN在docker build时运行
# shell格式
# <命令行命令>等同于,在终端操作的shell命令
RUN <命令行命令>
# 示例,下方命令在build的时候就会执行
RUN yum -y install vim
# exec模式
RUN ["可执行文件","参数1","参数2"]
#示例,等价于RUN ./test.php dev offline
RUN ["./test.php","dev","offline"]
EXPOSE
当前容器对外暴露的端口
WORKDIR
指定在容器创建后,终端默认登录进来的工作目录,一个落脚点
USER
指定该镜像以什么用户去执行,如果都不指定,默认是root
ENV
用来在构建镜像过程中设置环境变量
#这个环境变量可以在后续的任何RUN指令中使用,如果在命令前指定了环境变量前缀一一样
#也可以在其他指令中直接使用这个环境变量
ENV MY_PATH /usr/mytest
#使用示例
WORKDIR $MY_PATH
ADD
将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包,和COPY类似,相当于COPY+解压
COPY
docker中也有cp命令 docker cp 容器ID:容器内路径 目的主机路径
,COPY的作用类似
COPY也类似ADD,用于拷贝文件和目录到镜像中
将从构建上下文目录中<源路径>的文件 / 目录复制到新的一层的镜像内的<目标路径>
VOLUME
容器数据卷,用于数据保存和持久化工作
CMD
指定容器启动后需要干的事情
CMD指定的格式和RUN相似,也是两种格式,shell和exec
CMD在docker run时运行,RUN在docker build时运行
Dockerfile可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换
EXPOSE 8080
#启动tomcat
CMD ["catalina.sh","run"]
#该命令会正常调用CMD的设置启动tomcat暴露8080
docker run -it -p 8080:8080 30ef
# 该命令相当于会在CMD后面再加一行 CMD ["/bin/bash","run"]
# 则只有最后一行CMD生效,所以容器运行,会进入/bin/bash路径,但是不会启动tomcat,8080无法访问
docker run -it -p 8080:8080 30ef /bin/bash
ENTRYPOINT
也用于指定一个容器启动时要运行的命令
类似CMD,但不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给ENTRYPOINT指令指定的程序
命令格式: ENTRYPOINT ["<executeable>","<param1>","<param2>"...]
ENTRYPOINT可以和CMD一起,一般是变参才会使用CMD,这里的CMD等于是在给ENTRYPOINT传参
当指定了ENTRYPOINT后,CMD的含义就发生了变化,不再直接运行其命令而是将CMD的内容作为参数传递给ENTRYPOINT指令,组合变成<ENTRYPOINT> "<CMD>"
#假设已经通过dockerfile构建了nginx:test镜像
FROM nginx
ENTRYPOINT ["nginx","-c"] #定参
CMD ["/etc/nginx/nginx.conf"] #变参
是否传参 | 按照dockerfile编写执行 | 传参运行 |
---|---|---|
Docker命令 | docker run nginx:test | docker run nginx:test -c /etc/nginx/new.conf |
衍生出的实际命令 | nginx -c /etc/nginx/nginx.conf | nginx -c /etc/nginx/new.conf |
案例
自定义mycentosjava8镜像
# 前置条件:本地已经下载了centos镜像
# 要求:镜像具备 vim+ifconfig+jdk8
# 要求:本地环境有jdk8包: jdk-8u171-linux-x64.tar.gz
# java8下载地址 :https://www.oracle.com/java/technologies/downloads/#java8
vim Dockerfile
--------------------------------------------------------------------------
FROM centos
MAINTAINER hhxx<hhxx@qq.com>
ENV MY_PATH /user/local
WORKDIR $MY_PATH
RUN yum -y intall vim
RUN yum -y install net-tools
RUN yum -y install glibc.i686
# ADD的jdk包要和Dockerfile在同一位置
ADD jdk-8u171-linux-x64.tar.gz /usr/local/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
EXPORSE 80
CMD echo $MYPATH
CMD echo "success ok"
CMD /bin/bash
------------------------------------------------------------------------------
# 构建,不要忘记最后的.
docker build -t centosjdk8:1.0 .
总结
dockerfile,docker镜像和docker容器分别代表软件的三个阶段
dockerfile
dockerfile是软件的原材料,面向开发
镜像反解析后对应的一个个文件就是dockerfile
dockerfile定义了进程需要的一切东西,dockerfile涉及的内容包括执行的代码或者是文件、环境变量、依赖包、运行时环境、动态链接库,操作系统的发行版本,服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)
docker镜像
docker镜像是软件的交付品,交付标准
docker容器
docker容器则是软件的运行状态,直接提供服务,涉及部署和运维
虚悬镜像
仓库名和标签名都是的镜像,不能用
#测试构建虚悬镜像
# 1. vim Dockerfile
form centos
CMD "success"
# 2.build构建,就会生成
docker build .
# 查看系统所有的虚悬镜像
docker image ls -f dangling=true
# 删除所有的虚悬镜像
docker image prune
Docker微服务实战
1.通过idea新建一个普通微服务模块
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/>
</parent>
<groupId>org.example</groupId>
<artifactId>docker_boot</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
<mysql.version>5.1.47</mysql.version>
<druid.version>1.1.16</druid.version>
<mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
yml
server:
port: 6001
启动类
package com.huaxin.docker;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DockerBootApplication {
public static void main(String[] args) {
SpringApplication.run(DockerBootApplication.class,args);
}
}
controller
package com.huaxin.docker.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
@RestController
public class OrderController {
@Value("${server.port}")
private String port;
@RequestMapping("/order/docker")
public String helloDocker(){
return "hello,docker"+"\t"+port+"\t"+ UUID.randomUUID().toString();
}
@RequestMapping(value = "/order/index",method = RequestMethod.GET)
public String index(){
return "服务端口号"+"\t" +port+"\t"+UUID.randomUUID().toString();
}
}
最后通过maven的package打出jar包
通过dockerfile发布微服务部署到docker容器
#1.在linux环境机器创建测试目录,例如/mydocker
#2.将jar包上传到该目录
#3.在该目录下 vim Dockerfile
-----------------------------------------------------------------------------
#基础镜像使用java
FROM java:8
#作者
MAINTAINER huaxin
#指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
#将jar包添加到容器内并改名
ADD docker_boot-1.0-SNAPSHOT.jar huaxin_docker.jar
#运行jar包
RUN bash -c 'touch /huaxin_docker.jar'
ENTRYPOINT ["java","-jar","/huaxin_docker.jar"]
#暴露端口
EXPOSE 6001
-----------------------------------------------------------------------------
#4. build出镜像
docker build -t huaxin_docker:1.1 .
#5. 启动镜像
docker run -d -p 6001:6001 3db
#6.测试
curl http://1.12.249.69:6001/order/index
Docker网络
是什么
docker 不启动时,linux的网络情况
通过ifconfig 或ipaddr可以查看网络
ens33
lo
virbr0
在centos7的安装过程中如果有选择相关虚拟化的服务安装系统后【例如linux图形化桌面,就要支持虚拟化服务】,启动网卡时会发现有一个以网桥连接的私网地址的virbr0网卡(virbr0网卡:它还有一个固定的默认IP地址192.168.122.1),是做虚拟机网桥使用的,作用是为连接其他虚拟网卡,提供NET访问外网的功能
linux安装,勾选安装系统时附带了libvirt服务才会生成这个东西,不需要可以yum remove libvirt-libs.x86_64
卸载
docker启动后的网络状态
启动docker后会产生一个名为docker0的虚拟网桥
docker服务默认会创建这个docker0网桥(其上有一个docker0内部接口),该桥接网络的名称为docker0,它在内核层联通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络,docker默认指定了Docker0接口的IP地址和子网掩码,让主机和容器之间可以通过网桥相互通信
docker默认下的网络
docker默认创建三大网络模式,主要用bridge,勉强用host,一般不用none
常用基本命令
#通过下命令可以查看docker默认网络[安装后没有修改时的状态]
#docker network [command]
#commands
# connect :连接
# create :创建
# disconnect :中断
# inspect :查看详细
# ls :查看
# prune :删除所有无效,不占用的网络
# rm :删除指定网络
docker network ls
NETWORK ID NAME DRIVER SCOPE
bd6d0f8add85 bridge bridge local
662a75feca6a host host local
72c38821ee62 none null local
能干啥
容器间的互联通信以及端口映射
容器IP变动时候可以通过服务名直接网络通信而不受到影响
docker网络管理和容器调用之间的规划
网络模式
网络模式详细分类
网络模式 | 简介 |
---|---|
bridge | 为每个容器分配,设置IP等,并将容器连接到一个docker0虚拟网桥,默认为该模式 使用 --network bridge指定,默认docker0 |
host | 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口 使用 --network host指定 |
none | 容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair和网络桥接,IP等 使用 --network none指定 |
container | 新创建的容器不会创建自己网卡和配置自己的IP,而是和一个指定的容器共享IP,端口范围等 使用 --network container:NAME或容器ID指定 |
自定义网络 | 自定义网络实现了通过容器名ping通,更适合容器集群之间的通信 |
容器示例内默认网络IP生产规则
docker容器内部的ip是可能发生改变的
例如启动了镜像 centos 生成容器centos01,和centos02
假设此时centos01网络为172.17.0.2,centos02网络为172.17.0.3
如果centos02停止,或删除,02的网络就停止了
此时再启动centos03,03的网络可能还为172.17.0.3
若centos01原来与centos02通信,02单机,03起来后,就变为和03通信了,即网络发生变化,导致通信错误
容器通信的重要前提:ip地址发生变化不能影响调用通信出问题,且希望调用的服务号处于同一网段
bridge
#查看bridge网络的详细信息,并通过grep获取名称项
docker network inspect bridge | grep name
bridge解析
1.Docker使用linux桥接,在宿主机虚拟一个docker容器网桥(docker0),docker启动一个容器时会根据docker网桥的网段分配给容器一个IP地址,成为Container-IP,同时Docker网桥是每个容器的默认网关,因为在一宿主机内的容器都接入同一个网桥,这样容器之前就能够通过容器的Container-IP直接通信
2.doker run的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0,在宿主机ip addr
就可以看到docker0和自己create的network eth0,eth1,eth2…代表网卡1,2,3… lo
达代表127.0.0.1,inet addr用来表示网卡的IP地址
3.网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对存在与匹配
整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair)
每个容器示例内部也有一块网卡,每个接口叫eth0
docker0上面的每个veth匹配某个容器实例内部的eth0,两两匹配,一一对应
综上所述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的
host
直接使用宿主机的IP地址与外界进行通信,不再需要额外进行NAT转换
容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace,容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口
该方式docker启动时指定–network=host或-net=host,此时-p
参数不会有任何作,端口号会以主机端口号为主,重复则递增
类似虚拟机的桥接模式
none
禁用了网络功能,只有lo标识(就是127.0.0.1表示本地回环)
在none模式下,不为docker容器进行任何网络配置,即这个docker容器没有网卡,IP,路由等信息,只有一个lo
需要我们自己为docker容器添加网卡,配置IP等
container
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享,新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP,端口范围等,同样,两个容器除了网络方面,其他的如文件系统,进程列表等还是隔离的
自定义网络模式
自定义网络存在的问题
默认网络模式可以通过ip互ping,但是无法通过容器名ping,并且当某一容器宕机后,后增加的容器可能会顶替之前宕机的容器的ip,导致容器间通讯混乱,自定义网络解决了这个问题,通过容器名可以Ping实现了容器通信的唯一性,并且可以自由的根据业务设置网络通信模式
docker多个容器之间的集群规划一定要用服务名通信而不是ip
自定义网络案例
自定义网络默认使用桥接网络bridge
#新建自定义网络
docker network create huaxin_net
#新建容器加入自定义网络
docker run -d -p 8081:8080 --network huaxin_net --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --network huaxin_net --name tomcat82 billygoo/tomcat8-jdk8
Docker 平台架构图
整体说明
Docker是一个C/S模式的架构,后端是一个松耦合架构,众多模块各司其职
Docker的运行流程为:
1.用户使用docker client和docker daemon建立通信,并发送请求给后者
2.docker daemon作为docker 架构中的主体部分,首先提供docker server 的功能使其可以接受docker client的请求
3.docker engine执行docker 内部的一系列工作,每一项工作都是以一个job的形式存在
4.job的运行过程中,当需要容器镜像时,则从Docker registry中下载镜像,并通过镜像管理驱动Graph driver将下载镜像以Graph的形式存储
5.当需要为docker创建网络环境时,通过网络管理驱动Network driver 创建并配置docker 容器网络环境
6.当需要限制docker容器运行资源或执行用户指令等操作时,通过Execdriver来完成
7.Libcontainer是一项独立的容器管理包,Network driver以及Exec driver都是通过Libcontainer来实现具体对容器进行的操作
整体架构
Docker Compose
核心概念
docker compose是docker官方的开源项目,负责实现对docker容器集群的快速编排,可以管理多个docker容器组成一个应用
需要定义一个yaml格式的配置文件docker-compose.yml,写好多个容器之间的调用关系,然后一个命令可以同时启动或关闭这些容器
docker-compose是单机的多容器管理技术,k8s是跨主机的集群部署工具
核心要素:服务和工程
服务
指一个个应用容器实例
工程
一组关联的应用容器组成的一个完整业务单元,在docker-compose.yml文件中定义
安装
官网有两个版本version2和version3,尽量使用version3(需要和docker版本引擎匹配,1.13.0++)
安装流程
github连接不上可以百度找国内网站替代
使用步骤
常用命令
docker-compose案例
sql建表
CREATE TABLE `t_user`(
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名',
`password` varchar(50) NOT NULL DEFAULT '' COMMENT '密码',
`sex` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别 0=女 1=男',
'deleted' tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON CURRENT_TIMESTAMP COMMENT '更新时间',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
)ENGINE=INNODB AUTO_INCREMENT=1114 DEFAULT CHARSET=utf8 COMMENT='用户表'
Portainer
#安装
docker run -d -p 18000:8000 -p 19000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
Docker Swarm
运维案例
修改了挂载的配置文件然后启动报错
#进入了mysql容器内部
docker exec -it 213 /bin/bash
#修改了配置文件 ,然后重启发现报错
vim /ect/mysql/conf/mysql.cnf
#查看docker配置文件信息
docker inspect 213
#找到GraphDriver.Data.MergedDir这个属性,并且进入到地址
cd /var/snap/docker/common/var-lib-docker/overlay2/xxxxxxxxxxxxxxx
#在进入到配置文件地址
cd diff/etc/mysql/mysql.cnf
#修改好配置文件后重新启动
porainer更新为https服务
1.下载最新的portainer-ce
docker pull portainer/portainer-ce:latest
2.没有私库的情况下,tag镜像为非latest
解决启动一直去拉取最新镜像导致启动不起来的问题
docker tag portainer/portainer-ce:latest portainer/portainer-ce:1.0
注意:agent和私库需要一样的操作
3. 修改portainer-agent-stack.yml文件
一般在/opt/install-portainer/ 文件夹下
4.在portainer-agent-stack.yml所在目录执行以下命令,更新portainer
docker stack deploy --compose-file=portainer-agent-stack.yml portainer
5.访问
首次访问有警告提示,点击高级,继续访问
6.进入portainer
未分类
/var/lib/docker/image 镜像的配置文件
/var/lib/docker/containers 容器的配置文件
/var/lib/docker/overlay2 镜像的原文件 和 容器实例化的地址
/var/lib/docker/containers日志清理方法
方式一 脚本实现
#!/bin/sh
# drift
echo "==================== start clean docker containers logs =========================="
logs=$(find /var/lib/docker/containers/ -name *-json.log)
for log in $logs
do
echo "clean logs : $log"
cat /dev/null > $log
done
echo "==================== end clean docker containers logs =========================="
该方式随着时间推移,日志会一直在
[root@drift ~]# crontab -l
#Ansible: clean_logs
* * 2 * * /bin/sh /server/scripts/clean_logs.sh &>/dev/null
方式二 设置docker容器日志大小
通过配置容器docker-compose 的max-size来实现
logging:
driver: "json-file"
options:
max-size: "2g" # 日志文件大小
max-file: "10" # 日志的数量
方式三 全局设置
配置文件 /etc/docker/daemon.json 添加log-dirver和log-opts参数
max-size=500m,意味着一个容器日志大小上限是500M,
max-file=3,意味着一个容器有三个日志,分别是id+.json、id+1.json、id+2.json。
注意:设置的日志大小,只对新建的容器有效
{
"log-driver":"json-file",
"log-opts": {"max-size":"500m", "max-file":"3"}
}
修改完重启
systemctl daemon-reload
systemctl restart docker