php做网站最容易,用dw做网站的基本步骤,网站域名后缀那个好,Wordpress手机端模版一、dockerfile解析 
官方文档#xff1a; Dockerfile reference | Docker Docs 1.1、dockfile是什么#xff1f; 
dockerfile是用来构建docker镜像的文本文件#xff0c;由一条条构建镜像所需的指令和参数构成的脚本。 之前我们介绍过通过具体容器反射构建镜像(docker comm… 
一、dockerfile解析 
官方文档 Dockerfile reference | Docker Docs 1.1、dockfile是什么 
dockerfile是用来构建docker镜像的文本文件由一条条构建镜像所需的指令和参数构成的脚本。 之前我们介绍过通过具体容器反射构建镜像(docker commit)的方法这里就是第二种直接构建镜像的方法。 
构建三部曲 (1)编写Dockerfile文件 (2)docker build命令构建镜像 (3)docker run镜像运行容器实例 1.2、dockerfile构建过程 
1.2.1、 dockerfile基础知识 
(1)每条保留字指令都必须为大写字母且后面要跟随至少一个参数 (2)指令按照从上到下顺序执行 (3)#表示注释 (4)每条指令都会创建一个新的镜像层并对镜像进行提交 
注官网上的诸如ADD/CMD/COPY/FROM等关键字也称保留字。 
1.2.2、docker执行dockerfile的大致流程 
(1)docker从基础镜像运行一个容器; (2)执行一条指令并对容器作出修改; (3)执行类似docker commit的操作提交一个新的镜像层; (4)docker在基于刚提交的镜像运行一个新容器; (5)执行dockerfile中的下一条指令直到所有指令都执行完成; 1.2.3、小总结 
从应用软件的角度来看Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段 
Dockerfile是软件的原材料Docker镜像是软件的交付品Docker容器则可以认为是软件镜像的运行态也即依照镜像运行的容器实例 
Dockerfile面向开发Docker镜像成为交付标准Docker容器则涉及部署与运维三者缺一不可合力充当Docker体系的基石。 Dockerfile需要定义一个DockerfileDockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道这时需要考虑如何设计namespace的权限控制)等等;Docker镜像在用Dockerfile定义一个文件之后docker build时会产生一个Docker镜像当运行 Docker镜像时会真正开始提供服务;Docker容器容器是直接提供服务的。 1.3、dockerfile常用保留字指令 
1.3.1、dockerfile直观认识 
hub.docker.com 搜tomcat(随便搜啥都行)。都会有个Dockerfile links我们打开就可以看到其对应的dockerfile。 
1.3.2、dockerfile常用指令 
FROM: 
基础镜像。即当前新镜像是基于哪个镜像指定一个已经存在的镜像作为模板一般第一条必须是from。 
MAINTAINER: 
镜像维护者的姓名和邮箱地址。 
RUN: 
RUN是在容器构建(docker build)时需要运行的命令。有两种格式: (1)shell RUN 命令行命令 # 命令行命令等同于在终端操作的shell命令。 #举个例子:我需要在build的时候安装一个vim就可以按如下写: RUN yum -y install vim 
(2)exec RUN [可执行文件, 参数1, 参数2] #例如: RUN [./test.php, dev, offline]等价于 ./test.php dev offline 
注:感觉比价鸡肋用shell的方式其实就好了。 
EXPOSE  
指定当前容器对外暴露的端口。 
EXPOSE 80/tcp
EXPOSE 80/udp 
WORDIR 
指定在创建容器后终端默认登陆进来的工作目录(就是登陆容器的默认落脚路径)。 
USER 
指定该镜像以什么样的用户去执行如果都不指定默认就是root用户。 ENV 
用来在构建镜像过程中设置环境变量。就理解为定义了一个变量名(key)。 #举个例子就是定义了一个环境变量MY_HOME并使用。 ENV MY_HOME /usr/local/tomcat  WORKDIR $MY_HOME ADD 
将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包。相当于 COPY解压 COPY 
将宿主机目录下的文件拷贝进镜像(不解压)。显然用ADD更好。 
VOLUME 
容器数据卷用于数据保存和持久化。其实就是和 -v 选项平齐。 
CMD 
作用:指定容器启动后要干的事情。 
CMD指令的格式和 RUN 相似也是两种格式: (1)shell格式 CMD 命令 (2)exec格式: CMD[可执行文件, 参数1, 参数2 ……] 注意: Dockerfile中可以有多个CMD指令但只有最后一个生效; 另外CMD会被docker run之后的参数替换。啥意思呢这里解释一下。对于 tomcat 的dockerfile的最后两句如下 EXPOSE 8080    #暴露8080端口CMD [catalina.sh, run]   #执行tomcat的启动脚本catalina.sh 如果docker run不加参数的启动。 docker run -it -p 8080:8080 镜像id 就是按照dockerfile来执行。但是如果变成了 docker run -it -p 8080:8080 镜像id /bin/bash那么上述的 CMD [catalina.sh, run] 就会失效。         实际执行的效果变成了 CMD [/bin/bash, run]; 此时容器确实是启动了,但是tomcat本身确没有正常启动显然也不通。 
注和前面的RUN命令的区别。 CMD是在docker run时运行RUN是在docker build时运行。 
ENTRYPOINT 
作用: 也是用来指定一个容器启动时要运行的命令。 类似于CMD指令但是 ENTRYPOINT 不会被docker run后面的命令覆盖;而且这些命令行参数会被当做参数送给ENTRYPOINT指令指定的程序。 
#命令格式
ENTRYPOINT [executeable, param1, param2,……] 
ENTRYPOINT可以和CMD一起用一般是变参才会使用CMD这里的CMD等于是在给ENTRYPOINT传参。当指定ENTRYPOINT后CMD的含义就发生了变化不再是直接运行其明星而是将CMD的内容作为参数传递给ENTRYPOINT指令他两个组合会变成 ENTRYPOINT CMD 
看个具体的案例。假设已经通过Dockerfile构建了 nginx:test 镜像: FROM nginx ENTRYPOINT [nginx, -c] #定参 CMD [/etc/nginx/nginx.conf] #变参 如果执行 
docker run nginx:test  则容器启动后会执行 nginx -c /etc/nginx/nginx.conf 
docker run nginx:test /app/nginx/new.conf  则容器启动后会执行 nginx -c /app/nginx/new.conf 1.3、实际案例 
1.3.1、自定义镜像mycentosjava8 
目标docker原始的centos不具备vim、ifconfig、java等功能现在要做的事情就是在原有centos镜像的基础上构建出具有这些功能的镜像。 
(0)前期准备 #建立一个工作目录 mkdir myfile   
下载jdk8的tar包放在此目录 jdk-8u171-linux-x64.tar.gz 
(1)编写Dockerfile文件 
注文件名必须是 Dockerfile。 
创建 Dockerfile 文件,并粘贴如下内容。 
FROM centos
MAINTAINER zszs126.comENV MYPATH /usr/local
WORKDIR $MYPATH#必须要添加这一坨,否则会报错
#参照https://blog.csdn.net/weixin_51689532/article/details/127533832
RUN cd /etc/yum.repos.d/
RUN sed -i s/mirrorlist/#mirrorlist/g /etc/yum.repos.d/CentOS-*
RUN sed -i s|#baseurlhttp://mirror.centos.org|baseurlhttp://vault.centos.org|g /etc/yum.repos.d/CentOS-*
RUN yum update -y#安装vim编辑器
RUN yum -y install vim
#安装ifconfig命令查看网络IP
RUN yum -y install net-tools
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
#ADD 是相对路径jar,把jdk-8u171-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATHEXPOSE 80CMD echo $MYPATH
CMD echo success--------------ok
CMD /bin/bash 
(2)构建镜像 
#格式如下
docker build -t 新镜像名字:TAG .#具体执行指令如下
docker build -t centosjava8:1.5 .注完整的执行过程有点久主要是yum update -y花了很多时间。 
执行完毕后我们就可以通过 docker images查看到生成的镜像了。  
(3)运行镜像 
docker run -it centosjava8:1.5 
(4)验证确实含有java/vim/ifconfig命令 
java -version 
1.3.2、虚悬镜像 
虚悬镜像仓库名、标签名都是none的镜像称为dangling images(虚悬镜像)。 一般都是在镜像构建或删除出错导致出现虚悬镜像这种镜像占用资源但是是没有意义的要予以删除。 
1构建一个虚悬镜像。 创建包含如下内容的 Dockerfile并构建。 from ubuntu CMD echo action is success #构建
docker build . 
(2)列出docker中的虚悬镜像 
docker image ls -f danglingtrue 
(3)删除虚悬镜像: 
docker image prune 1.3.3、自定义镜像myubuntu 二、docker微服务实战 2.1、java微服务的玩法 (0)编写java源码并构建jar包 
得到 docker_boot-1.0-SNAPSHOT.jar  java的玩法不做介绍。 
(1)编写Dockerfile 
FROM openjdk:8-oracle
MAINTAINER lee# 在主机 /var/lib/docker目录下创建一个临时文件并链接到容器的 /tmp
VOLUME /tmp# 将jar包添加到容器中并命名为 springboot_docker.jar
ADD docker_boot-1.0-SNAPSHOT.jar /springboot_docker.jar
# 运行jar包
RUN bash -c touch /springboot_docker.jar
ENTRYPOINT [java, -jar, /springboot_docker.jar]# SpringBoot项目配置的端口号为6001需要将6001暴露出去
EXPOSE 6001 
2构建镜像 
docker build -t springboot_docker:1.0 . 
3启动容器 
docker run -d -p 6001:6001 --name springboot springboot_docker:1.0 2.2、mongo_proxy打镜像 
注mongo_proxy为作者本人实现的一个访问mongodb存储的trpcgo服务读者看看流程就好。 
此处要实现的效果是将mongo_proxy服务打成一个镜像并部署实例化的容器此外还会在宿主器上启动一个mongodb的容器。期望的效果就是外界工具脚本通过访问mongo_proxy暴露的接口实现mongodb数据的增删改查。 
2.2.1、mongodb容器 
1启动mongodb容器 
docker run -d -p 27017:27017 --namezsmongodb \-e MONGO_INITDB_ROOT_USERNAMEroot \-e MONGO_INITDB_ROOT_PASSWORD123456 \mongo:4.0 2连接mongodb并插入一条测试数据 
docker exec -it zsmongodb /bin/bashmongo --host 127.0.0.1 -u root -p 123456use db_call_trackdb.coll_1.save({_id : ObjectId(64af6d368350f30cc6fb1fbb),ext1 : {\callid\:\7085095277245292544\,\has_third_call\:0,\legid\:\70850952772452925441\}\n,ext2 : ,key : call_2885715001_8615731633538,kfext : 3007552478,kfuin : 2885715001,status : 0,call_source : 5,display_type : 3,ext3 : ,phonenumer : 8615731633538,time : 1689218355954380,direction : 2,duration : 0
}) 
3查看mongodb容器分配的ip(记录下来为172.17.0.2) 
docker inspect 3454673b0961 | tail -n 25  
2.2.2、mongo_proxy服务镜像制作部署 —— 写死ip访问 
1准备物料 
新建mongo_proxy目录,将mongo_proxy_svr.tar.gz、trpc_go.yaml、start.sh三个文件复制进来。 start.sh 内容如下 
#!/bin/shcd /data/app/bin
chmod x mongo_proxy_svr
./mongo_proxy_svr -conf ../conf/trpc_go.yaml  /data/app/log/stdout.log 21 
trpc_go.yaml 如下其中基于原服务修改了 (1)bid10对应的配置如下(其中172.17.0.2是mongodb镜像被分配的ip)     - name: trpc.mongodb.online.instance9       target: mongodb://root:123456172.17.0.2:27017/?readPreferencesecondaryPreferred       timeout: 3000      (2)把最下面的metrix相关配置删掉 global:                             #全局配置namespace: Development            #环境类型分正式production和非正式development两种类型env_name: test                    #环境名称非正式环境下多环境的名称server:                                            #服务端配置app: test                                        #业务的应用名server: TimelineProxyService                             #进程服务名bin_path: /usr/local/trpc/bin/                   #二进制可执行文件和框架配置文件所在路径conf_path: /usr/local/trpc/conf/                 #业务配置文件所在路径data_path: /usr/local/trpc/data/                 #业务数据文件所在路径filter:                                          #针对所有service处理函数前后的拦截器列表- simpledebuglog- recovery                                     #拦截框架创建的业务处理协程panicservice:                                         #业务服务提供的service可以有多个- name: inner.track.timeline.TimelineProxyService            #service的路由名称#ip: 127.0.0.1                            #服务监听ip地址 可使用占位符 ${ip},ip和nic二选一优先ipnic: eth0port: 21187                #服务监听端口 可使用占位符 ${port}network: udp                             #网络监听类型  tcp udpprotocol: inner               #应用层协议 trpc httptimeout: 1000                            #请求最长处理时间 单位 毫秒- name: trpc.track.timeline.TimelineProxyService      #service的路由名称#ip: 127.0.0.1                            #服务监听ip地址 可使用占位符 ${ip},ip和nic二选一优先ipnic: eth0port: 21187                #服务监听端口 可使用占位符 ${port}network: tcp                             #网络监听类型  tcp udpprotocol: inner               #应用层协议 trpc httptimeout: 1000                            #请求最长处理时间 单位 毫秒#client:                                            #客户端调用的后端配置
#  timeout: 1000                                    #针对所有后端的请求最长处理时间
#  namespace: Development                           #针对所有后端的环境
#  filter:                                          #针对所有后端调用函数前后的拦截器列表
#  service:                                         #针对单个后端的配置
#    - name: trpc.track.timeline.TimelineProxyService      #后端服务的service name
#      namespace: Development                   #后端服务的环境
#      network: tcp                             #后端服务的网络类型 tcp udp 配置优先
#      protocol: trpc               #应用层协议 trpc http
#      target: ip://127.0.0.1:8000              #请求服务地址
#      timeout: 1000                            #请求最长处理时间#yaml文件格式必须正确;如同统一加一行空格之中都是不行的
client:                                         service:                                        - name: trpc.mongodb.online.instance8       #对应bid9,验证访问容器名是否oktarget: mongodb://root:123456zsmongodb:27017/?readPreferencesecondaryPreferredtimeout: 3000                                      - name: trpc.mongodb.online.instance9       #对应bid10,验证访问分配ip是否oktarget: mongodb://root:123456172.17.0.2:27017/?readPreferencesecondaryPreferredtimeout: 3000                                  - name: trpc.mongodb.online.instance10      #对应bid11,验证访问本机是否oktarget: mongodb://root:123456127.0.0.1:27017/?readPreferencesecondaryPreferredtimeout: 3000                                     - name: trpc.track.timeline.TimelineProxyService    #后端服务的service namenamespace: Development                   #后端服务的环境network: tcp                             #后端服务的网络类型 tcp udp 配置优先protocol: trpc                           #应用层协议 trpc httptarget: ip://9.134.50.94:8000              #请求服务地址timeout: 1000                            #请求最长处理时间plugins:                                          #插件配置log:                                            #日志配置default:                                      #默认日志的配置可支持多输出- writer: file                              #本地文件日志level: debug                              #本地文件滚动日志的级别writer_config:filename: ../log/trpc_water.log                  #本地文件滚动日志存放的路径max_size: 20                              #本地文件滚动日志的大小 单位 MBmax_backups: 20                           #最大日志文件数max_age: 7                                #最大日志保留天数compress:  false                          #日志文件是否压缩- writer: uls                        #ULS日志level: debug                       #日志级别remote_config:app_id: 0x950009                 #业务的AppId,由系统管理员分配,必填字段water_id: 70                     #iWaterDestID: 流水日志需要发送到的日志中心ID流水日志中心可能有多套,每套一个IDcolor_id: 2                      #iColorDestID: 染色日志需要发送到的日志中心ID染色日志中心可能有多套,每套一个IDlog_path: ../log/trpc            #szLogFilePath:本地磁盘log文件的绝对路径,本地的流水日志和染色日志都记录在该路径下,不能传入空指针,否则函数调用出错svr_configed: 1                  #iSvrConfiged:是否启用远程记录流水日志,0:不启用, 1:启用color_svr_configed: 0            #iColorSvrConfiged:是否启用远程记录染色日志,0:不启用, 1:启用msg_port: 0                      #可指定发送远程日志所绑定的端口为0则随机端口relay_port: 0                    #可指定转发包所绑定的端口为0则随机端口user_def_1: 3                    #初始化用户自定义字段1由调用者自己填写自己解释agent_local_log: 0               #是否由Agent来负责记录本地log业务进程不再记录w_log_level: 5                   #cWLogLevel:本地流水日志的日志记录级别(取值范围0-5,请参考日志级别定义)小于等于该级别的都记录到本地w_log_msg_level: 5               #cWLogMsgLevel:流水日志中心的日志记录级别(取值范围0-5,请参考日志级别定义)小于等于该级别的都发送到流水日志中心, 一般设置为_LC_WARNING_t_log_level: 5                   #cTLogLevel:本地染色日志的日志记录级别(取值范围0-5,请参考日志级别定义)小于等于该级别的都记录到本地t_log_msg_level: 5               #cTLogMsgLevel:染色日志中心的日志记录级别(取值范围0-5,请参考日志级别定义)小于等于该级别的都发送到染色日志中心, 一般设置为_LC_WARNING_relay_log_level: 3               #cRelayLogLevel:转发包的记录级别(取值范围0-5,请参考日志级别定义),小于等于该级别并且染色配置命中,会转发到指定的ip:portlog_size: 10000000               #iLogSize:本地磁盘log文件单个文件的大小log_num: 10                      #iLogNum:本地磁盘log文件的最大个数call_depth: 7                    #必须是7才能打印正确的文件名和函数名 
2新建Dockerfile内容如下 
FROM centos
MAINTAINER zszs126.comENV MYPATH /data/app
WORKDIR $MYPATHRUN mkdir -p /data/app/bin
RUN mkdir -p /data/app/conf
RUN mkdir -p /data/app/log
RUN cd /data/app/log
RUN touch stdout.log
ADD mongo_proxy_svr $MYPATH/bin
RUN chmod x $MYPATH/bin/mongo_proxy_svr
ADD trpc_go.yaml $MYPATH/conf
ADD start.sh $MYPATH/bin
RUN chmod x /data/app/bin/start.sh
ENTRYPOINT [/data/app/bin/start.sh]EXPOSE 21187/udp
EXPOSE 21187/tcp 
3构建镜像 
docker build -t mongo_proxy:1.0 . 
4确认镜像已经存在 
docker images 
5利用此镜像启动容器 
docker run -d --name my_mongoproxy -p 21187:21187/tcp -p 21187:21187/udp  mongo_proxy:1.0 
6进入容器验证服务进程正常运行 
7用脚本工具向宿主机的21187端口发送如下请求 
inner_timeline_read_req {uint32_bid: 10str_db_name: db_call_trackstr_table_name: coll_1str_req_args: {\filter\: {\key\: \call_2885715001_8615731633538\, \time\: {\$gte\: 1673402312430230}}, \sort\: {\time\: -1}, \limit\: 2}
}#其中str_req_args为:
findArgs  {filter : {key : call_2885715001_8615731633538,time : {$gte : 1673402312430230}},limit : 2,sort : {time : -1}
}#./303294.py -e 6 -k 2355128746 -x 3008819490 
可以看到有数据返回。显然都通了 2.2.3、mongo_proxy服务镜像制作部署 —— host模式 
上述mongo_proxy访问mongodb的时候采用写死ip的方式显然是不行的即此处要进行网络规划。 
此处直接采用host模式理论上讲访问mongodb数据库的时候把连接串ip换成127.0.0.1就行了。 
预期预期bid11能通。。 
1启动mongodb数据库 
docker run -d --namezsmongodb \--net host \-e MONGO_INITDB_ROOT_USERNAMEroot \-e MONGO_INITDB_ROOT_PASSWORD123456 \mongo:4.02启动mongo_proxy_svr 
docker run -d --name my_mongoproxy --net host  mongo_proxy:1.03是通的符合预期 2.2.4、mongo_proxy服务镜像制作部署 —— 自定义网络模式 
预期预期bid9即直接用名字zsmongodb代替ip的连接方式是能通的。 
1创建一个网络 
docker network create my_network 
2启动mongodb容器并加入此网络 
docker run -d -p 27017:27017 --namezsmongodb \--network my_network \-e MONGO_INITDB_ROOT_USERNAMEroot \-e MONGO_INITDB_ROOT_PASSWORD123456 \mongo:4.0 
3启动mongo_proxy服务容器并加入此网络 
docker run -d --name my_mongoproxy --network my_network -p 21187:21187/tcp -p 21187:21187/udp  mongo_proxy:1.04向mongodb数据库中插入测试数据 
docker exec -it zsmongodb /bin/bash
mongo --host 127.0.0.1 -u root -p 123456
use db_call_track
db.coll_1.save({_id : ObjectId(64af6d368350f30cc6fb1fbb),ext1 : {\callid\:\7085095277245292544\,\has_third_call\:0,\legid\:\70850952772452925441\}\n,ext2 : ,key : call_2885715001_8615731633538,kfext : 3007552478,kfuin : 2885715001,status : 0,call_source : 5,display_type : 3,ext3 : ,phonenumer : 8615731633538,time : 1689218355954380,direction : 2,duration : 0
})5外部脚本访问效果如下显然符合预期 2.3、mongo_proxy镜像上传腾讯云 
按照 上一篇文章 的方法将此镜像上传腾讯云。 
由于名字发生了变更所以将docker-compose.yml稍微改下以后就可以随时服用mongo_proxy  mongodb这对组合了。 # docker-compose文件版本号
version: 3# 配置各个容器服务
services:mongo_proxy_svr:image: ccr.ccs.tencentyun.com/shuozhuo/mongo_proxy:1.0container_name: my_mongoproxy  # 容器名称如果不指定会生成一个服务名加上前缀的容器名ports:- 21187:21187/tcp- 21187:21187/udpvolumes:- /data/app/mongo_proxy_svr/log:/data/app/lognetworks:- my_networkdepends_on:  # 配置该容器服务所依赖的容器服务- zsmongodbzsmongodb:image: mongo:4.0environment:MONGO_INITDB_ROOT_USERNAME: rootMONGO_INITDB_ROOT_PASSWORD: 123456ports:- 27017:27017volumes:- /data/app/mongodb/data:/data/dbnetworks:- my_networknetworks:# 创建 my_network 网桥网络my_network: 2.4、q的玩法 
稍晚补充 三、docker网络 
3.1、docker network简介 先简单比对下没启动docker和启动docker后的主机的网络情况。 
#没有docker执行ifconfig:ens33/eth0: 这个标识宿主机的地址lo: 回环地址 127.0.0.1vibri0:#启动docker后执行ifconfig:docker0eth0lovirbro 
可以看到多了个docker0。这是因为docker启动后会产生一个名为docker0的虚拟网桥。 
docker就是通过docker0这个网桥进行容器↔宿主机、容器→容器间的网络通信。 
Docker 服务默认会创建一个docker0网桥其上有一个docker0内部接口该桥接网络的名称为 docker0它在内核层连通了其他的物理或虚拟网卡这就将所有容器和本地主机都放到同一个物理网络。 
Docker默认指定了docker0接口的IP地址和子网掩码让主机和容器之间可以通过网桥互相通信。 
查看bridge网络的详细信息并通过grep获取名称 
docker network inspect bridge | grep name 
可以看到其名称为docker0。 3.2、docker network常用命令 (1)列出当前网络
docker network ls
注主要用的是brige、其次是host,第三个none几乎不用。(2)创建一个网络
docker network create my_network(3)删除一个网络
docker network rm my_network(4)查看网络元数据
docker network inspect bridge 3.3、docker network能干啥 
(1)容器间的互联和通讯以及端口映射; (2)容器ip变动的时候可以通过服务名直接网络通信而不受到影响(而不是写死ip); 
其实就是名字服务的意思。docker1去访问docker2的mysql你绝对不能直接写死ip地址而应该写的是访问mysql。因为重启后mysql所在的容器的ip地址是会变的。 3.4、验证示例内默认网络ip生成规则 
默认启动ubuntu系统得到u1和u2。(记得通过winpq退出,否则容器也随之退出了) 
docker run -it --name u1 ubuntu bash
docker run -it --name u2 ubuntu bash 
#查看网络情况 
docker inspect 6302d5f329b3 | tail -n 25
docker inspect ffd05fb83ff1 | tail -n 25 
其中bridge即表示网络模式;IPAddress即为容器的ip地址。 可以看到u1的ip是172.17.0.2u2的ip是172.17.0.3显然两个容器的IPAddress彼此独立。 
我们现在将u2删除然后启动u3并查看u3的ip。 
docker rm -f u2
docker run -it --name u3 ubuntu bash
docker inspect u3 | tail -n 25 
发现u3的ip是172.17.0.3了(此ip之前被u2占有)显然ip是不能表征某个具体的容器的。 
结论docker容器内部的ip是可能发生改变的ip不能用于表征具体容器。在访问的时候也就不能根据ip进行访问。 
3.5、docker network网络模式有哪几种 
总共有如下五种模式。主流就是bridge、host、none三种;其中bridge最常用、host次之。其他平时不怎么用。 ps: 分别使用 --network bridge / --network host / --network none  指定。 网络模式  简介  使用方式  bridge  为每一个容器分配、设置IP等并将容器连接到一个docker0 虚拟网桥默认为该模式  --network bridge  host  容器将不会虚拟出自己的网卡、配置自己的IP等而是使用宿主机的IP和端口  --network host  none  容器有独立的 Network namespace但并没有对齐进行任何网络设置如分配 veth pari 和 网桥连接、IP等  --network none  container  新创建的容器不会创建自己的网卡和配置自己的IP而是和一个指定的容器共享IP、端口范围等  --network container:NAME或者容器ID 自定义就是bridge模式,理解为自定义的bridge(可以实现访问名字)/ 
3.5.1、bridge模式(默认) Docker使用Linux桥接在宿主机虚拟一个Docker容器网桥docker0Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址称为Container-IP同时Docker网桥是每个容器的默认网关。因为在同一个宿主机内的容器接入同一个网桥这样容器之间就能够通过容器的Container-IP直接通信。 docker run的时候没有指定--network的话默认使用的网桥模式就是bridge使用的就是docker0。在宿主机ifconfig就苦役看到docker0和自己create的network。 网桥docker0创建一对对等虚拟设备接口一个叫veth另一个叫eth0成对匹配 整个宿主机的网桥模式都是docker0类似一个交换机有一堆接口。其中docker0就交换器veth就是交换机上的插槽运行的容器就视为一个精简后的linux系统的eth0网卡就插在veth上。veth,eth0就称为veth pair。显然通过这种方式就可以实现容器和宿主机、容器与容器间的网络通信。 我们分别在宿主机和容器内执行ip addr可以看到匹配情况。 3.5.2、host模式 直接使用宿主机的 IP 地址与外界进行通信不再需要额外进行 NAT 转换。 
容器不会获得独立的Network Namespace而是和宿主机公用一个Network Namespace。容器也不会虚拟出自己的网卡(eth0)而是使用宿主机的ip和端口。 如果在 docker run 命令中同时使用了 --network host 和 -p端口映射例如 
docker run -d -p 8083:8080 --network host --name tomcat83 tomcat#不指定网址启动tomcat82
docker run -d -p 8082:8080 --name tomcat82 tomcat执行如下指令会出现警告 
WARNING: Published ports are discarded when using host network mode 
因为此时已经使用了host模式本身就是直接使用的宿主机的IP和端口此时的-p端口映射就没有了意义也不会生效端口号还是会以主机端口号为主。 
正确做法是不再进行-p端口映射或者改用bridge模式 
显然tomcat82和83的区别如下 查看tomcat83的内部信息因为和宿主机公用IP、端口所以就没有自己独立的了。  
docker inspect tomcat83 | tail -n 25 同理进入容器后执行“ip addr”的返回信息也和宿主机执行差不多。 
此时访问tomcat的ip就是宿主机的ip,port就是默认的8080其效果就类似于在宿主机上装了一个tomcat。 3.5.3、none模式 
禁用网络功能。 在none模式下并不为docker容器进行任何网络配置。进入容器内使用 ip addr查看网卡信息只能看到 lo本地回环网络127.0.0.1网卡。 
3.5.4、container模式 
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡、不会配置自己的ip而是和一个指定的容器共享ip、端口范围等。当然两个容器除了网络方面其他的如文件系统、进程列表等都还是隔离的。 实例 docker run -it --name alpine1 alpine /bin/sh # 指定和 alpine1 容器共享网络 docker run -it --netrowk container:alpine1 --name alpine2 alpine /bin/sh 注这个alpine是一个轻量、功能相对完备的Linux发行版本。由于小巧且功能完备非常适合用作基础镜像。 3.5.5、自定义网络 
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通) 
注:这里使用 billygoo/tomcat8-jdk8 是因为这个镜像有ip addr/ping等指令(官方认证的tomcat没有这些指令所以没用)。 
不用自定义网络按照IP地址去ping是ok的即容器1去ping容器2的ip能通反之亦然。但是按照服务名去ping就是不通的。如下 
docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8 
#通过一下指令直到81的ip是 172.17.0.2, 82的ip是 172.17.0.3 
docker inspect tomcat81 | tail -n 25
docker inspect tomcat82 | tail -n 25 
#进入两个容器ping对方的ip发现都是通的,但是尝试ping对方名字(tomcat81、tomcat82)发现都是不通的。 
docker exec -it tomcat81 /bin/bash
ping 172.17.0.3
ping tomcat82docker exec -it tomcat82 /bin/bash
ping 172.17.0.2
ping tomcat81 前面我们知道随着容器的销毁创建ip是会变的(即ip代表不了容器)但是直接访问名字又不通那要怎么办呢—— 自定义网络就可以解决这个问题。 
自定义桥接网络自定义网络默认使用的就是桥接网络bridge。   
自定义网络效果演示: 
新建自定义网络
docker network create zszs_network
docker network ls#新建的容器加入上一步新建的自定义网络。
docker run -d -p 8081:8080 --network zszs_network --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --network zszs_network --name tomcat82 billygoo/tomcat8-jdk8#进入容器ping对方的名字,发现可以ping通
docker exec -it tomcat81 /bin/bash 
#然后在进入tomcat81,tomcat82看看名字能不能ping通。果然可以ping通了。 注意docker多容器的集群规划一定要访问名字不能直接粗暴访问ip。 四、docker-compose容器编排 
官网: https://docs.docker.com/compose/   
4.1、docker-compose是什么能干什么 一句话容器太多(集群)而且容器之间涉及启动顺序、网络调用、一键部署、一键重启等诉求所以需要一个大总管管理起来。 
compose是docker公司推出的一个工具软件用于管理多个Docker容器组成的一个大的应用。通过定义一个yaml格式的配置文件docker-compose.yml写好容器之间的调用关系。然后只要一个命令就能同时启动/关闭这个大规模容器集群。 
docker建议我们每一个容器中只运行一个服务因为docker容器本身占用的资源极少。这种细粒度的划分显然就会让整体流程更加繁琐。 举个例子我的一个web微服务可能依赖redis、mongodb、kafka、es还可能需要注册中心、负载均衡等等显然执行N遍docker run就太傻了。 
compose运行用户通过一个单独的docker-compose.yml模板文件来定义一组相关联的应用容器为一个项目。然后就可以很容易的用一个配置文件定义一个多容器的应用。一条指令就可以完成这个项目的所有依赖并完成构建。它解决了容器与容器之间的管理编排问题。 4.2、下载与安装 
安装简介参照这里 https://docs.docker.com/compose/install/ 
我们这里选择 Scenario two: Install the Compose plugin 的 “Downloading and installing manually”。 
步骤如下。 
1、To download and install the Compose CLI plugin, run: DOCKER_CONFIG${DOCKER_CONFIG:-$HOME/.docker} mkdir -p $DOCKER_CONFIG/cli-plugins curl -SL https://github.com/docker/compose/releases/download/v2.24.6/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose 注: wget太慢的话就手动下载然后在上传到 $DOCKER_CONFIG/cli-plugins 路径并重命名为docker-compose。 
2、Apply executable permissions to the binary: chmod x $DOCKER_CONFIG/cli-plugins/docker-compose 3、测试安装 docker compose version 总结下来就是把docker-compose下载下来然后放到$DOCKER_CONFIG/cli-plugins路径下就可以了。 
卸载方式参见:  https://docs.docker.com/compose/install/uninstall/   
4.3、compose使用步骤 
1一个文件: docker-compose.yml 2两个要素:  1)服务(service):一个个应用容器实例比如业务微服务、mysql容器、nginx容器或redis容器。 2)工程(project):由一组关联的应用容器组成的一个完成业务单元在docker-compose.yml文件中定义。 
3compose使用的三个步骤 首先编写Dockerfile定义各个微服务应用并构建出对应的镜像文件 使用 docker-compose.yml定义一个完整业务单元安排好整体应用中的各个容器服务。 最后执行docker-compose.yml命令来启动并运行整个工程完成一键部署上线。 4.4、compose常用命令 
注我这个版本是“docker compose”有的是“docker-compse”  docker compose -h     #查看帮助 docker compose up     #启动所有docker-compose服务 docker compose up -d  #启动所有docker-compose服务并后台运行 docker compose down   #停止并删除容器、网络、卷、镜像 docker compose exec yml里面的服务id   #进入容器实例内部 docker compose ps     #展示当前docker-compose编排过的运行的所有容器 docker compose top    #展示当前docker-compose编排过的容器进程 docker compose logs yml里面的服务id   #查看容器输出日志 docker compose config      #检查配置 docker compose config -q   #检查配置有问题才有输出 docker compose restart     #重启服务 docker compose start       #启动服务 docker compose stop        #停止服务 4.5、compose编排微服务 
还是上面mongo_proxy访问mongodb的例子我们编排2.2.4(自定义网络)的工程。 
1首先编写如下docker-compose.yml文件 
注以后写docker-compose.yml就是拿现成的过来改而不是从头自己写(总体比较直观) 
# docker-compose文件版本号
version: 3# 配置各个容器服务
services:mongo_proxy_svr:  #第一个启动的容器的容器名为mongo_proxy_svrimage: mongo_proxy:1.0  #其依赖的镜像是 mongo_proxy:1.0container_name: my_mongoproxy  # 指定容器名。如果不指定会生成一个服务名加上前缀的容器名ports:- 21187:21187/tcp  #指定端口映射相当于-p- 21187:21187/udp  #指定端口映射相当于-pvolumes:               #指定容器数据卷相当于-v- /data/app/mongo_proxy_svr/log:/data/app/log  networks:              #指定要加入的网络相当于--net- my_networkdepends_on:            #配置该容器服务所依赖的容器服务(依赖zsmongodb这个容器)- zsmongodbzsmongodb:image: mongo:4.0environment:           #指定环境变量(对应docker run中指定环境环境变量)MONGO_INITDB_ROOT_USERNAME: rootMONGO_INITDB_ROOT_PASSWORD: 123456ports:- 27017:27017volumes:- /data/app/mongodb/data:/data/dbnetworks:- my_networknetworks:# 创建 my_network 自定义网桥网络my_network: 
2进行检查 
没有输出说明语法等都没有问题。  
docker compose config -q 
3启动 
docker compose up -d 4自测也都符合预期 5一键停止 
docker compose stop5总结。显然我们就实现了一键部署、一键停止。 
使用compose后对于三五十个容器的编排完全不在话下不过如果规模继续增大就需要k8s了。 4.6、更多容器编排案例 
1、官网上有些案例   Sample apps with Compose | Docker Docs 其中有很多常用的搭配例如下面这些。以后需要可以上来看看。 Elasticsearch / Logstash / Kibana - Sample Elasticsearch, Logstash, and Kibana stack.NGINX / Flask / MongoDB - Sample Python/Flask application with Nginx proxy and a Mongo database. 2、也可以网上直接搜。  
3、此处在提供一个案例如下。 
# docker-compose文件版本号
version: 3# 配置各个容器服务
services:microService:image: springboot_docker:1.0container_name: ms01  # 容器名称如果不指定会生成一个服务名加上前缀的容器名ports:- 6001:6001volumes:- /app/microService:/datanetworks:- springboot_networkdepends_on:  # 配置该容器服务所依赖的容器服务- redis- mysqlredis:image: redis:6.0.8ports:- 6379:6379volumes:- /app/redis/redis.conf:/etc/redis/redis.conf- /app/redis/data:datanetworks:- springboot_networkcommand: redis-server /etc/redis/redis.confmysql:image: mysql:5.7environment:MYSQL_ROOT_PASSWORD: 123456MYSQL_ALLOW_EMPTY_PASSWORD: noMYSQL_DATABASE: db_springbootMYSQL_USER: springbootMYSQL_PASSWORD: springbootports:- 3306:3306volumes:- /app/mysql/db:/var/lib/mysql- /app/mysql/conf/my.cnf:/etc/my.cnf- /app/mysql/init:/docker-entrypoint-initdb.dnetworks:- springboot_networkcommand: --default-authentication-pluginmysql_native_password # 解决外部无法访问networks:# 创建 springboot_network 网桥网络springboot_network: 五、docker轻量级可视化工具Portainer 
5.1、是什么 
Protainer是一款轻量级的应用提供了图形化的界面用于方便地管理Docker环境。 
5.2、安装与使用 
1、官网 https://www.portainer.io/ 
2、Resources → install →  Community Edition → Set up a new Portainer CE Server installation → Docker Standalone → Install Portainer CE with Docker on Linux。 
进入此链接对照着安装即可。  https://docs.portainer.io/start/install-ce/server/docker/linux 
(1)First, create the volume that Portainer Server will use to store its database: 
docker volume create portainer_data 
(2)Then, download and install the Portainer Server container: 
docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restartalways -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest 
注:如果是云服务器记得在安全组规则上放开9443/8000端口。 注:--restartalways 的意思是如果整个docker重启了,此容器也跟着重启。 
(3)检查是否起来了 
docker ps 
(4)连接portainer的web服务器(ip为宿主机外网ip) https://118.xx.xx.69:9443    #浏览器直接输入 
首次进入的话会有一个初始化的过程,其实就是定义用户名密码按操作就好。 
username: admin
password: abcdefg123456 (5)之后出现了如下提示按提示我们重启portainer即可。 “Your Portainer instance timed out for security purposes. To re-enable your Portainer instance, you will need to restart Portainer.” 
sudo docker restart portainer 
重新登陆后就进来后就可以看到如下界面。 连接local后就可以看到当前宿主机的监控情况了如下 注其中“Stack”表示容器编排其他各项就顾名思义了。 六、docker容器监控CAdvisorInflusDBGranfana(CIG) 6.1、原生命名 docker stats 
占了多少cpu、找了多少内存、网络io是多少 说到这里肯定会立马想到之前介绍过的 docker stats命令。 
他可以方便的看到当前宿主机上的所有容器的cpu、内存及网络流量等数据。 但是docker stats统计的只是当前宿主机的全部容器且数据资料没有落地存储、没有健康指标过线预警等功能。 
6.2、容器监控三剑客(CIG) 
一句话CAdvisor监控收集  InfluxDB存储数据  Grafana展示图表 
1、CAdvisor: CAdvisor是一个容器资源监控工具包括容器的内存CPU网络IO磁盘IO等监控。但是它默认只存储2分钟的数据而且只针对单物理机。不过CAdvisor提供了很多数据集成接口支持Influxdb, redis,kafka,elasticsearch等集成可以加上对应配置将监控数据发往这些数据库存储起来。 总的来讲CAdvisor收集信息很强。 
2、InfluxDB: 是一款基于go语言编写的分布式时序数据库。为了持久化存储数据和统一收集展示监控数据 需要将数据存储到Influxdb中。Influxdb是一个时序数据库专门用于存储时序相关数据。而且CAdvisor本身 提供了Influxdb的集成方法启动容器时指定配置即可。 
3、Grafana: Grafana是一个开源的数据监控分析可视化平台。 6.3、docker compose一键部署 
编写docker-compose.yml文件如下 
version: 3.1volumes:grafana_data: {}services:influxdb:# tutum/influxdb 相比influxdb多了web可视化视图。但是该镜像已被标记为已过时image: tutum/influxdb:0.9restart: alwaysenvironment:- PRE_CREATE_DBcadvisorports:- 8083:8083         # 数据库web可视化页面端口- 8086:8086         # 数据库端口volumes:- ./data/influxdb:/datacadvisor:image: google/cadvisor:v0.32.0links:- influxdb:influxsrvcommand:- -storage_driverinfluxdb- -storage_driver_dbcadvisor- -storage_driver_hostinfluxsrv:8086restart: alwaysports:- 8080:8080volumes:- /:/rootfs:ro- /var/run:/var/run:rw- /sys:/sys:ro- /var/lib/docker/:/var/lib/docker:rografana:image: grafana/grafana:8.5.2user: 104restart: alwayslinks:- influxdb:influxsrvports:- 3000:3000volumes:- grafana_data:/var/lib/grafanaenvironment:- HTTP_USERadmin- HTTP_PASSadmin- INFLUXDB_HOSTinfluxsrv- INFLUXDB_PORT8086 注意事项 (1)我们在influxdb中创建了一个数据库 cadvisor ,这个后面选数据源的时候会用到。 (2) (3) 执行部署命令 
docker compose up -d 
部署完了后分别进行测试。注这三个软件都有对外暴露专门的图形化界面这里分别看下。 ①浏览CAdvisor收集服务http://ip:8080         注: 第一次比较慢稍微等等。 ②浏览Influxdb存储服务http://ip:8083         注:可以查询创建数据库、删除数据库等。 ③浏览grafana展现服务 http://ip:3000         注:默认用户名(密码)是admin(admin)然后login更改密码为123456 三个都ok后就可以继续了。。 6.4、配置grafana 6.4.1、配置数据源 
Configuration → DATA source → Add data source。 可以看到支持很多数据库我们这里就选择Influxdb作为数据源。进入配置先配置URL如下 注 “http://InfluxDB:8086”这里是尽量用名字去调用而不是写死ip(应该就是Name)。 
然后再 配置数据库、用户名(默认root)、密码(默认root)如下 点击 Savetest后出现如下绿色就说明通了。 6.4.2、创建仪表盘(dashboard)并添加面板(panel) 
首先创建仪表盘。  Create → Dashboard  然后添加面板。 → Add a new panel 接下来进入如下页面。首选 选择监控样式(柱状图/折线图/指针图等)。  → Time series 选择一个自己想要的此处选了折线图 Graph(old)。 注选了之后在其下方“panel option”有诸多属性配置试试就会用了。 
此处简单配置下这个面板(panel)的 Title、Description如下 然后点击save输入下dashboard的名字面板就弄出来了如下 可以看到此时并没有数据接下来我们需要添加数据。 
6.4.3、为panel添加数据 
下箭头 → Edit 如下图所示 大方框中就可以配置一个指标。如果有多个指标点击“ Query”继续添加即可。 接下重点看看如何配置一个具体的监控指标。 1红框处就是我们之前配置的数据源没有任何问题 2蓝框处选择具体哪张表(influxdb叫measurements)此处选择“memory_usage”; 3绿框处“memory_usage”这张表中具体字段即筛选值 4黄框处给我的指标重新命令一下。 注意1蓝框处出现的选项其实就是选择那个数据库influxdb中可以直接看到。 注意2选择 memory_usage 后后面的where条件的key-value值都是根据数据库中的字段来的。 
如下图。memory_usage表中有两个可选字段分别是 container_name 和 machine后面具体的value也都是数据库中实际有的value。 好了后点击右上角 Apply即可。 6.4.3、效果演示 
如下图配置了两个监控指标分别监控influxdb、grafana、Cadvisor三个容器的内存使用情况。 
我们还可以在这个dashboard下继续添加panel如下箭头所示。 然后我又添加了一个cpu监控的panel最终效果如下