- 学习视频:https://www.bilibili.com/video/BV1og4y1q7M4?p=7&spm_id_from=pageDriver
- Docker Hub:https://hub.docker.com/
- Docker Doc:https://docs.docker.com/
入门篇
概述
为什么要有docker
- 环境配置方便,比如hadoop,每台机器都要配置文件。
- 自带开发环境,发布方便。例如一个项目打一个jar,但是要运行jar还要Reids,ES,MQ等环境支持。
- 跨平台,Java项目可以跨平台,但相关环境不一定。
- 简单运维人员的工作,docker的方案
例如,java开发 --- 生成app --- 发布应用商店 --- 下载安装,即可用
Java开发 --- 生成jar --- 打包自带环境 --- 发布docker仓库 --- 下载安装,直接运行
容器化技术
虚拟机:把整个电脑模拟了一个,虚拟了硬件和内核,各个虚拟机隔离非常的占用资源,响应慢。 同时公用一个运行环境lib,如果lib挂了就都挂了。
容器化:把系统的核心虚拟,没有虚拟硬件,比如linux内核只有4M。各个容器相互隔离,一个lib挂了不影响其他的。
Docker基本组成
客户端:请求服务器,docker pull拉取镜像,docker build编译镜像,docker run,运行镜像。
服务端:每一个镜像可以看做一个class,一个镜像可以有N个运行实例,提供服务,组成集群
仓库:存在镜像,比如Docker Hub
安装
安装准备
1.删除原先docker
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
2.更新yum
yum install -y yum-utils
3.安装阿里云镜像
yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
4.重新构造索引
yum makecache fast
5.安装docker
yum install docker-ce docker-ce-cli containerd.io
6.启动docker
systemctl start docker
安装成功,执行 docker version 查看版本
7.阿里云镜像加速
注:必须删除注释,才能正常运行
# 以系统管理员身份 递归创建/etc/docker目录
sudo mkdir -p /etc/docker
# 以系统管理员身份 在daemon.json文件末尾插入大括号中的配置
sudo tee /etc/docker/daemon.json <<-'EOF'
{
# 这里的地址要改成管理控制台中的加速地址
"registry-mirrors": ["https://5xcgs6ii.mirror.aliyuncs.com"]
}
EOF
# 重启守护进程
sudo systemctl daemon-reload
# 重启docker
sudo systemctl restart docker
8.测试运行
docker run hello-world
docker images 查询镜像
docker run hello-world 到底发生了什么??
常用命令
帮助命令
帮助文档地址):https://docs.docker.com/reference/
docker version 查询版本
docker info 查询信息
docker --help 万能命令
镜像命令
镜像是一种轻量级、可执行的独立软件包,包括:代码、库、环境变量和配置文件等。
镜像加载:采用联合文件系统,分层原理。将一层一层的可以共同的文件一次加载,其他镜像一起使用。。
docker images/docker image ls 查看镜像
docker search mysql 查询镜像mysql
docker pull mysql:laset 下载指定版本镜像 这里应用联合文件系统,分层下载文件,多线程下载,这样如果其他版本公用的就可以不用重复下载
docker rmi/docker image rm 镜像ID 删除镜像
docker rmi -f $(docker images -a -q) 删除全部镜像
容器命令
ducker run 新建并启动容器(镜像实例)
--name 命名
-d 后台运行
-it 使用交互方式运行,可查询容器内容
例如:docker run -it centos /bin/bash
Exit 停止并退出
Ctrl+P+Q 退出不停止
docker attach 容器ID 再次进入容器
docker exec -it 容器ID /bin/bash 或 /bin/sh
-p 指定容器端口
例如:-p 8080:8080 主机端口映射到容器端口
-p 8080 容器端口,内部调用
docker ps 列出容器
docker rm 删除容器
docker rm -f 容器ID
docker rm $(docker ps -aq)
docker start 启动已经停止的容器
docker restart 重启容器
docker stop 停止容器
docker kill 杀死容器进程
操作命令
docker status 查询cpu状态
docker top 查询容器进程信息
docker inspect 查看容器元数据
docker exec -it 容器ID /bin/bash 进入容器打开新的终端
docker attach 容器ID 进入容器使用当前终端
docker cp 源 终 拷贝文件
docker commit 提交镜像
例如:docker commit -a '作者' -m '描述' 容器ID 镜像名:版本号
图形化界面
Portainer 简易界面
docker run -d -p 9000:9000 \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
--name prtainer-test \
portainer/portainer
Rancher 高级界面
高级篇
数据卷
问题:运行时的数据都在容器中,一旦容器被删除,数据就丢失了,且容器间相互隔离,不能公用。比如Mysql数据库
解决:数据卷,容器之间有一个数据共享的技术。目录的挂载,将容器的目录直接挂载在linux上
使用方式
方式一:指定目录挂载
命令 docker run -v 主机目录:容器目录 数据同步是双向的
docker run -d -v /home/ceshi:/home tom002 挂载数据卷
docker inspect 容器ID 查询容器信息,Mount挂载是否成功
实例:mysql
docker run -d --name mysql01 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=111111 -v /home/mysql:/etc/mysql/conf.d -v /home/mysql:/var/lib/mysql mysql:5.7
方式二:匿名挂载 挂载卷不指定linux目录,不命名
不指定linux目录,就会在docker根目录下生成对应挂载目录
方式三:具名挂载 挂在卷不指定linux目录,有命名
不指定linux目录,就会在docker根目录下生成对应挂载目录
拓展
设置挂载目录 读写权限
方式四:Docker File挂载
1. 创建DockerFile文件
采用匿名挂载的方式
2. docker build编译文件生成镜像
docker build -f test_volume.txt -t testdocker/centos:1.0 .
3. 启动容器
发现挂载的目录存在。这里是匿名挂载,因为只是指定了容器目录
4. 查看主机映射目录 docker inspect 容器ID
方式五:数据卷容器
volumes-form 挂载容器,多个容器实现数据备份,实现共享数据
docker run -it --volumes-from 数据卷容器ID 镜像
Docker File
用于构建docker镜像的构建文件。
之前用commit构建过,但它是修改已有的镜像。DockerFile是从无到有
基本指令
FROM 基础镜像
MAINTAINER 作者
RUN 镜像构建时运行命令
ADD/COPY 添加文件
WORKDIR 镜像的工作目录
VOLUME 挂载目录
EXPOSE 开放给linux的端口
CMD 容器启动时运行命令
ONBUILD 继承DockerFile
ENV 环境变量
提交到docker hub
登录账户docker login -u
推送镜像docker push
拓展
提交报错denied: requested access to the resource is denied
原因:一般镜像需要前面加上tag比如tomcat:1.0 改为 xxx/tomcat:1.0 (xxx必须是DockerHub等用户名,分配文件系统)
解决:命令docker tag修改
网络原理
每一个容器都是一个app,那么多个容器之前怎么通信呢??
安转docker时,会在linux上自动生成一个docker容器用的ip地址,默认为docker网关(路由器),采用桥接网络,利用linux自身进行路由转发。类比下VMWare就可以一目了然。
之后,每创建一个容器,docker为该容器自动生成ip,并且会在linux的路由表ifconfig中添加该容器ip,这样就可以容器与服务器,容器与容器之间可以通过ip相互通讯
用ip可以实现相互通信,但分布式集群,怎么可能都用ip呢??
Docker建立的三种局域网络:bridge/host/myXX
解决:自定义局域网
容器之所以会用桥接模式进行相互间通信,是因为 docker run时默认--net bridge ,这里的bridge就是docker0的局域网。
我们可以创建自己的局域网,让所有容器使用自定义的局域网,这样可以解决域名访问。
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
--driver bridge 网络模式为 桥接模式 默认
--subnet 192.168.0.0/16 设置子网
--gateway 192.168.0.1 设置网关
网络连通
对于不同的服务集群可以采用局域网进行隔离,那么不同的局域网的容器需要通信,怎么办??
docker network connect mynet tomcat001
将容器tomcat001,添加到mynet网络中,为它创建一个mynet中的ip,叫做1个容器2个ip。
只有打通的容器可以通信。
以上知识可以满足单台服务器,单个镜像容器之间的部署需求了。但是实际生产往往是N台服务器,N个镜像容器,我们不可能一台一台,一个一个的去部署,那要怎么办?
实战篇
docker-compose
单台服务器,一键启动多个容器
用一个yarm文件配置,用一个简单的命令,直接运行多个容器,包括存在依赖关系的容器(redis/mysql等)。
只需要三步骤:
a. Dockerfile保证项目可以在任何地方运行;
b .Yarm配置文件
c. 命令启动容器
安装
curl -L https://get.daocloud.io/docker/compose/releases/download/1.12.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
测试
1,复制jar、Dockerfile文件
2,创建docker-compose.yml
# 指定docker-compose版本,必须与docker版本对应。。这里不知道也没有关系,启动之后会报错提示
version: "3.0"
# 各个服务配置
services:
# web 自己写的jar,需要编译
web:
# stack不支持build,因为build只是在本机有镜像,不能保证集群机器上有镜像
#build: .
# 指定镜像版本
image: web:1.0
# 指定容器名,各个容器可以根据容器名相互访问
container_name: myweb
# 访问端口
ports:
- 8080:8080
# 启动顺序,按照depends
depends_on:
- redis
- mysql
# 集群部署的主要区别,就是这里
deploy:
replicas: 2
networks:
- webnet
# redis根据已有镜像启动
redis:
ports:
- 6379:6379
# 指定镜像
image: "redis:6.0.4-alpine"
# 数据卷
volumes:
- /home/dockerdir/redis/redis.conf:/etc/redis/redis.conf
- /home/dockerdir/redis/data:/data
# 启动命名 run 镜像 后面跟着的
command:
- redis-server
- /etc/redis/redis.conf
- --appendonly yes
- --requirepass 111111
deploy:
replicas: 1
placement:
# 指定节点运行服务
constraints:
- node.hostname==192.168.207.128
mysql:
image: "mysql:5.7"
ports:
- 3306:3306
volumes:
- /home/dockerdir/mysql/data:/var/lib/mysql
- /home/dockerdir/mysql/conf:/etc/mysql/conf.d
# 环境变量 run -e
environment:
- TZ=Asia/Shanghai
- MYSQL_ROOT_PASSWORD=111111
deploy:
replicas: 1
placement:
# 指定节点运行服务
constraints:
- node.hostname==192.168.207.128
networks:
webnet:
3,执行命令,一键启动
docker-compose up
启动时,会自动创建一个自己的局域网,所以容器都可以自由访问。默认网络名:当前文件夹名
Docker Swarm集群管理
集群情况下,快速启动多个容器,快速扩缩容
参考链接:https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/
创建一个swarm集群
docker swarm init --advertise-addr ip:port
注意:2377端口必须开放 telnet 192.168.207.128 2377,如果不开放则要关闭防火墙:systemctl stop firewalld.service
swarm服务service
将单机的容器,换成服务service,可以动态的扩缩容。比如nginx,增加一个节点就要去nginx配置修改。现在由swarm管理,屏蔽了底层的感知。
单机启动容器:docker run -p 80:80 --name nginx001 nginx:1.18-alpine
集群启动容器:docker service create -p 80:80 --name nginx001 nginx:1.18-alpine
docker stack集群部署
docker-compose up 单机一键启动
docker stack deploy 集群一键启动
# dokcer stack 部署不支持build, 因为build只是在本机有镜像,不能保证集群机器上有镜像
# 需要先生成镜像,推送到远程仓库
build
save
scp
load
# 需要先创建一个ingress网络,联通各个管理节点
docker network create --driver overlay --ingress
# 部署stack
docker stack deploy
问题
- 目前已知创建3个局域网:bridge机器内容器连接、overlay不同机器连接、overlay管理节点连接??
解决:
- ingress:一个端口表示服务,根据请求端口用于服务节点间的负载均衡
- overlay:swam服务之间通信的网络
- bridge: 单台容器间通信的网络
数据库、缓存等需要指定服务器运行,不能随机部署 ??
解决:placement-constraints请求集群任意manage节点都会分发到各个实际存在服务的节点,与nginx有什么区别??
解决:
网络通讯原理 DNS+VIP(虚拟IP)
参考链接:
https://www.jianshu.com/p/60bccbdb6af9
https://www.cnblogs.com/justart/p/11692331.html
https://blog.csdn.net/sinat_33822516/article/details/107595612
Overlay networks 管理 Swarm 中 Docker 守护进程间的通信。你可以将服务附加到一个或多个已存在的 overlay 网络上,使得服务与服务之间能够通信。
ingress network 是一个特殊的 overlay 网络,用于服务节点间的负载均衡。当任何 Swarm 节点在发布的端口上接收到请求时,它将该请求交给一个名为 IPVS 的模块。IPVS 跟踪参与该服务的所有IP地址,选择其中的一个,并通过 ingress 网络将请求路由到它。
初始化或加入 Swarm 集群时会自动创建 ingress 网络,大多数情况下,用户不需要自定义配置,但是 docker 17.05 和更高版本允许你自定义。
docker_gwbridge 是一种桥接网络,将 overlay 网络(包括 ingress 网络)连接到一个单独的 Docker 守护进程的物理网络。默认情况下,服务正在运行的每个容器都连接到本地 Docker 守护进程主机的 docker_gwbridge 网络。