目录
2. 安装docker(参考官方文档https://docs.docker.com/)
3.1 docker run --help 启动命令参数说明
2. --link(现在不常用,功能有限,实际中经常使用自定义网络)
3.3 网络连通docker network connect跨网络通讯
一. docker简介
docker是为了解决环境配置应用部署的不同环境问题,提供一次性安装,多地拿来即用的解决方案。
docker核心思想:打包装箱,每个包运行在不同的容器中,容器的环境都是互相隔离的。
docker的历史:
docker一开始是美国的一家dotCloud开发云计算的创业公司。主要做Linux虚拟内核容器技术,然后他们搞了一套容器化技术,就叫docker。一开始是无人问津的。知道docker被开源后,逐渐被人熟悉并了解了其强大好用的功能。从而促使docker越来越活跃。至今已经成为了行业不可或缺的解决方案。
它本质上也是一种虚拟化技术,并不是模拟的一个完整的操作系统(共享服务器内核,容器运行在服务器上,容器中只需要安装需要的APP和环境即可),但是它的容量是很小的。体量非常轻,是使用GO语言开发的开源项目。
docker的出现和使用能够极大的提高开发效率:
- 能够使程序的部署,扩展更加简易,使用docker直接部署即可
- 使用相同的镜像,保证不同环境是一致的
- 能够最大效率的利用服务器资源,使服务器利用率达到极致
二. docker的安装
1. docker的组件组成
- 镜像(image)
docker的镜像就是打包好的一整套服务,形成的镜像文件。镜像可以运行在docker容器中
- 容器(container)
docker容器就是用来运行docker镜像的隔离环境。一个镜像可以被运行在多个容器中。
- 仓库(repository)
docker 的仓库就是用来存储docker镜像的云仓库。我们可以从仓库中获取镜像, 也可以将自己的镜像打包上传至仓库中
官方的仓库是docker hub,但是是国外的仓库,所以需要配置镜像加速来访问docker Hub
2. 安装docker(参考官方文档https://docs.docker.com/)
- 环境准备
centos 7(cat /etc/os-release查看)、 系统内核3.10(uname -r查看)
- 卸载旧版本docker
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
- 准备安装环境
yum install -y yum-utils #安装docker环境
- 设置镜像地址
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
#可通过docker info查看docker相关信息
- 安装docker
#docker-ce 是指docker社区版,企业版是-ee,以及安装docker客户端、容器等
yum install docker-ce docker-ce-cli containerd.io
#也可以通过指定版本安装docker,默认都是安装最新版本的
yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io
- 启动并测试docker
#启动
systemctl start docker
#查看
docker version
#运行测试官方提供的测试镜像
docker run hello-world
- 卸载docker
#卸载安装包
yum remove docker-ce docker-ce-cli containerd.io
#删除资源文件
rm -rf /var/lib/docker
3. 阿里云镜像加速
登录阿里云--控制台---弹性计算---容器镜像服务---镜像加速
执行这几个命令即可完成镜像加速。能够帮助我们下载上传镜像速度更快。
三. docker的常规使用
1. 工作原理
docker本身是通过service-client模式来完成工作的。 dockerservice守护进程运行在宿主机上。
docker为什么比VM运行速度快?
VM: 创建一个虚拟机,就安装了一整套的操作系统,然后去部署应用,多个虚拟机就是多个操作系统
docker: 安装docker后,应用可以部署在容器中,每个容器都是互相隔离的,就相当于每个容器就是一个操作系统。但是docker容器占用的内存和空间是很小的,因为多个容器是利用宿主机的内存和内核的。不需要在容器中安装过多的重复的东西。
2. docker镜像常用命令
帮助命令查询:
docker 命令 --help 例如镜像的帮助命令: docker image --help
或者通过官方文档查阅reference:https://docs.docker.com/engine/reference/commandline/image_ls/
- docker images --help
docker images = docker images -a : 显示所有镜像
docker images -q :只显示docker镜像的ID
- docker search mysql : 在dockerHub上搜素镜像
- docker pull mysql:5.7 : 下载指定版本的镜像, 如果不加版本则默认下载最新版本latest
- docker rmi :删除镜像
docker rmi -f $(docker images -aq) 删除所有(过滤器传入的是所有的容器ID)、
docker rmi asdfwe4as 删除指定容器ID
3. docker容器常用命令
3.1 docker run --help 启动命令参数说明
- docker run --name centos 启动的容器名称别名
- -d 后台方式运行
- -it 使用交互方式运行,即表示能够进入容器查看内容
- -p 指定端口 -p 8888:8080 即表示宿主机的8888端口映射到容器的8080端口
- -P 指定随机端口
docker run -dit --privileged -p21:21 -p30000-30010:30000-30010 --name test centos:centos7 /usr/sbin/init
3.2 其他常用命令
- docker ps -a : 查询所有的容器 docker ps 查询正在运行的容器
- docker rm id : 删除指定ID容器,不能删除正在运行的容器
- docker rm -f $(docker ps -aq):删除所有容器,会把正在运行的容器强制删除
- docker start id:启动容器
- docker restart id :重启容器
- docker stop id : 停止容器
- docker kill id :强制停止容器
- docker logs -tf --tail 10 容器id: 查看指定容器指定最新行数的日志
- docker top 容器ID : 查看容器内部的进程信息
- docker inspect 容器ID :查看容器的元数据
- docker exec -it 容器ID /bin/bash : 进入容器
- docker attach 容器ID :进入容器,并进入正在执行的操作
- docker cp 容器ID:/文件路径 目标路径 : 将容器中的文件copy到宿主机上,例: docker cp sdfwer11:/opt/test.html /opt,就会将id为sdfwer11的容器中的test.html复制到当前服务器的/opt路径下
- docker stats : 查看docker容器的CPU情况
- docker commit -m "msg" -a "author" 容器id 新镜像名:[TAG] :将某个容器打包成镜像存放在本地。eg:docker commit -m "add webapps init" -a "lemon" aea9f1f901ed tom02:1.0
4. docker 的可视化UI界面
简易的图形化管理界面portainer。
docker run -d -p 8091:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer 启动运行portainer即可完成
5. 镜像加载原理
镜像的加载通过联合文件系统来进行镜像的下载。联合文件系统就是一层一层模块化的文件。
例:安装nginx镜像时,可能nginx镜像会分为4层文件(layers【可通过docker inspect ID 查看元数据】),第一层是centos、第二层是JDK环境、第三层是mysql、第四层是python
此时在宿主机的镜像中,依次下载这四层镜像,如果第一层centos已经存在,则无需下载直接跳过(复用)下载第二层。这就是docker的文件分层。
基层的bootfs相当于是服务器的内核,共用该内核,并一层一层的添加镜像文件。
容器中的centos其实内核还是使用的宿主机内核。
启动操作镜像时
当我们启动下载下来的nginx镜像时(下载下来的nginx镜像文件是只读的不可修改),docker就会在原nginx镜像之上再加一层可写入镜像文件(layers),记录我们自己的操作内容。从而之后我们可以把自己修改的镜像打包后上传。
四. docker的进阶使用
docker在使用过程中,主要是应用于生产应用的部署。所以掌握基础的命令是不够的,我们还需要使用docker完成打包,保证数据的安全性以及docker容器之前是如何通讯的等进阶使用:
docker容器数据卷、dockerFile打包镜像、docker网络通讯
1. docker容器数据卷 -v
应用是通过镜像运行在容器中的,所以一旦容器被删除或者丢失,那容器中应用的数据就会全部丢失。所以需要一个持久化技术,来保证容器即便删除,数据还在。这就是容器数据卷的功能。
他能将容器的文件映射到宿主机的路径中。将容器文件和宿主机文件进行同步,实现数据共享。读写宿主机文件就==读写容器中的文件,相当于文件的挂载。
容器间的数据也可以共享
重启容器后数据会自动同步
使用:
docker run -d -v /opt/ceshi:/home[:ro/rw] centos:centos7 /usr/sbin/init 启动该镜像,并将宿主机的/opt/ceshi与容器内的/home进行同步
ro/rw 代表只读/读写权限的设置,如果设置为ro,则改文件只能通过宿主机修改。容器内只能读取。
此时,该容器与宿主机的目录就实现了同步。可以通过查看元数据docker inspect 容器ID 查看挂载情况
EG: mysql数据恢复
下载启动mysql镜像:
①将mysql的配置文件/etc/mysql/conf.d 挂载到宿主机/opt/mysql/conf
②将mysql的数据文件/var/lib/mysql挂载到宿主机/opt/mysql/data
实现文件同步
docker run -d -v /opt/mysql/conf:/etc/mysql/conf.d -v /opt/mysql/data:/var/lib/mysql -p 8096:3306 -e MYSQL_ROOT_PASSWORD=root --name mysql mysql:5.7
启动后,创建数据库test库,并随机创建两张表。因为数据卷已经挂载了,所以宿主机上文件已经同步。
此时删除正在启动的mysql容器。重新按照以上指令启动一个新的mysql容器。
因为挂载的文件已经记录了mysql的数据,所以启动后数据会同步到新的容器中,实现了数据的恢复。
1.1 匿名挂载、具名挂载、dockerFile挂载
docker在进行数据卷挂载的时候,可以通过匿名/具名挂载来实现文件的挂载:
匿名: 不制定宿主机的文件路径,随机分配
docker run -d -p 8891:33306 -v /etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root --name mysql mysql:5.7
具名:在默认的docker数据卷路径下创建一个别名文件夹,用来挂载容器中的数据
# 将容器的路径挂载到具名 sql_data文件夹中 docker run -d -p 8891:3306 -v sql_data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root --name mysql mysql:5.7
dockerFile: 通过构建镜像时,将文件目录进行挂载。这种方式就不需要每次启动的时候手动-v进行挂载了,只要启动容器,就会进行挂载。构建镜像时非常常用
如何查找具名的文件夹呢?可以通过docker volume ls 查看所有的挂载数据卷
1.2 数据卷容器:实现容器间数据同步
如果要实现容器与容器之间的文件挂载共享,可以通过:--volumes-from 容器名 来完成挂在,从而实现不同容器之间,数据的共享和同步。
eg1:
创建一个容器,并挂载目录 -v /opt/data:/home 此时,该容器与宿主的完成数据卷挂载。
再启动一个容器:与第一个容器一样,也挂载到当前宿主机的该路径下, --volumes-from 容器名/容器ID ,此时就相当于继承了第一个容器的挂载,实现了,两个容器间的数据共享(同时挂载在了宿主机的/opt/data路径下,共享同步数据)、
2. docker File 构建镜像
dockerFile就是用来制作自己的镜像,images都是通过dockerFile构建出来的。
编写脚本 ------ docker build 构建脚本 ------ 生成image镜像
镜像可以被push 到docker Hub或者阿里云镜像仓库中
2.1 dockerFile的指令
- docker的关键字都是大写
- 自上而下顺序执行
- 每一行命令都会创建一层镜像,通过build打包成一个整体镜像
- FROM : 指定基础镜像,例如基于centos就FROM centos
- MAINTAINER:镜像的作者
- RUN : docker镜像运行时的命令
- ADD : 添加需要的东西,例如mysql/JDK等之类的,也就是一层一层的镜像从这里添加进去
- VOLUME : 挂载目录
- EXPOSE:需要暴露的端口
- CMD: 指定这个容器启动的时候,需要制定的命令 例如:/bin/bash等,会被最后一个命令替换掉
- ENTRYPOINT : 相比CMD,指定这个容器启动的时候,需要制定的命令,有多个命令时,会追加不会替换
- ENV : 构建的时候设置环境变量
2.2 构建一个简单的镜像
在centos镜像的基础上,创建一个安装了vim以及rz命令的centos:
①首先需要在某个路径下,创建一个dockerfile文件,例如创建一个dockerfile_centos文件,文件内容如下:
#基于centos镜像 FROM centos #作者信息 MAINTAINER lemon<123456@qq.com> #环境变量 ENV WORKPATH /opt #工作路径 WORKDIR $WORKPATH #run :构建时,运行相应的命令 RUN yum -y install vim RUN yum -y install lrzsz #暴露8080端口 EXPOSE 8080 #启动容器运行的命令 CMD /bin/bash
②指定 docker build -f dockerfile_centos(构建文件的路径) -t mycentos:1.0(镜像名及版本) .
③显示successful表示构建成功,在本地就可以看到构建出来的images了。
通过docker history 镜像ID的方式可以查看镜像构建的历史,可以通过这个命令,查看别人镜像的构建过程,例如:
2.3 构建一个复杂的镜像(具有JDK环境的centos)
① 创建文件Dockerfile(改文件名为官方规定文件名,启动时可以不用-f指定)
FROM centos
MAINTAINER lemon
# 根据压缩包自动解压文件到容器中该路径
ADD jdk-8u201-linux-x64.tar.gz /usr/local/jdk
RUN yum -y install vim
ENV WKPATH /usr/local
WORKDIR $WKPATH
#添加JDK的环境变量
ENV JAVA_HOME /usr/local/jdk/jdk1.8.0_201
ENV CLASSPATH .:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH $JAVA_HOME/bin:$PATH
EXPOSE 8083
#指定启动jar包的命令
CMD nohuo java -jar /usr/local/jar/pms-2.0-SNAPSHOT.jar &
然后通过docker build -t pms . 构建镜像
运行镜像:将宿主机的jar包路径挂载到容器中的jar包路径,然后通过启动命令nohup启动jar包
docker run -dit -v /opt/docker/jar:/usr/local/jar -p 8097:8083 pms nohup java -jar /usr/local/jar/pms-2.0-SNAPSHOT.jar &
此时就完成了自己构建一个具有JDK环境的centos。+
3. 发布镜像
- 注册dockerHub账号
- 服务器登录dockerHub账号
- 提交镜像push到仓库
命令:
①将镜像重新打标记:例如我的dockerHub用户名是:lemon,那如果我的本地镜像的name是pms,我在直接
docker push pms时,是会被拒绝的:“denied: requested access to the resource is denied”
此时需要将镜像打标记,标记为用户名格式:lemon/pms 才可以push成功
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
docker tag [本地镜像名:tag] [需要改成的镜像名:tag]
eg: docker tag pms:latest lemon/pms:1.0
此时docker images 就发现多个lemon/pms 1.0 这个镜像,我们就提交这个镜像push上去就可以了
②push到远程:docker push [name:tag]
eg: docker push lemon/pms:1.0
五. docker的网络通讯
docker中的网络通讯是通过虚拟网卡的形式实现通讯。安装了docker的宿主机会默认分配一个虚拟网关,用来作为桥接docker容器的网桥。从而能够支持宿主机与容器间能够网络通讯,容器与容器间也能进行网络通讯
常用命令
- docker network ls :查看docker网络模式
- docker network inspect 网络模式名/ID :查看该网络模式的元数据
- docker run --link serverName :打通容器名的网络通讯
- docker run --net mynet :启动时使用指定网络模式
- docker network connect mynet server01 :将某个容器加入到某个网络中
1. docker的网络原理
- docker0 网络
docker0是docker安装后就会有的虚拟网卡,主要用来桥接容器与容器。容器与宿主机间的网络通讯。
- 启动一个容器后,宿主机就会多出一个网卡信息,在容器中也会有个网卡信息。组成了一对基于evth-pair技术实现的网络桥接模式
也就是说我们每启动一个容器,宿主机都会分配一个虚拟网卡(此时宿主机的docker0就相当于一个路由器,每当一个容器连接后,就分配一个IP地址,路由器可以连接容器,容器也可以通过路由器连接其他的容器)。该网卡信息与容器中的信息组成一个桥接组。实现网络通讯。
- 宿主机可以与容器通讯,容器也可以与容器进行通讯
容器与容器间网络通讯原理图
- 查看当前docker网络
可以通过docker network --help 查看docker网络情况
例如查看docker现在所有的网络:docker network ls
查看某个容器的网络元数据: docker network inspect [id] 也可以通过 docker inspect 容器ID ,在元数据中也可以查到
2. --link(现在不常用,功能有限,实际中经常使用自定义网络)
如果要实现容器间的通讯,直接通过分配的IP访问的话,就会存在,如果容器重启就可能会导致IP更换。所以我们可以通过服务名的方式来实现通讯
例如:有两个容器A,B。 A中可以通过B:8080/user/login的方式代替IP来进行访问
eg:
# 运行一个server01的容器 [root@hecs-x-medium-2-linux-20200604093545 docker]# docker run -dit --name server01 centos 1e53ae254d24e5da6d40c40a0d73206660d335c2ad056545a63a16373c0a84cc [root@hecs-x-medium-2-linux-20200604093545 docker]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1e53ae254d24 centos "/bin/bash" 5 seconds ago Up 4 seconds server01 [root@hecs-x-medium-2-linux-20200604093545 docker]# clear #运行一个server02,并且--link server01 与01建立网络通讯 [root@hecs-x-medium-2-linux-20200604093545 docker]# docker run -dit --name server02 --link server01 centos 34e8ac055fcb90b532f2ab822a576b7725cfd113019351b1ed94d4d858c77228 [root@hecs-x-medium-2-linux-20200604093545 docker]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 34e8ac055fcb centos "/bin/bash" 6 seconds ago Up 4 seconds server02 1e53ae254d24 centos "/bin/bash" 31 seconds ago Up 30 seconds server01 #成功ping 通 [root@hecs-x-medium-2-linux-20200604093545 docker]# docker exec -it server02 ping server01 PING server01 (172.17.0.2) 56(84) bytes of data. 64 bytes from server01 (172.17.0.2): icmp_seq=1 ttl=64 time=0.058 ms 64 bytes from server01 (172.17.0.2): icmp_seq=2 ttl=64 time=0.039 ms 64 bytes from server01 (172.17.0.2): icmp_seq=3 ttl=64 time=0.034 ms
此时,访问server02的hosts文件发现:
3. 自定义网络
docker可以进行自定义网络连接,也就是说,可以自己规定一种网关,然后启动容器的时候,将容器加入到自己的网关中。自定义网络之间又是互相隔离的。
特点:
- 自定义网络是可以实现容器间、宿主机间通讯的
- 不通过--link 也可以实现通过容器名进行通讯
- 可以实现网络隔离,例如mysql集群共用一个网络路由,jar服务共用一个网络路由,就可以通过创建两个不同的自定义网络实现
- 可以自定义很多配置
3.1 docker的网络模式
- bridge:桥接模式,默认启动容器就是这种模式,就是使用我们的docker0网关
- none:不配置网络
- host:和宿主机共享网络
- 自定义网络....
如果我们启动一个容器时: docker run -d centos 默认就是使用的bridge网络模式相当于:docker run -d --net bridge centos
但是这种默认的模式会存在很多缺陷和局限性,例如如果容器重启就会导致IP变化,就需要配置一个服务名使用--link来进行通讯,十分麻烦。
所以我们可以通过自定义网络的形式,来替代默认的网络模式
3.2 创建自定义网络模式
通过docker network --help 查看命令可以找到创建网络模式的指令
docker network create
# --driver bridge 模式是桥接模式
#--subnet 192.168.0.0/16 : 子网地址的可分配IP范围是192.168.0.1 ——192.168.255.255
#--gateway 192.168.0.1 : 网关入口是从192.168.0.1开始
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
启动测试:启动时,指定net模式为自定义模式 --net mynet
并且两个容器见,可以通过名字ping通
3.3 网络连通docker network connect跨网络通讯
docker network connect 可以将某个容器加入到某个网络路由中去:docker network connect 网络模式名 容器ID/容器名
如下图:
如果server01想访问server_net01该怎么办呢?
可以通过: docker network connect mynet server01
相当于将server01这个容器,也加入到mynet这个网络模式中,server01就相当于有了两个IP地址。
此时,就可以在server01中直接访问到server_net01中的内容了,两个不同网络中的容器就可以打通了。
测试:
此时,查看mynet的元数据:docker network inspect mynet。
六. 搭建单机版Redis集群
实现:
在一台服务器上,搭建6个Redis,实现一个三主三从的Redis集群
①创建Redis的网络模式:
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 redis
②创建6个Redis配置文件,并开启集群,这里通过shell脚本实现:
六次循环,写入配置文件
for port in $(seq 1 6); \
do \
mkdir -p /opt/docker/redis_cluster/node-${port}/conf
touch /opt/docker/redis_cluster/node-${port}/conf/redis.conf
cat <<EOF>> /opt/docker/redis_cluster/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 192.168.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
③启动6个Redis镜像 端口从6381-6386 通讯端口16381-16386
并将Redis的数据、Redis的配置文件(挂载到脚本自动生成的配置文件路径)进行挂载
docker run -p 6386:6379 -p 16386:16379 --name redis-06 -v /opt/docker/redis_cluster/node-6/data:/data -v /opt/docker/redis_cluster/node-6/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 192.168.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
④进入某个Redis容器,创建集群
docker exec -it redis-01 /bin/sh
/data # redis-cli --cluster create 192.168.0.11:6379 192.168.0.12:6379 192.168.0.13:6379 192.168.0.14:6379 192.168.0.15:6379 192.168.0.16:6379 --cluster-replicas 1
⑤测试
集群创建完成。