本篇论述的内容
- Docker 解决的问题
- Docker 论述
- Docker常用命令
- Docker镜像、网络、数据卷简述
- DockerFile
- DockerCompose
- 容器编排Swarm与k8s
注:本文内容来自B站狂神说java的Docker视频总结。
一、Docker为啥出现
当然是为了赚钱啦,于是做docker的几个人成立了dotcloud公司,但是因为没有知名度赚不到钱,为了公司能或下去,于是将项目开源。很快,越来越多的人发行了docker的优点,就火了。
那Docker到底有什么优点呢,亦或说它解决了哪些问题呢?
- 解决了运行环境不一致的问题(避免了程序在我电脑上能跑,但是在你电脑不能跑的尴尬),这也使得DevOps(开发和运维)变得更简单。
- Docker通过操作系统层面的虚拟化技术,运行的各个容器直接相互隔离,都有的自己的文件系统,但是都是使用的服务器的内核,将服务器资源利用到极致;
二、Docker常用命令
2.1、 Docker安装
详见linux基本操作2.10.3 yum安装docker,亦或查看官网文档。
2.2、Docker运行原理
Docker引擎直接运行在宿主机操作系统上,不需要像虚拟机那样虚拟化硬件资源,不需要加载操作系统内核,能充分利用硬件资源,启动极快。
Docker结构:
Docker,是一个Client-Server结构的系统,Dcoker守护进程运行在宿主机上,客户端通过socket访问守护进程,守护进程进程接受客户端命令,并管理运行的容器。
2.3、Docker帮助命令
docker version #显示docker版本信息
docker info # 显示docker系统信息,包括镜像和容器数量
docker 命令 --help #帮助命令,可以通过这个命令,查看docker命令的具体用法
2.4、Docker镜像命令
docker search 关键字 # 搜索相关镜像
docker pull 镜像名 #拉取镜像到本地
docker rmi 镜像名或id #删除镜像
docker images #查看本地所有镜像
2.5、Docker容器命令
docker run 参数 镜像名或id #创建容器并启动
docker ps #查看运行中的镜像
docker start 容器id #启动容器
docker stop 容器id #停止容器
docker restart 容器id #重启容器
docker kill 容器id #强制停止容器
docker run 参数说明:
--name='name' #容器名称
-d #后台方式运行
-e #容器参数
-it #交互方式运行,启动后会进入容器
-p [ip可选]主机端口:容器端口 #端口映射
docker ps 参数说明:
-a #查看所有容器
-n=? #显示最近创建的容器
-q #只显示容器的编号
进入容器
docker exec -it 容器id bashShell #进入容器(bashShell一般用/bin/bash即可),可以操作
docker attach 容器id #进入当前容器,不会id新的进程
区别:
exec ,会启动新的终端,可以进行操作;attach不会启动新的终端,而是进入正在运行的进程。一般使用第一种即可。
其他常用相关容器命令
docker inspect 容器id #查看容器元数据新
docker top 容器id #查看容器进程信息
docker cp 容器id:容器内路径 宿主机路径 #将容器内文件拷贝到宿主机
docker cp 文件或目录 容器id:容器内路径 #将宿主机文件拷贝到容器
docker logs 参数 容器id #查看容器日志信息
docker stats #实时查看docker容器cpu内存使用情况
2.6、docker命令总结
images #列出系统当前镜像
rmi #删除镜像
history #展示一个镜像形成历史
commit #提交当前容器为新的镜像
create #创建一个新的容器
run #创建(不存在)并执行容器
cp #复制文件
diff # 查看容器变化
import #从tar包内容创建一个新的文件系统映像(对应export)
export #导出容器的内容流为一个tar归档文件
load #从一个tar包中加载一个镜像(对应save)
save #保存镜像为一个tar包
build #通过DockerFile定制镜像
pull #拉取镜像
push #推送镜像库到docker服务器
start #启动容器
kill #kill指定容器
stop #停止容器
unpause #取消暂停容器
pause #暂停容器
wait # 截取容器停止时的退出状态值
logs # 输出当前容器的日志信息
inspect #查看容器元数据信息
attach #当前shell进入容器
port #查看端口映射
ps #列出容器列表
top #查看容器进程信息
rm #删除镜像
exec #指定shell进入容器
search #搜索镜像
login #登录或注册到docker源服务器
logout #退出docker源服务器
version #显示docker版本信息
info #显示系统相关信息
events #从docker服务器获取容器实时事件
2.7、命令的使用:安装ngnix、tomcat、es+kibana、mysql、gitLab;
安装nginx
docker search nginx #查看dockerhub上相关的nginx镜像,
#也可以到官网上查看(https://hub.docker.com/_/nginx)
docker pull nginx
docker images
docker run --name="nginx" -d -p 80:80 nginx
安装完成进入容器,可以看到nginx的配置文件
浏览器访问80端口:
修改nginx每次都要进入容器十分麻烦,我们可以通过数据卷,在宿主机提供一个映射路径,在宿主机修改文件,就会自动修改容器内文件;
但是此时容器已经启动了,若要修改启动参数,有三种方式,参考博文:Docker 修改容器参数
安装tomcat
安装es+kibana
es初始化内存至少2G,会让服务器比较卡,可以在启动时添加参数
docker pull elasticsearch:7.6.2
docker run --name="elasticsearch7.6.2" -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64M -Xmx512m" elasticsearch:7.6.2
访问:
安装mysql
详见3.2数据卷
安装gitLab
docker run -d --name="gitlab" -p 8443:443 -p 8080:80 -p 2202:22 -v /root/gitlab/config:/etc/gitlab -v /root/gitlab/logs:/var/log/gitlab -v /root/gitlab/data:/var/opt/gilab 镜像名
修改配置文件,降低gitlab对内存的使用,进入容器/etc/gitlab或修改config目录下的gitlab.rb文件;
unicorn['worker_processes'] = 2 #修改cpu核数
#修改最大小内存
unicorn['worker_memory_limit_min'] = "100 * 1 << 20"
unicorn['worker_memory_limit_max'] = "200 * 1 << 20"
sidekiq['concurrency'] = 4 #修改并发数
postgresql['shared_buffers'] = "128MB" #修改数据库缓存量
postgresql['max_worker_processes'] = 1 #修改数据库并发数
prometheus_monitoring['enable'] = false #关闭监控
修改之后,容器内重新使配置文件生效:
gitlab-ctl reconfigure
gitlab-ctl restart
如果内存大量被占用,可以设置虚拟内存:
参考虚拟内存设置
free -m #1、先查看内存现在的状态
mkdir swap #2、创建虚拟内存状态
cd swap
dd if=/dev/zero of=swapfile bs=100M count=50
mkswap /usr/swap/swapfile #注意自己的文件路径位置
swapon /usr/swap/swapfile #用命令激活swap,立即启用交换分区文件
vim /etc/fstab #3、/etc/fatab里直接写入
/usr/swap/swapfile swap swap defaults 0 0
以下文段来自:在 Linux 系统中,可以通过查看 /proc/sys/vm/swappiness内容的值来确定系统对 SWAP 分区的使用原则。当 swappiness 内容的值为 0 时,表示最大限度地使用物理内存,物理内存使用完毕后,才会使用 SWAP 分区。当 swappiness 内容的值为 100 时,表示积极地使用 SWAP 分区,并且把内存中的数据及时地置换到 SWAP 分区。
修改前为 0,需要在物理内存使用完毕后才会使用 SWAP 分区:
- 临时修改
echo 10 >/proc/sys/vm/swappiness
- 永久修改
vim /etc/sysctl.conf #设置,增加以下配置
vm.swappiness=10
使配置生效
sysctl -p
三、Docker镜像、容器卷、网络解释
3.1、镜像
镜像是一个轻量级、可执行的独立软件包,用来打包软件运行环境和基于环境的软件,包括软件的所有内容,包括代码、运行时、库、环境变量和配置文件。
Docker镜像是基于UnionFS文件系统(分层、轻量级且高性能的文件系统,对文件的修改是一层层叠加的,同时不同的目录可以将不同目录挂载到同一虚拟文件系统下),所以Docker镜像可以通过分层来继承,基于基础镜像,制作各种具体的应用镜像。Docker镜像文件图如下:
bootfs(boot file system)主要包含bootloader和kernel,在linux刚启动时bootloader引导加载kernel,当bootfs文件系统加载完成后,kernel就被加载到内存中去了,此时内存的使用权,就由bootfs转交给kernel了,此时系统会卸载bootfs。
rootfs(root file system)在bootfs之上,包括/dec、/proc、/bin、/etc等标准目录和文件,rootfs就是各种不同linux操作系统的发行版本,如ubuntu、centos等。
Docker基础镜像就是一个很小的linux OS,只包含最基本的命令、工具和程序库。而bootfs,所有的linux OS基本一致,Docker就直接使用宿主机的bootfs。
Docker镜像通过分层继承,下载过的层级就不会再进行下载(层级共享)。
Docker镜像的所有层级都是只读,不能修改。当容器启动时,会在镜像上顶部增加一个可写层级,这就是容器层。而我们提交容器为镜像时,会保存当前容器的状态为新的一层。
tomcat安装演示:
分层镜像文件下载:
启动容器,新增一个可写层:
此时访问查看:
docker官方的tomcat镜像,访问404。需要在容器内进行修改,将空的webapps 删除,将webapps.dist文件名修改为webapps。此时再访问,就可以看到tomcat欢迎界面了。
将此时的tomcat容器状态打包为一个新的镜像,以后启动这个镜像就可以正常访问了:
3.1.1镜像推送
我们也可以将这个镜像push到阿里云镜像仓库去上(dockerhub),以后直接拉取这个镜像:
推送步骤
<1>登录:sudo docker login --username=用户名 服务器地址(可在阿里云容器镜像查看自己的地址)
<2>阿里云创建命名空间
<3>创建本地镜像仓库
<4>根据操作指南,上传镜像
<5>上传成功后,我们就可以看到自己上传的镜像版本
3.2、容器卷
docker镜像是将应用和环境都打包了,而我们的操作都记录在容器,若将容器删除了,那么我们操作的所有数据就都被删除了,十分危险。为了避免这种删除容器,数据就消失的问题,就需要一个数据的备份,将数据同步到宿主机上,这就是容器卷技术,将容器内的目录挂载到宿主机上。
通过容器卷技术,无论是容器内数据发生变化还是宿主机数据变化,都会保持数据的同步一致。通过 -v命令(-v 宿主机目录:容器内目录[:ro/rw(读写权限)])即可实现挂载,挂载分为具名挂载和匿名挂载(不写宿主机目录)。
mysql安装:
docker run -d --name "mysql5.7" -p 3306:3306 -v /home/mysql/conf:etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
进入容器,对mysql远程授权:
docker exec -it 容器id /bin/bash
<1>mysql登录
mysql -u root -p密码 #注意密码和-p之间没有空格
<2>授权
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '密码' ;
flush privileges;
show grants for root;#查看授权
数据卷(实现多个容器之间的数据共享)
在容器启动时,通过 参数(–volume-from 父容器名 )实现两个容器之前的数据同步。这些同步的数据是拷贝概念,子容器数据并不会因为父容器数据删除而丢失数据。并且,还可以将数据挂载到宿主机上,此时所有容器删除,本地数据依旧存在。
命令:
docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from 父容器名 mysql:5.7
3.3、网络
查看服务器ip地址(ip addr):
可以看到一个docker0地址,后面的33、35、37地址则是容器地址,容器启动时,docker0会给容器分配地址,使用veth-pair(虚拟设备接口,一端连接协议,一端彼此相连,veth-pair充当桥梁。参考文章)桥接。docker0直连物理网卡的,宿主机是docker容器的。
因此,容器与宿主机,容器与容器之间都是可以互相ping通的。但是只能通过ip地址进行ping,若要使用容器名进行ping,可以在容器启动时,使用 —link 容器,之后就可以使用容器名ping了,但是这种方式是直接修改容器内/etc/hosts文件,添加一个映射地址(已不推荐使用)。
docker run -d --name="容器名" --link 要ping的容器名 -p 宿主端口:容器端口 镜像名
自定义网络
查看所有docker网络类型:docker network ls
brige:桥接模式,默认,创建也是使用这个模式;
none:不创建网络;
host:和主机共享网络;
container:容器网络联通(局限大,一般不用)
在启动容器时,加上 --net brige或者不写 ,就是指的docker0(只能ip访问,容器名不能访问)
docker run -d --name tomcat --net bridge tomcat <=> docker run -d --name tomcat tomcat
因此,自定义一个网络,使得可以通过容器名进行访问:
docker network create -d bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 customernet
指定自定义网络启动容器:
docker run -d -p 8080:8080 --name tomcat01 --net customernet tomcat:9.0
如果报错
WARNING: IPv4 forwarding is disabled. Networking will not work.
则需要网桥开启转发,不然容器启动后,就会没有网络(解决);
vim /etc/sysctl.conf
net.ipv4.ip_forward=1 #添加此行配置
systemctl restart NetworkManager && systemctl restart docker #重启network(centos8版本NetworkManager )和docker服务
sysctl net.ipv4.ip_forward #如果返回为“net.ipv4.ip_forward = 1”则表示修改成功
解决问题后,再启动一个容器:
docker run -d -p 8080:8080 --name tomcat02 --net customernet tomcat:9.0
此时直接通过容器名也可以ping通了。
总结
在自定义网络下,服务之间不仅ip可以ping通,也可以使用容器名ping通。因此通过自定义docker网络,可以让不同的集群使用不同的网络,保证集群安全和健康。
如果要使得两个网络之间的容器能够连通,则需要使用docker network connect命令,将一个容器加入另一个网络中,使得这个容器拥有两个网络。
docker network connect mynet b9758e460297
当我们要跨网络操作别人,就需要使用docker network connect 连通。
四、DockerFile
dockerfile是用来构建docker镜像的命令参数脚本;
构建步骤
<1>编写一个dockerfile文件;
<2>docker build 构建为一个镜像;
<3>docker run运行镜像;
<4>docker push发布镜像(dockerhub、阿里云镜像仓库)
4.1、 DockerFile基础
- DockerFile的指令,必须全部是大写字母;
- 执行顺序,同书写顺序,自上而下;
- # 表示注释
- 每一个指令都会创建提交一个新的镜像层,并提交;
4.2、DockerFile常用命令
镜像构建常用命令
FROM #定义基础镜像;
MAINTAINER #定义镜像作者信息,姓名+邮箱
RUN #镜像构建时,需要运行的命令
ADD #步骤
WORKDIR #镜像工作目录
VOLUME #挂载的目录
EXPOSE #暴露容器运行时的监听端口给外部,如果想使得容器与主机的端口有映射关系,必须在容器启动的时候加上 -P参数
CMD #指定这个容器启动的时候要运行的命令。只有最后一个生效,可以被替代。
ENTRYPOINT #指定容器启动时要运行的命令,可以追加命令
ONBUILD #镜像添加触发器,其参数是任意一个Dockerfile 指令
COPY #将文件拷贝到镜像中
ENV #设置环境变量
bulid镜像命令
docker build -t 镜像名:标签(镜像名必须全部小写) .
Dockerfile是默认文件名,不用-f指定文件名,若不是此文件名,则需指定;.代表当前目录;
测试构建自己的一个镜像
FROM java:8
COPY *.jar /jrebelserver.jar
EXPOSE 8888
ENTRYPOINT ["java","-jar","jrebelserver.jar","-p","8888"]
docker build t jerbel:1.0 .
五、Docker Compose容器管理
dockercompose主要是对容器进行编排管理,编写docker-compose.yml文件(编写dockerfile文件)管理(定义和运行)容器。
5.1、 compose安装:
## 官网安装
sudo curl -L "https://github.com/docker/compose/releases/download/1.3.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 国内镜像安装
curl -L https://get.daocloud.io/docker/compose/releases/download/1.3.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
授权
chmod 777 /usr/local/bin/docker-compose
5.2、docker-compose.yaml编写规则
#三层配置
version:"3.9" #一层,compose版本
service: #二层,服务
web: #自定义服务名 ; 》启动顺序3
image:
build:
depends_on:
- redis #依赖服务名
- db
ports:
network:
...
redis: # 自定义服务名; 》启动顺序2
image:
db: # 》启动顺序1
image:
...
# 三层 其他配置 网络、数据卷、全局配置
network:
frontend:
bakend
5.3、compose部署springboot项目
编写Dockerfile文件
FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8002"]
EXPOSE 8002
ENTRYPOIT ["java","-jar","app.jar"]
编写docker-compose.yml(定义整个服务,需要的环境、端口、挂载目录、网络等)文件:
version: '3.9'
services:
demo:
build: .
image: demo
ports: 8002:8002
depends_on:
- redis
redis:
image: redis
启动项目:
docker-compose up --bu
项目如果需要重新部署打包
docker-compose up - -build
注:
- 默认服务名:文件名_服务名;
- 项目下的所有容器都在一个网络下;
停止项目:
docker-compose down #将会删除项目启动的容器以及自动创建的网络
一些其他命令
docker-compose up -d
docker-compose ps
docker-compose stop #完全删除容器
六、集群管理Docker Swarm
6.1、swarm基本概念
swarm主要是对宿主机的集群容器进行编排和管理的,能够实现动态扩展、动态更新、动态扩容。swarm是在docker环境中的扩展,通过初始化swarm,让其他服务docker节点加入到swarm集群,之后就可以管理节点node节点而管理服务service。docker-swarm官网地址。
docker engine引入swarm模式,使得我们可以创建由一个或多个docker引擎组成的集群,称为swarm。swarm由一个或多个节点(节点有两类型:manager和workers)组成,在swarm模式下运行docker引擎或更高的物理或虚拟机。
管理节点
管理节点用于处理集群管理任务,包括:
-
维护集群状态
-
调度服务
-
为集群端点的HTTP API提供服务
通过Raft协议,管理维护整个swarm及其上运行的所有服务的一致内部状态。为了swarm模式的容错特性,根据组织的高可用要求实现奇数个管理节点,便于在不停机的情况下从管理器节点的故障中恢复。- 一个三个管理器的集群,最多可以容忍一个管理的损失;
- 一个五个管理器的集群,最多可容忍同时丢失二个管理节点;
- 一个N管理器的集群,最多可容忍丢失(N-1)/2个节点。
添加更多的管理器并不意味着可扩展或更高的性能,一般来讲,情况正好相反。Docker建议一个群,最多有七个管理节点。
工作节点
工作节点是Docker引擎的实列,其唯一的目的是执行容器。Woker节点不参与Raft分布状态,不做出调度决策,也不为HTTP API提供服务。
可以创建一个由一个管理节点(最少一个管理节点)组成的群,在单个管理器节点集群中,运行docker service create,调度程序将所有任务放在本地引擎上。
Raft一致性协议:保证大多数节点存活才可用(即活的节点要多余死去的节点,因此最少需要3节点,存活节点>1)。因此,docker集群要保证高可用,则至少需要三个主节点,当一个主节点挂掉时,存活的节点还有两个,保证大多数可用。
6.2、简单的swarm搭建
命令
我个穷比不配学技术😂,买不起最少4台服务器,就看看命令。
docker swarm --help
docker swarm init --help #初始化一个管理节点
docker swarm join --help #加入一个节点
swarm搭建就两步:
- init初始化swarm
- 把需要的加入集群的节点join到对应的角色(管理节点、工作节点)
测试
1、初始化swarm,生成一个管理节点。
注:默认使用内网ip,若要使用外网ip,则需要指定外网ip;(端口默认:2377)
docker swarm init --advertise-addr 10.0.1.5(ip地址,最好集群的服务器都在一个网络中,通过内网地址访问)
2、docker swarm join加入
docker swarm join-token worker #查看如何加入为工作节点
docker swarm join-token manager #查看如何加入为管理节点
如果加入出错,去配置防火墙,开放2377端口
3、查看节点信息
docker node ls
4、离开集群
docker swarm leave --force
6.3、docker service
service可以实现集群状态下的弹性扩缩容,对比docker run:
- docker run 启动一个单机项目,不能扩缩容;
- docker service 服务,具有扩缩容,滚动更新;
通过service,swarm能轻松实现灰度发布:金丝雀发布(一般来说,随着一个产品不断地快速迭代开发上线,必然会有一方面要保证线上版本稳定,另一方面又要保证新版本上线的需求。用较小的代价试错,即使出现了严重的错误,对业务总体的影响也是可承受的或者是非常小的,这就是金丝雀发布)。
创建服务:
docker service create -p 8088:80 --name mynginx nginx
创建的服务,通过任意节点的ip:端口都能够访问到。
动态扩容(创建三个副本):
docker service update --replicas 3 mynginx
视流量情况,创建副本数;
6.4、swarm总结
- swarm对集群进行管理。docker初始化一个swarm集群,其他节点可以加入(管理者、工作者);
- service,可以在管理节点或工作节点来运行(核心)。用户访问的内容就是服务;
- task,任务,容器内的命令,细化任务;
swarm运行机制及原理:
七、Docker Stack
docker-compose,是进行单机项目部署;
#单机
docker-compose up -d work.yaml
docker stack部署,是集群部署;
#集群
docker statck deploy work.ymal
八、Docker Secret
配置密码、安全证书