docker
docker安装
#yum安装gcc相关环境
yum -y install gcc
yum -y install gcc-c++
#1.uninstall old version
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
#2.安装需要的软件包
yum install -y yum-utils
#3.设置镜像仓库
yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#4.更新yum软件包索引
yum makecache
#5.安装docker CE
yum install docker-ce docker-ce-cli containerd.io
#6.启动docker
systemctl start docker
#7.配置阿里云加速
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://a44vgxfx.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload
systemctl restart docker
Docker的常用命令
常用
#启动docker
systemctl start docker
#卸载docker
systemctl stop docker
yum -y remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker
帮助命令
docker version
docker info //显示docker的系统信息
docker 命令 --help
镜像命令
docker images 查看本机所有的镜像
docker search 搜索命令
docker pull 下载镜像
docker rmi -f 删除镜像
容器命令
有了镜像才可以创建容器
新建容器并启动
docker run [可选参数] image
#可选参数
--name="name"
-d 后台运行
-it 交互式运行
-p 指定容器的端口 -p 8080:8080
-p ip:主机端口:容器端口
-p 主机端口:容器端口
-p 容器端口
容器端口
-p 随机指定端口
#测试,启动并进入容器
root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker run -it centos /bin/bash
[root@66b736657325 /]#
列出所有运行中的容器
docker ps 查看运行中的容器
#当前运行、
-a #列出运行的容器+历史运行
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
66b736657325 centos "/bin/bash" 5 minutes ago Exited (0) 3 minutes ago bold_golick
bc74ee3218c7 hello-world "/hello" About an hour ago Exited (0) About an hour ago wonderful_kepler
退出容器
exit #退出
Ctrl+P+Q #容器不停止退出
删除容器
docker rm 容器id
docker rm -f $(docker pa -aq) #删除所有
启动和停止容器
docker start 容器id
docker restart 容器id
docker stop id
docker kill id
其他常用命令
#查看日志
docker logs
#自己编写一段shell脚本
docker run -d centos /bin/sh -c "while true;do echo kuangshen;sleep 1;done"
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker ps
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker logs -tf --tail 10 ca62595a175a
#查看容器的进程信息
docker top 容器id
#查看容器的元信息
docker inspect id
#进入当前正在运行的容器
#我们的容器都是使用后台方式运行的,需要进入容器,修改一些配置
docker exec -it 容器id bashShell
#测试
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
df33d9b19dfc centos "/bin/bash" 3 hours ago Up 3 hours intelligent_pasteur
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker exec -it df33d9b19dfc /bin/bash
[root@df33d9b19dfc /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 10:10 pts/0 00:00:00 /bin/bash
root 15 0 0 12:50 pts/1 00:00:00 /bin/bash
root 29 15 0 12:51 pts/1 00:00:00 ps -ef
#方式二
docker attach 容器id
#docker exec #进入容器后开启一个新的终端,可以在里面操作
#docker attach #进入容器正在执行的终端
#从容器内拷贝文件到主机上
docker cp 容器id:
#测试
[root@iZ2vc7zktoz7z9fn3qhptjZ home]# docker attach 31ffda8491d6
[root@31ffda8491d6 /]# cd /home
[root@31ffda8491d6 home]# ls
[root@31ffda8491d6 home]# touch text.java
[root@31ffda8491d6 home]# ls
text.java
[root@31ffda8491d6 home]# exit
exit
[root@iZ2vc7zktoz7z9fn3qhptjZ home]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
31ffda8491d6 centos "/bin/bash" About a minute ago Exited (0) 10 seconds ago sleepy_diffie
#将文件拷贝出到主机上
[root@iZ2vc7zktoz7z9fn3qhptjZ home]# docker cp 31ffda8491d6:/home/text.java /home
[root@iZ2vc7zktoz7z9fn3qhptjZ home]# ls
text.java yang.java
作业
Docker安装Nginx
#1.搜索镜像 docker search
#2.下载镜像 docker pull
#3.运行测试
[root@iZ2vc7zktoz7z9fn3qhptjZ home]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql latest ecac195d15af 16 hours ago 516MB
nginx latest 87a94228f133 7 days ago 133MB
hello-world latest feb5d9fea6a5 3 weeks ago 13.3kB
centos latest 5d0da3dc9764 4 weeks ago 231MB
#-d 后台运行
#--name 给容器命名
#-p 容器内部端口
[root@iZ2vc7zktoz7z9fn3qhptjZ home]# docker run -d --name nginx01 -p 3344:80 nginx
c2487d62a28c0577cf3dd7f1c3dd98967c32a2e81fcc45a6c4bf3502b5ee3924
[root@iZ2vc7zktoz7z9fn3qhptjZ home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c2487d62a28c nginx "/docker-entrypoint.…" 4 seconds ago Up 4 seconds 0.0.0.0:3344->80/tcp, :::3344->80/tcp nginx01
[root@iZ2vc7zktoz7z9fn3qhptjZ home]# crul localhost:3344
-bash: crul: command not found
[root@iZ2vc7zktoz7z9fn3qhptjZ home]# curl localhost:3344
#进入容器
端口暴露的概念
数据卷
作业:安装Tomcat
#官方的使用
docker run -it --rm tomcat:9.0
#我们之前启动的是后台,停止了容器之后,容器还是可以查到 docker run -it --rm 这个命令用完即删
#下载
docker pull tomcat
#启动
docker run -d -p 3355:8080 --name tomcat01 tomcat
#进入容器
[root@iZ2vc7zktoz7z9fn3qhptjZ home]# docker exec -it tomcat01 /bin/bash
#进入容器后发现:1.Linux命令少了 2.没有webapps 阿里云镜像默认只保存最小的镜像,不必要的将会删除
思考问题:我们以后部署项目,每次都要进入容器非常麻烦
部署es+kiband
#es暴露的端口很多
#es十分耗费内存
#es的数据需要放到安全目录挂载
#--net somenetwork
#启动elasticsearch
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
#启动后Linux变得非常卡 docker stats 查看CPU的状态
#es是十分耗内存的
#测试es十分成功
#赶紧关闭,增加内存限制
docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
#测试
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# curl localhost:9200
{
"name" : "df4d4ae3f99e",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "YoDi8IlLRke18VxvJr2gLQ",
"version" : {
"number" : "7.6.2",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build_date" : "2020-03-26T06:34:37.794943Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
作业:使用kibana连接es,网络如何才能连接过去
可视化
portainer
docker run -d -p 8088:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
Rancher
什么是portainer
docker图形化界面管理工具,提供一个后台面板供我们操作
访问测试
测试外网端口8088
如何提交自己的镜像
docker commit #提交容器称为一个新的副本
docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[tag]
实战测试
#启动一个默认的Tomcat
#发现这个默认的Tomcat是没有webapps应用,官方的原因
#自己通过命令拷贝进去了基本的文件
#将我们操作过得容器通过commit提交为一个镜像,我们以后就使用自己修改过得镜像
容器数据卷
什么是容器数据卷
docker理念回顾:将应用和环境打包成一个镜像!
数据?如果数据都在容器中,那么我们删除容器,数据就会丢失 需求:实现数据持久化
MySQL ,容器删了,就完了!!!! 需求:MySQL数据可以存储在本地
容器之间有一个数据共享技术,docker容器产生的数据,同步到本地
这就是卷技术,目录的挂载,将我们容器的目录挂载到Linux上面
容器的持久化和同步操作,容器间也是
使用数据卷
方式1:直接使用命名挂载 -v
docker run -it -v 主机目录:容器目录
#测试
docker run -it -v /home/ceshi:/home centos /bin/bash
实战:安装MySQL
#获取镜像
docker pull mysql:5.7
#运行容器,配置mysql的密码
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
#启动我们的mysql
-d 后台运行
-p 端口
-v 磁盘挂载
-e 环境设置
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
#在挂载的时候宿主机的目录必须不存在或者为空,否则容器会自动停止运行
#
docker run -p 3310:3306 --name mysql01 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
#测试 使用Navicat连接
删除镜像后,数据库的数据并未删除
具名挂载和匿名挂载
#匿名挂载 不指定宿主机内的目录,随机分配挂载目录
docker run -d -P --name nginx01 -v /etc/nginx nginx
#查看所有volume的情况
docker volume ls
[root@iZ2vc7zktoz7z9fn3qhptjZ data]# docker volume ls
DRIVER VOLUME NAME
local 8f25eadc6fc021cceec30d57f098c8b747c0c4259893daef94180fcad9e0d035
local 77191ab5590d6993214c197d35234b802b20b1dd0b3fc9ab89610614478e1cab
local 2561304f2d5452e681af143f6bf7f89a3ffd8d16b54b87fe4d7d56baa54666ef
#具名挂载
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
#测试
[root@iZ2vc7zktoz7z9fn3qhptjZ data]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
47a6f0234961c0370c3c03517e556e74ac2a73569aeb82d5987c3935571d30c7
[root@iZ2vc7zktoz7z9fn3qhptjZ data]# docker volume ls
DRIVER VOLUME NAME
local 8f25eadc6fc021cceec30d57f098c8b747c0c4259893daef94180fcad9e0d035
local 9e95356d6b94193e20b71ca27ba174e7f9dafb083d548cfb41304cba212e1e80
local 77191ab5590d6993214c197d35234b802b20b1dd0b3fc9ab89610614478e1cab
local 2561304f2d5452e681af143f6bf7f89a3ffd8d16b54b87fe4d7d56baa54666ef
local juming-nginx
#查看挂载的具体地址
docker volume inspect juming-nginx
[root@iZ2vc7zktoz7z9fn3qhptjZ data]# docker volume inspect juming-nginx
[
{
"CreatedAt": "2021-10-21T20:17:55+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
"Name": "juming-nginx",
"Options": null,
"Scope": "local"
}
]
#所有docker容器内的卷,在没有指定目录的情况下都在/var/lib/docker/volumes/XXXX/_data
#所有docker容器内的卷,在没有指定目录的情况下都在/var/lib/docker/volumes/XXXX/_data
我们通过具名挂载可以方便的找到我们的卷,大多数时候使用
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载
拓展
#通过 -v 容器内路径:ro rw 改变读写权限
ro #只读
rw #读写
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
#ro只能通过宿主机操作,在容器内部是无法操作的
初识Dockerfile
Dockerfile就是用来构建docker镜像的构建文件命令脚本!
通过这个脚本可以生成镜像,镜像一层一层的,脚本就是一个个的命令,每个命令都是一层
#创建一个dockerfile文件
#文件中的内容命令大写
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "----end----"
CMD /bin/bash
#
docker build -f /home/docker-test-volume/dockerfile1 -t kuangshen/centos:1.0 .
这个卷一定和外部的目录是挂载的
测试刚才的文件是否同步出去
数据卷容器
多个mysql同步数据
启动3个容器,通过我们自己构建的容器启动
#将docker02的数据挂载到docker01 删除docker01,docker02的数据还在,所以文件共享是拷贝的状态
docker run -it --name docker02 --volumes-from docker01 kuangshen/centos:1.0
多个mysql实现数据共享
#第一步
docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
#第二步
docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql02 mysql:5.7
#实现两个容器数据共享
结论:容器之间配置信息的传递,容器数据卷的生命周期一直持续到没有容器使用为止
但是你一旦持久化到了本地,本地的数据是不会删除的
Dockerfile
dockerfile是用来构建docker镜像的文件!命令参数脚本!
构建步骤
1.编写一个dockerfile文件
2.docker build构建成为一个镜像
3.docker run 运行镜像
4.docker push 发布镜像(DockerHub,阿里云镜像仓库)
查看官方是怎么做的
很多官方镜像都是基础包,跟多功能没有,我们通常会搭建自己的环境
官方可以自己制作镜像,我们也可以
Dockerfile构建过程
基础知识
1.每个保留关键字或者指令都必须是大写指令
2.指令从上执行到下
3.#表示注释
4.每个指令都会创建并提交一个新的镜像层
dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件
步骤:开发,部署,运维
DockerFile:构建文件,定义了一切的步骤,源代码
DockerImages:通过DockerFile构建生成的镜像,最终发布和运行的产品
Docker容器:容器就是镜像运行起来提供服务的
DockerFile的指令
#指令
FROM #基础镜像 centos ubantu,一切从这里开始
MAINTAINER #镜像是谁写的 姓名+邮箱
RUN #镜像运行的时候需要运行的命令
ADD #步骤:Tomcat镜像:Tomcat压缩包!
WORKDIR #工作目录
VOLUME #设置卷,挂载到哪个位置
EXPOSE #指定对外的端口
CMD #指定容器启动运行的要运行的命令,只有最后一个会生效
ENTRYPOINT #容器启动是运行的命令,可以追加命令
ONBUILD #当构建镜像被继承,这个时候会运行ONBUILD 的指令
COPY #类似ADD,将文件拷贝到镜像中
ENV #构建的时候设置环境变量
练习:写个自己的镜像
DockerHub中99%的镜像都是FROM scratch,然后配置需要的软件和配置
创建自己的centos
#1.编写dockerfile文件
[root@iZ2vc7zktoz7z9fn3qhptjZ dockerfile]# vim mydockerfile-centos
[root@iZ2vc7zktoz7z9fn3qhptjZ dockerfile]# cat mydockerfile-centos
FROM centos
MAINTAINER ybw<1554094535@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "---end----"
CMD /bin/bash
#2.通过docker build 构建
#3.测试运行
对比
之前的原生centos
增加我们自己的centos
我们可以本地查看变更历史
CMD和ENTRYPOINT的区别
CMD #指定容器启动运行的要运行的命令,只有最后一个会生效
ENTRYPOINT #容器启动是运行的命令,可以追加命令
测试CMD
#编写dockerfile文件
[root@iZ2vc7zktoz7z9fn3qhptjZ dockerfile]# vim dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]
#构建镜像
[root@iZ2vc7zktoz7z9fn3qhptjZ dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .
#run运行
[root@iZ2vc7zktoz7z9fn3qhptjZ dockerfile]# docker run 0ab8341a6e84
.
..
.dockerenv
bin
dev
etc
home
lib
#要想追加一个命令-l,使得执行的命令变成 ls -al,会发现报错
[root@iZ2vc7zktoz7z9fn3qhptjZ dockerfile]# docker run 0ab8341a6e84 -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
ERRO[0000] error waiting for container: context canceled
#正确的办法应该为
[root@iZ2vc7zktoz7z9fn3qhptjZ dockerfile]# docker run 0ab8341a6e84 ls -al
total 0
drwxr-xr-x 1 root root 6 Oct 21 15:32 .
drwxr-xr-x 1 root root 6 Oct 21 15:32 ..
-rwxr-xr-x 1 root root 0 Oct 21 15:32 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x 5 root root 340 Oct 21 15:32 dev
drwxr-xr-x 1 root root 66 Oct 21 15:32 etc
drwxr-xr-x 2 root root 6 Nov 3 2020 home
测试ENTRYPOINT
[root@iZ2vc7zktoz7z9fn3qhptjZ dockerfile]# vim dockerfile-cmd-entrypoint
FROM centos
ENTRYPOINT ["ls","-a"]
#构建
[root@iZ2vc7zktoz7z9fn3qhptjZ dockerfile]# docker build -f dockerfile-cmd-entrypoint -t entrypoint-test .
Successfully built 7cf9e42fd793
Successfully tagged entrypoint-test:latest
#启动
[root@iZ2vc7zktoz7z9fn3qhptjZ dockerfile]# docker run 7cf9e42fd793
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
#追加命令
[root@iZ2vc7zktoz7z9fn3qhptjZ dockerfile]# docker run 7cf9e42fd793 -l
total 0
drwxr-xr-x 1 root root 6 Oct 21 15:36 .
drwxr-xr-x 1 root root 6 Oct 21 15:36 ..
-rwxr-xr-x 1 root root 0 Oct 21 15:36 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x 5 root root 340 Oct 21 15:36 dev
drwxr-xr-x 1 root root 66 Oct 21 15:36 etc
drwxr-xr-x 2 root root 6 Nov 3 2020 home
lrwxrwxrwx 1 root root 7 Nov 3 2020 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 2020 lib64 -> usr/lib64
drwx------ 2 root root 6 Sep 15 14:17 lost+found
实战:Tomcat镜像
1.准备Tomcat压缩包,jdk的压缩包
2.编写dockerfile文件,官方命名Dockerfile,执行docker build时会自动寻找dockerfile文件不需要-f指定
FROM centos
MAINTAINER ybw<1554094535@qq.com>
COPY readme.txt /usr/local/readme.txt
ADD apache-tomcat-9.0.54.tar.gz /usr/local/
ADD jdk-8u311-linux-x64.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_311
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.54
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.54
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.54/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.54/bin/logs/catalina.out
3.构建镜像
docker build -t diytomcat .
4.运行
docker run -d -p 9090:8080 --name ybwtomcat -v /home/ybw/tomcat/test:/url/local/apache-tomcat-9.0.54/webapps/test -v /home/ybw/tomcat/tomcatlogs/:/url/local/apache-tomcat-9.0.54/logs diytomcat
5.启动镜像
6.访问测试
7.发布项目,做了卷挂载,直接在本地发布
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
</web-app>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>hello,杨博文</title>
</head>
<body>
Hello World!<br/>
<%
System.out.println("---ybw---");
%>
</body>
</html>
项目部署成功
我们以后的开发步骤,需要掌握DockerFile的编写
发布自己的镜像
DockerHub注册自己的账号
1、地址 hub.docker.com注册账号
2、在服务器上提交
#1.查看登录命令
[root@iZ2vc7zktoz7z9fn3qhptjZ tomcatlogs]# docker login --help
Usage: docker login [OPTIONS] [SERVER]
Log in to a Docker registry.
If no server is specified, the default is defined by the daemon.
Options:
-p, --password string Password
--password-stdin Take the password from stdin
-u, --username string Username
#2.登录
[root@iZ2vc7zktoz7z9fn3qhptjZ tomcatlogs]# docker login -u timenever
#给镜像添加标签
docker tag diytomcat ybw/tomcat:1.0
#发布
docker pull
发布到阿里云镜像
1.登录阿里云
2.找到容器镜像服务
3.创建命名空间
4.创建容器镜像
5.游览仓库信息
小结
Docker 网络
理解docker0
1.清空所有环境
测试
三个网络
#docker如何处理网络访问
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker run -d -P --name tomcat01 tomcat
#查看容器内部网络地址 ip addr 发现容器启动时会有eth0@if77 这是docker分配的
#容器容器内部没有ip命令,进入容器执行 apt update && apt install -y iproute2
# 没有ipconfig 执行 apt install net-tools
#没有ping命令 执行 apt install iputils-ping
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker exec -it tomcat01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
76: eth0@if77: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
#思考 Linux能不能ping通容器内部
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.034 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.035 ms
64 bytes from 172.18.0.2: icmp_seq=3 ttl=64 time=0.037 ms
64 bytes from 172.18.0.2: icmp_seq=4 ttl=64 time=0.033 ms
#说明Linux可以ping通容器内部
原理
1.我们每安装一个docker容器,docker就会docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0桥接模式,使用的是evth-pair技术
#在此使用ip addr
#多了一个网卡77
2.再启动一个容器测试,发现又多了一对网卡
#我们发现这个容器的网卡,都是一对对的
#evth-pair 就是一对虚拟设备接口,他们是成对出现的,一段连着协议,一段彼此相连
#正因为有这个特性,evth-pair 充当一个桥梁,连接着各种虚拟设备
#OpenStack,Docker容器之间的连接,OVS的连接,都是使用evth-pair技术
3.我们来测试Tomcat01和Tomcat02能否ping通
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker exec -it tomcat02 ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.061 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.043 ms
64 bytes from 172.18.0.2: icmp_seq=3 ttl=64 time=0.046 ms
#发现容器和容器之间是可以ping通
tomcat01和tomcat02是公用的一个路由器
所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器默认分配ip
小结
Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥 docker0
Docker中所有的网络接口都是虚拟的,虚拟的转发效率高
只要删除容器,对应的一对网桥就没了
思考一个场景,编写一个微服务,database url=ip;项目不重启,数据库ip换掉了,我们希望可以处理这个问题,可以通过名字来进行访问容器
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
#如何解决这个问题
#1.用--link
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
#2.测试
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.18.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.18.0.3): icmp_seq=1 ttl=64 time=0.069 ms
64 bytes from tomcat02 (172.18.0.3): icmp_seq=2 ttl=64 time=0.047 ms
64 bytes from tomcat02 (172.18.0.3): icmp_seq=3 ttl=64 time=0.044 ms
#反向可以ping通吗
其实这个tomcat03就是在本地配置了tomcat02的配置
#查看hosts配置,在这里发现
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.3 tomcat02 0b46548f4648
172.18.0.4 300b08083fdb
本质:–link就是我们在host配置中增加了一个172.18.0.3 tomcat02 0b46548f4648
我们现在用docker已经不建议用–link
我们现在自定义网络
自定义网络
查看所有的docker网络
网络模式
bridge:桥接 docker(默认)
none: 不配置网络
host:和宿主机共享网络
container:容器网络连通(局限大)
测试
#我们直接启动的命令 --net bridge,而这个就是我们的docker0
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat
#docker0的特点 默认:域名不能访问 --link可以打通连接
#我们可以自定义一个网络
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
39029c391c45291274fb21b1dece9b46664b2ad95987804b13fe10db98125039
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
570b70de9ce6 bridge bridge local
76ade01f6e8e host host local
39029c391c45 mynet bridge local
e846891d3b76 none null local
我们自己的网络就创建好了
#进入容器后解决apt update下载速度慢
root@6646172977e6:/usr/local/tomcat# cd /etc/apt
root@6646172977e6:/etc/apt# ls
apt.conf.d auth.conf.d preferences.d sources.list sources.list.d trusted.gpg.d
root@6646172977e6:/etc/apt# echo "">sources.list
root@6646172977e6:/etc/apt# echo "deb http://ftp2.cn.debian.org/debian/ buster main">>sources.list
root@6646172977e6:/etc/apt# echo "deb http://ftp2.cn.debian.org/debian/debian-security buster/updates main">>sources.list
root@6646172977e6:/etc/apt# echo "deb http://ftp2.cn.debian.org/debian/debian buster-updates main">>sources.list
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.028 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.026 ms
64 bytes from 192.168.0.3: icmp_seq=3 ttl=64 time=0.027 ms
#发现ping容器名称可以ping通
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.074 ms
64 bytes from tomcat-net-02.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.054 ms
我么自定义的网络docker都已经帮我们维护好了对应的关系
好处:
redis:不同的集群使用不同的网络,保证集群是安全和健康的
mysql:不同的集群使用不同的网络,保证集群是安全和健康的
网络连通
#尝试将tomcat01和tomcat-net-01连通
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker exec -it tomcat01 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
#失败
#测试 tomcat能否ping通tomcat-net-01
docker network connect mynet tomcat01
#连通之后就是将tomcat01放到了mynet网络下
#一个容器两个ip地址
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.072 ms
64 bytes from tomcat-net-01.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.053 ms
64 bytes from tomcat-net-01.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.055 ms
#tomcat01和tomcat-net-01连通
#tomcat02依旧是打不通的
[root@iZ2vc7zktoz7z9fn3qhptjZ ~]# docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
结论:假设要跨网操作别人,就需要使用docker network connect连通
实战:部署redis集群
#创建网卡
docker network create redis --subnet 172.38.0.0/16
#通过脚本创建6个Redis配置
redis集群
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/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 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
运行部分
for port in $(seq 1 6); \
do
docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf; \
done
#创建集群
[root@iZ2vc7zktoz7z9fn3qhptjZ conf]# docker exec -it redis-1 /bin/sh
/data # ls
appendonly.aof nodes.conf
/data # redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.
38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: 3d08d4a1b1a69e6541f94748cf58f0e3d406c7f5 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
M: 4409cb51675fd8cfc259b083991d40225329747f 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
M: f0bf7d6fce8e15091e4de77d2e3c0fc28db6c4d5 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
S: eca5b549a77c15e0274f2472600bfbf05dc00b82 172.38.0.14:6379
replicates f0bf7d6fce8e15091e4de77d2e3c0fc28db6c4d5
S: 92d808d95466384e4dc5f26d2b50f77f0207e887 172.38.0.15:6379
replicates 3d08d4a1b1a69e6541f94748cf58f0e3d406c7f5
S: 6856d04ed4b0b2ef5257ff3f9638518089eb1133 172.38.0.16:6379
replicates 4409cb51675fd8cfc259b083991d40225329747f
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
..
>>> Performing Cluster Check (using node 172.38.0.11:6379)
M: 3d08d4a1b1a69e6541f94748cf58f0e3d406c7f5 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 92d808d95466384e4dc5f26d2b50f77f0207e887 172.38.0.15:6379
slots: (0 slots) slave
replicates 3d08d4a1b1a69e6541f94748cf58f0e3d406c7f5
S: 6856d04ed4b0b2ef5257ff3f9638518089eb1133 172.38.0.16:6379
slots: (0 slots) slave
replicates 4409cb51675fd8cfc259b083991d40225329747f
M: f0bf7d6fce8e15091e4de77d2e3c0fc28db6c4d5 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: 4409cb51675fd8cfc259b083991d40225329747f 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: eca5b549a77c15e0274f2472600bfbf05dc00b82 172.38.0.14:6379
slots: (0 slots) slave
replicates f0bf7d6fce8e15091e4de77d2e3c0fc28db6c4d5
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
#测试
/data # redis-cli -c
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:186
cluster_stats_messages_pong_sent:199
cluster_stats_messages_sent:385
cluster_stats_messages_ping_received:194
cluster_stats_messages_pong_received:186
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:385
127.0.0.1:6379> cluster nodes
92d808d95466384e4dc5f26d2b50f77f0207e887 172.38.0.15:6379@16379 slave 3d08d4a1b1a69e6541f94748cf58f0e3d406c7f5 0 1635347376000 5 connected
6856d04ed4b0b2ef5257ff3f9638518089eb1133 172.38.0.16:6379@16379 slave 4409cb51675fd8cfc259b083991d40225329747f 0 1635347377502 6 connected
f0bf7d6fce8e15091e4de77d2e3c0fc28db6c4d5 172.38.0.13:6379@16379 master - 0 1635347376501 3 connected 10923-16383
4409cb51675fd8cfc259b083991d40225329747f 172.38.0.12:6379@16379 master - 0 1635347376501 2 connected 5461-10922
3d08d4a1b1a69e6541f94748cf58f0e3d406c7f5 172.38.0.11:6379@16379 myself,master - 0 1635347375000 1 connected 0-5460
eca5b549a77c15e0274f2472600bfbf05dc00b82 172.38.0.14:6379@16379 slave f0bf7d6fce8e15091e4de77d2e3c0fc28db6c4d5 0 1635347377002 4 connected
127.0.0.1:6379> set a b
-> Redirected to slot [15495] located at 172.38.0.13:6379
OK
172.38.0.13:6379> get a
Could not connect to Redis at 172.38.0.13:6379: Host is unreachable
(18.18s)
not connected>
/data # redis-cli -c
127.0.0.1:6379> get a
-> Redirected to slot [15495] located at 172.38.0.14:6379
"b"
172.38.0.14:6379> cluster nodes
92d808d95466384e4dc5f26d2b50f77f0207e887 172.38.0.15:6379@16379 slave 3d08d4a1b1a69e6541f94748cf58f0e3d406c7f5 0 1635347593557 1 connected
f0bf7d6fce8e15091e4de77d2e3c0fc28db6c4d5 172.38.0.13:6379@16379 master,fail - 1635347462939 1635347462000 3 connected
3d08d4a1b1a69e6541f94748cf58f0e3d406c7f5 172.38.0.11:6379@16379 master - 0 1635347594560 1 connected 0-5460
6856d04ed4b0b2ef5257ff3f9638518089eb1133 172.38.0.16:6379@16379 slave 4409cb51675fd8cfc259b083991d40225329747f 0 1635347593958 6 connected
4409cb51675fd8cfc259b083991d40225329747f 172.38.0.12:6379@16379 master - 0 1635347593057 2 connected 5461-10922
eca5b549a77c15e0274f2472600bfbf05dc00b82 172.38.0.14:6379@16379 myself,master - 0 1635347594000 7 connected 10923-16383
SpringBoot微服务打包Docker镜像
1.构建springboot项目
2.打包应用
3.编写dockerfile
4.构建镜像
5.发布运行
Docker进阶
Docker Compose
Docker Compose轻松高效管理容器
官方介绍
定义运行多个容器
YAML file配置文件
Using Compose is basically a three-step process:
- Define your app’s environment with a
Dockerfile
so it can be reproduced anywhere. - Define the services that make up your app in
docker-compose.yml
so they can be run together in an isolated environment. - Run
docker compose up
and the Docker compose command starts and runs your entire app. You can alternatively rundocker-compose up
using the docker-compose binary.
version: "3.9" # optional since v1.27.0
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
compose重要概念
- 服务service,容器,应用(Redis,mysql)
- 项目project 一组关联的容器
安装
1.下载
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
#或者
curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
2.授权
chmod +x /usr/local/bin/docker-compose
#查看是否安装成功
[root@ybw bin]# docker-compose version
docker-compose version 1.25.5, build 8a1c60f6
docker-py version: 4.1.0
CPython version: 3.7.5
OpenSSL version: OpenSSL 1.1.0l 10 Sep 2019
3.体验
[root@ybw bin]# docker-compose version
docker-compose version 1.25.5, build 8a1c60f6
docker-py version: 4.1.0
CPython version: 3.7.5
OpenSSL version: OpenSSL 1.1.0l 10 Sep 2019
1.应用app.py
2.Dockerfile 应用打包为镜像
3.Docker-compose.yaml(定义整个服务需要的环境 web redis)
4.启动docker-compose(docker-compose up)
流程
1.创建网络
2.执行docker-compose.yaml
3.启动服务
[root@ybw composetest]# docker-compose up
Starting composetest_web_1 ...
Starting composetest_web_1 ... done
#步骤
1.创建项目文件夹
mkdir composetest
cd composetest
#2创建app.py文件
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
if __name__ == "__main__":
app.run(host="0.0.0.0",debug=True)
#3创建requirements.txt
flask
redis
#4创建Dockerfile
FROM python:3.6-alpine
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
#4创建docker-compose.yml文件
version: "3.8"
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
redis:
image: "redis:alpine"
#5使用docker-compose up 启动
默认的服务名 :文件名_______服务名____num
网络规则
以前都是单个docker run 启动容器
docker-compose,通过编写yml文件,一次启动或停止多个容器
yaml规则
#docker-compose.yml
#3层
version:'3.8'
service:
服务1:web
#服务配置
images
build
服务2:redis
#服务配置
服务3:
#第3层 其它配置
volumes:
network:
实战
docker-compose up --build #重新构建
Docker Swarm
1.生成主节点 docker swarm init
2.加入
十分简单:集群,可用!3个主节点
Raft协议
双主双从:假设一个节点挂了,其它节点是否可用
Raft协议:保证绝大多数节点存活才可用,只要>1,