生成自己的镜像
镜像就是将自己定制化后的系统封装,方便下次使用
例如:曾经的Ghost系统虚拟机的快照
前期准备:
1.下载官方tomcat镜像
2.运行镜像后将webapp目录里新增文件(官方镜像是没有页面的 具体操作见)
3.使用docker ps -a 查看刚刚修改后的容器id
4.执行下面操作
docker commit -a="rb2010" -m="my tomcat image" 6bcebdb36a1c my_tomcat_images
# 提交人 提交信息 要提交的容器id 生成新镜像的名字 不写版本默认是latest,指定版本可写成 my_tomcat_images:1.0
5.执行docker images 查看,可以看到上一步创建的镜像
6.启动新的镜像,访问http://192.168.1.232:83/发现可以正常显示页面,证明这个镜像已经封装好了
docker run --name mytomcatimages -d -p 83:8080 my_tomcat_images
7.通过以下命令查看刚制作的镜像记录
docker history my_tomcat_images:latest
数据卷|数据挂载
多个容器共享的数据,可将容器内指定的路径映射到容器外指定路径,在容器外路径进行文件操作后,容器内相应路径下会变。例如数据库的数据文件,要挂在出来,避免误删容器数据丢失和多容器间数据共享。
1.在服务器中创建一个目录,用于存放容器内的文件
mkdir tomcat_data
# tomcat_data路径为:/usr/local/tomcat_data/webapps
2.将上一篇转移的webapps中的文件夹内容复制到上一步创建的tomcat_data文件夹下(webapps转移操作见 具体操作;将容器内文件复制到容器外具体操作)
docker cp tomcat:/usr/local/tomcat/webapps /usr/local/tomcat_data
#这一步操作需要先将上面自己打包好的镜像运行起来,当然,直接用官方tomcat也行,只不过要去webapps.dist中复制
3.重新运行一个官方tomcat镜像(官方镜像webapps下是空的)
docker run --name tomcat -v /usr/local/tomcat_data/webapps:/usr/local/tomcat/webapps -p 80:8080 -d tomcat
# -v数据挂载 容器外挂载路径:容器内挂载路径
4.进入容器查看webapps下,发现有文件了;并且在容器外/usr/local/tomcat/webapps这个路径下创建修改文件,容器内会同步更新
5.可通过命令查看挂载的情况
docker inspect tomcat
# 容器名字
6.挂载后将容器内挂载目录设置为只读
docker run --name tomcat -v /usr/local/tomcat_data/webapps:/usr/local/tomcat/webapps:ro -p 80:8080 -d tomcat
# ↑↑↑
#ro:readonly
#rw:readwrite (默认)
7.具名&匿名挂载
这两种挂载方式是不指定挂载到外部服务器具体位置,使用docker默认的挂载位置
匿名挂载
-
执行命令
docker run --name tomcat -v /usr/local/tomcat/webapps -d tomcat
-
查看挂载详情
docker inspect tomcat
-
进入外部挂载路径,创建一个文件,在容器内查看,发现可以看到刚刚创建的文件
具名挂载
名字太长了,来一个自定义名字的
-
执行命令
docker run --name tomcat -v tomcatdata:/usr/local/tomcat/webapps -d tomcat # 起的名字 #这块注意:起的名字前面不可以有/,否则会当作外部挂载路径 例:tomcatdata 挂载名字 ;/tomcatdata 外部挂载路径
-
可通过上面docker inspect 命令查看具体存放位置,也可通过下面命令查看
docker volumes list #查看所有匿名、具名挂载信息
-
可以看到了第一步起名字的挂载卷,再通过下面命令查看具体存放的位置
docker volume inspect tomcatdata
8.多个容器共享同一个数据卷
-
启动新的容器tomcat01
基于上面复制出来的 /usr/local/tomcat_data/webapps 路径,启动了一个容器 tomcat01,并且挂载/usr/local/tomcat_data/webapps这个路径
-
再启动一个容器tomcat02
docker run --name tomcat02 --volumes-from tomcat01 -d tomcat # 挂载 容器tomcat01的数据卷
-
这样,就完成了数据卷共享
DockerFile
这个就是自己制作镜像的一个东西,通常在工作中会使用它生成带项目的镜像上传到云端,运维拉取后进行发布
1.DockerFile 内容如下:
FROM centos
#使用哪个基础镜像进行定义
MAINTAINER rb2010<476852847@qq.com>
#指定镜像制作人信息
ENV MYPATH /usr/local
#设置一个环境变量
WORKDIR $MYPATH
#设置镜像运行后到哪个路径下
#为原装镜像安装一些工具start
RUN yum -y install vim
RUN yum -y install net-tools
#为原装镜像安装一些工具end
#创建两个文件夹start
RUN mkdir /usr/local/test01
RUN mkdir /usr/local/test02
#创建两个文件夹start
#匿名挂载start
#VOLUME ["/usr/local/test01","/usr/local/test02"]
#匿名挂载end
#挂载只可以匿名挂载
#将dockerfile同级目录下jdk和tomcat解压至指定目录start
ADD jdk-8u251-linux-x64.tar.gz /usr/local
ADD apache-tomcat-9.0.36.tar.gz /usr/local
#将dockerfile同级目录下jdk和tomcat解压至指定目录end
#配置解压的jdk omcat环境变量start
ENV JAVA_HOME /usr/local/jdk1.8.0_251
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.36
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.36
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#配置解压的jdk omcat环境变量end
#创建文件夹temp,将dockerfile同级目录下文件复制到镜像指定路径start
RUN mkdir /usr/local/temp
COPY a.txt /usr/local/temp
#创建文件夹,将dockerfile同级目录下文件复制到镜像指定路径end
EXPOSE 8080
#对外暴漏端口,但只是定义暴漏,并未真正暴露,还需通过手动指定-p 或 随机暴漏-P 进行暴漏
#CMD /bin/bash
#最后这句CMD代表在run这个镜像的时候,会默认执行一个bash命令,可以换成其他的命令
#有这个命令在docker run --name meiyou -d -it myimages 时候就不用在最后加bash参数,否则就要加
#启动时运行tomcat
#CMD /usr/local/apache-tomcat-9.0.36/bin/startup.sh
#和CMD语义相近的还有ENTRYPOINT这个命令,区别在于cmd指定的命令,在run启动命令的最后如果添加命令必须添加完整的命令,不能和dockerfile中命令相接使用,而ENTRYPOINT会在dockerfile指定命令后追加。可以理解为CMD是String a="str1"; a="str2"; ENTRYPOINT是 StringBuffer 的append()
#ENTRYPOINT ["ls","-a"]
感觉上面说的CMD和ENTRYPOINT还是不够清晰,再整理下:
dockerfile中写CMD ["ls","-a"] ,在启动的时候如果添加命令必须这样添加 docker run --name cmd -it cmd ls -a -Z 不会和dockerfile中CMD命令追加
dockerfile中写ENTRYPOINT["ls","-a"],在启动的时候如果添加命令就可以这样添加 docker run --name cmd -it cmd -Z 会和dockerfile中命令追加为 ls -a -Z
2.根据dockerfile创建镜像
docker build -t img_name . #dockerfile文件名为“DockerFile”时,可通过这个命令创建
# 创建镜像名字 可写成img_name:1.0,不带版本号默认是latest
docker build -f dockerfile -t img_name . #dockerfile文件名不为“DockerFile”时,必须通过这个命令
# 指定dockerfile文件名
Docker网络
容器相当于独立的一个系统、环境,但是它们之间却可以Ping通,研究后发现是这样的原理
1.多个容器为什么能PING通?
-
Docker0
当安装完docker后,执行ifconfig可以发现多了一个docker0网卡(没有安装ifconfig的可以使用ip addr查询)
可以把这个网卡当作家中的路由器(我家小只有一个路由器,如果家中安了很多个路由器,那就是宽带光猫出来的网线接入的第一个路由器)
-
新增网卡
当每RUN一个镜像时,都会在服务器上创建一个网卡
例如,运行一个tomcat容器,使用ip addr查看,会多一个
再运行一个tomcat容器,又会多一个
可以看到多出来的两个网卡 ,每个网卡分别有一组编号,345、344,docker0网卡就是通过这组数字进行关联,这个官方叫做veth-pair技术
345: veth6fef756@if344
349: veth41d4fe9@if348
(如果容器是连续运行的,这个编号都是连续的)
图示:
-
再次理解
第二步新增的两个网卡都是docker0网卡下发的,可以理解为家里有两台电脑连接到家中路由器,两台电脑互ping由路由器(docker0)协调沟通
2.自定义网络
上面了解到,多容器互通只能使用ping ip的方式,如果容器ip变了,那就麻烦了,例如:A容器调用B容器的服务,将ip写死了,如果B容器ip改了,那还要修改A容器项目,如果能ping容器的名字那最好了,所以出现了下面两种方式:
link方式,这个方式可以ping本质是修改了主机的hosts,但是这个方法不够灵活,不推荐使用;
自定义网络,推荐使用这个,下面也是针对这个来梳理步骤。
- 创建自定义网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.1.1 rbnet
# 选择模式,默认是bridge 设置最多可用ip数,上面这个大约是6W多个 设置网关 自定义网卡名字
- driver类型
-
查看刚刚创建的网络
docker network ls
-
使用刚创建的网卡
docker run --name tomcat01 --network rbnet -d tomcat:8.5 # 指定网卡 docker run --name tomcat02 --network rbnet -d tomcat:8.5
-
查看下运行的容器,看看是否使用了自定义的网卡
docker inspect tomcat01
-
进入启动的tomcat01 02 容器,发现可以不仅可以使用ip ping 也可以使用容器名字进行Ping了
3.多个网卡如何互通
如果有两块自定义网卡,每块网卡分别启动了两个tomcat,默认情况见下图
解决方式:
目的:让tomcat2和ping同网卡B下所有容器互通, (就是tomcat2可ping通tomcat3和tomcat4,tomcat3和tomcat4也可ping通tomcat2)
-
首先先创建一个非网卡B的容器
-
执行命令
docker network connect rbnet tomcat2
# 连接 网卡B名字 要与网卡B互通的网卡A容器名字
- 执行后就可以进行互ping了
注意:如果网卡A的tomcat1也要和网卡B下所有容器互通,也要执行第二步命令
练习1:搭建redis集群
搭建基于cluster模式的集群,之前没用docker搭建过,详情见:Redis集群-Cluster模式
1.创建网卡
docker network create redis_net --subnet 192.166.0.1/16
2.创建六个redis配置文件(以下配置文件直接在命令行输入即可,注意一定要删除#注释后执行)
用于启动六个redis
for port in $(seq 1 6);
do
mkdir -p /usr/local/redis_conf/node-${port}/conf
#创建1-6个redis节点文件夹
touch /usr/local/redis_conf/node-${port}/conf/redis.conf
#创建1-6个redis配置文件
cat << EOF >/usr/local/redis_conf/node-${port}/conf/redis.conf
#修改配置文件start
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 192.166.0.1${port} #注意,这步设置的ip就是上面创建网卡的ip段,不一致会导致集群分配失败
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
#修改配置文件end
EOF
done
3.使用配置文件启动六个redis
for port in $(seq 1 6);
#docker 依次运行1-6个redis
do
docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port}
# 对外暴漏连接端口 集群通信端口 每个redis容器起名字
-v /usr/local/redis_conf/node-${port}/data:/data
#将redis数据挂载至外部
-v /usr/local/redis_conf/node-${port}/conf/redis.conf:/etc/redis/redis.conf
#将上一步创建的六个配置文件依次挂载
-d --net redis_net --ip 192.166.0.1${port} redis:5.0 redis-server /etc/redis/redis.conf;
#后台运行 ,指定使用第一步创建的网卡 指定容器ip 启动redis镜像 执行redis启动命令 #使用每个容器中挂载的配置文件启动
done
4.查看运行情况
docker ps
5.搭建Cluster集群
redis-cli --cluster create 192.166.0.11:6379 192.166.0.12:6379 192.166.0.13:6379 192.166.0.14:6379 192.166.0.15:6379 192.166.0.16:6379 --cluster-replicas 1
6.登录一台redis,查看集群是否搭建成功
redis-cli -c -p6379
#登录redis(登录前提是先进入容器)
cluster info
#查看集群状态
练习2:Kibana使用容器名方式连接ES
1.创建网卡
docker network create es_net --subnet 192.111.0.1/16
2.运行es
es+kibana怎么安装见此处
docker run --name es -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" --net es_net elasticsearch:7.7.1
#注意,这我指定了第一步创建的网卡 --net es_net
3.验证下es是否启动成功
浏览器访问 192.168.1.232:9200(别的ip自己更换)
4.运行kibana
-
先写个kibana配置文件
因为我下面启动的时候对配置文件进行挂载了,所以我要修改这个文件(外部目录是这个/usr/local/kibana_conf/kibana.yml)
server.name: kibana server.host: "0" elasticsearch.hosts: ["http://es:9200"] #现在指定的是上面es的容器名字 #elasticsearch.hosts: ["http://192.168.1.232:9200"] 原来是直接指定的容器ip xpack.monitoring.ui.container.elasticsearch.enabled: true
-
运行kibana
docker run --name kibana01 -d -p 5601:5601 -v /usr/local/kibana_conf/kibana.yml:/usr/share/kibana/config/kibana.yml --net es_net kibana:7.7.1
#注意,这我指定了第一步创建的网卡 --net es_net
5.验证kibana是否启动成功
浏览器访问验证 http://192.168.1.232:5601
6.再次验证,是不是通过容器名字连接的
把/usr/local/kibana_conf/kibana.yml文件中
elasticsearch.hosts: ["http://es:9200"] 这个属性
改为
elasticsearch.hosts: ["http://es123123:9200"]
重启kibana容器,后再次访问192.168.1.5601,发现访问不了了,证明,可通过容器名进行连接,这样就不会出现es容器ip变了,还要修改kibana配置的情况了
练习3:项目的jar包,如何运行
利用dockerfile,可以非常快速的生成一个可运行的镜像,将生成好的镜像给到运维,直接就可以运行了,无需再配置各种运行环境(例如安装jdk。。。)
1.创建一个springboot项目
这个项目只改动两处
-
添加一个html文件
-
修改启动端口
2.打包
将上面的项目打成jar包,放到服务器上dockerfile同级文件夹
3.编写Dockerfile文件
将下面的文件放到上一步jar包同级目录
FROM java:8
# 使用 java8的环境,这里镜像已经配置好了jdk等环境
COPY *.jar /demo.jar
#将dockerfile(就是这个文件)同级目录的所有jar包复制到容器根目录一份,*可以换成具体的jar包名,我这就一个jar包
# 指定容器内要暴露的端口
EXPOSE 8080
ENTRYPOINT ["java","-jar","/demo.jar"]
4.运行镜像
执行下面的命令后就可以看到启动日志了
docker run --name demo -it -p 8080:8080 demo
# 将上一步暴漏的8080对外暴漏
5.测试
访问连接,发现a.html的页面可正常访问
镜像提交上传
DockerHub卡,所以使用阿里云的
1.注册阿里云
登录后创建镜像仓库
2.进入创建的镜像
里面会展示非常详细的操作步骤
大致步骤如下:
-
登录
docker login --username=476852847@qq.com registry.cn-hangzhou.aliyuncs.com
-
给已经创建好的镜像打一个tag
docker tag demo registry.cn-hangzhou.aliyuncs.com/rb2010/rb2010:1.0 # 要上传的镜像id或名字 阿里云提供的地址 最后的:1.0如果不写,默认是lastest
-
push打好标记的镜像
docker push registry.cn-hangzhou.aliyuncs.com/rb2010/rb2010:latest
-
等待上传完毕后,去阿里云看看是否有镜像