docker学习进阶

一、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体系的基石。

  1. Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
  2. Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时会真正开始提供服务;
  3. 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 zs<zs@126.com>

ENV 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|#baseurl=http://mirror.centos.org|baseurl=http://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:$PATH

EXPOSE 80

CMD 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 dangling=true

(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 --name=zsmongodb \
    -e MONGO_INITDB_ROOT_USERNAME=root \
    -e MONGO_INITDB_ROOT_PASSWORD=123456 \
    mongo:4.0


(2)连接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
})

(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/sh

cd /data/app/bin
chmod +x mongo_proxy_svr
./mongo_proxy_svr -conf ../conf/trpc_go.yaml > /data/app/log/stdout.log 2>&1

trpc_go.yaml 如下,其中基于原服务修改了

(1)bid10对应的配置如下(其中172.17.0.2是mongodb镜像被分配的ip)
    - name: trpc.mongodb.online.instance9
      target: mongodb://root:123456@172.17.0.2:27017/?readPreference=secondaryPreferred
      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                                     #拦截框架创建的业务处理协程panic
  service:                                         #业务服务提供的service,可以有多个
    - name: inner.track.timeline.TimelineProxyService            #service的路由名称
      #ip: 127.0.0.1                            #服务监听ip地址 可使用占位符 ${ip},ip和nic二选一,优先ip
      nic: eth0
      port: 21187                #服务监听端口 可使用占位符 ${port}
      network: udp                             #网络监听类型  tcp udp
      protocol: inner               #应用层协议 trpc http
      timeout: 1000                            #请求最长处理时间 单位 毫秒
    - name: trpc.track.timeline.TimelineProxyService      #service的路由名称
      #ip: 127.0.0.1                            #服务监听ip地址 可使用占位符 ${ip},ip和nic二选一,优先ip
      nic: eth0
      port: 21187                #服务监听端口 可使用占位符 ${port}
      network: tcp                             #网络监听类型  tcp udp
      protocol: inner               #应用层协议 trpc http
      timeout: 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,验证访问容器名是否ok
      target: mongodb://root:123456@zsmongodb:27017/?readPreference=secondaryPreferred
      timeout: 3000                                      
    - name: trpc.mongodb.online.instance9       #对应bid10,验证访问分配ip是否ok
      target: mongodb://root:123456@172.17.0.2:27017/?readPreference=secondaryPreferred
      timeout: 3000                                  
    - name: trpc.mongodb.online.instance10      #对应bid11,验证访问本机是否ok
      target: mongodb://root:123456@127.0.0.1:27017/?readPreference=secondaryPreferred
      timeout: 3000                                     
    - name: trpc.track.timeline.TimelineProxyService    #后端服务的service name
      namespace: Development                   #后端服务的环境
      network: tcp                             #后端服务的网络类型 tcp udp 配置优先
      protocol: trpc                           #应用层协议 trpc http
      target: 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                              #本地文件滚动日志的大小 单位 MB
          max_backups: 20                           #最大日志文件数
          max_age: 7                                #最大日志保留天数
          compress:  false                          #日志文件是否压缩
      - writer: uls                        #ULS日志
        level: debug                       #日志级别
        remote_config:
          app_id: 0x950009                 #业务的AppId,由系统管理员分配,必填字段
          water_id: 70                     #iWaterDestID: 流水日志需要发送到的日志中心ID(流水日志中心可能有多套,每套一个ID)
          color_id: 2                      #iColorDestID: 染色日志需要发送到的日志中心ID(染色日志中心可能有多套,每套一个ID)
          log_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:port
          log_size: 10000000               #iLogSize:本地磁盘log文件单个文件的大小
          log_num: 10                      #iLogNum:本地磁盘log文件的最大个数
          call_depth: 7                    #必须是7才能打印正确的文件名和函数名

(2)新建Dockerfile,内容如下

FROM centos
MAINTAINER zs<zs@126.com>

ENV MYPATH /data/app
WORKDIR $MYPATH

RUN 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: 10
  str_db_name: "db_call_track"
  str_table_name: "coll_1"
  str_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 --name=zsmongodb \
    --net host \
    -e MONGO_INITDB_ROOT_USERNAME=root \
    -e MONGO_INITDB_ROOT_PASSWORD=123456 \
    mongo:4.0

(2)启动mongo_proxy_svr

docker run -d --name my_mongoproxy --net host  mongo_proxy:1.0

(3)是通的,符合预期

2.2.4、mongo_proxy服务镜像制作部署 —— 自定义网络模式

预期:预期bid9,即直接用名字zsmongodb代替ip的连接方式是能通的。

(1)创建一个网络

docker network create my_network

(2)启动mongodb容器并加入此网络

docker run -d -p 27017:27017 --name=zsmongodb \
    --network my_network \
    -e MONGO_INITDB_ROOT_USERNAME=root \
    -e MONGO_INITDB_ROOT_PASSWORD=123456 \
    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.0

(4)向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.5、q的玩法

稍晚补充

三、docker网络

3.1、docker network简介

  先简单比对下没启动docker和启动docker后的主机的网络情况。

#没有docker执行ifconfig:
    ens33/eth0: 这个标识宿主机的地址
    lo: 回环地址 127.0.0.1
    vibri0:

#启动docker后执行ifconfig:
    docker0
    eth0
    lo
    virbro

可以看到多了个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。(记得通过win+p+q退出,否则容器也随之退出了)

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.2,u2的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容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一个宿主机内的容器接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

    docker run的时候,没有指定--network的话,默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig就苦役看到docker0和自己createnetwork

        网桥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 tomcat82

docker 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文件中定义。

(3)compose使用的三个步骤
首先,编写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文件版本号
version: "3"

# 配置各个容器服务
services:
  mongo_proxy_svr:
    image: mongo_proxy:1.0
    container_name: my_mongoproxy  # 容器名称,如果不指定,会生成一个服务名加上前缀的容器名
    ports:
      - "21187:21187/tcp"
      - "21187:21187/udp"
    volumes:
      - /data/app/mongo_proxy_svr/log:/data/app/log
    networks:
      - my_network
    depends_on:  # 配置该容器服务所依赖的容器服务
      - zsmongodb

  zsmongodb:
    image: mongo:4.0
    environment:
      MONGO_INITDB_ROOT_USERNAME: 'root'
      MONGO_INITDB_ROOT_PASSWORD: '123456'
    ports:
      - "27017:27017"
    volumes:
      - /data/app/mongodb/data:/data/db
    networks:
      - my_network

networks:
  # 创建 my_network 网桥网络
  my_network:

(2)进行检查

没有输出说明语法等都没有问题。 

docker compose config -q

(3)启动

docker compose up -d

(4)自测也都符合预期!!!!

(5)一键停止

docker compose stop

(5)总结。显然我们就实现了一键部署、一键停止。

使用compose后对于三五十个容器的编排完全不在话下,不过如果规模继续增大就需要k8s了。

五、docker轻量级可视化工具Portainer

5.1、Portainer简介

  (0)待补充

六、docker容器监控CAdvisor+InflusDB+Granfana

6.1、方案简介

  (0)待补充

6.2、搭建流程

  (0)待补充

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/441714.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第11周,第三期技术动态

大家好&#xff0c;才是真的好。 真没想到&#xff0c;本周是今年第十一周&#xff0c;2024年还有不到三百天就结束了。 今天周五&#xff0c;我们继续介绍与Domino相关产品新闻&#xff0c;以及互联网或其他IT行业动态等。 一、在Windows 10和Windows 11上运行Domino和Trav…

错误和异常之标准异常创建异常

标准异常 表 10.2 列出了所有的 Python 当前的标准异常集,所有的异常都是内建的. 所以它们在脚本启动 前或在互交命令行提示符出现时已经是可用的了. 表10.2 Python内建异常 异常名称描述所有异常的基类 python 解释器请求退出 用户中断执行(通常是输入^C) 常规错误的基类

大模型时代下的自动驾驶研发测试工具链-SimCycle

前言&#xff1a; 最近OpenAI公司的新产品Sora的发布&#xff0c;正式掀起了AI在视频创作相关行业的革新浪潮&#xff0c;AI不再仅限于文本、语音和图像&#xff0c;而直接可以完成视频的生成&#xff0c;这是AI发展历程中的又一座重要的里程碑。AI正在不断席卷着过去与我们息…

仿牛客项目Day02:http、调试、日志、git

http状态码 后端调试 f8&#xff1a;逐行执行 f7&#xff1a;进入语句内部 f9&#xff1a;执行到下一个断点 前端调试 f10&#xff1a;逐行调试 f11&#xff1a;进入语句内部 f8&#xff1a;执行到下一个断点 日志 按照级别开启日志 日志的测试类 比如把application里…

基于交叉表生成风控规则(Python)

大家好&#xff0c;我是东哥。 规则是风控策略中最常用的工具之一&#xff0c;生成、筛选、监控、调优&#xff0c;几乎每天都在打交道&#xff0c;本篇来介绍如何基于交叉表来生成风控规则&#xff0c;并且如何基于评估指标进行筛选。 出品人&#xff1a;东哥起飞 专栏&#…

【字符串】【分类讨论】【KMP】1163. 按字典序排在最后的子串

作者推荐 视频算法专题 本文涉及知识点 字符串 字典序 分类讨论 本题无法使用KMP&#xff0c;因为t1不段变化。 LeetCode1163. 按字典序排在最后的子串 给你一个字符串 s &#xff0c;找出它的所有子串并按字典序排列&#xff0c;返回排在最后的那个子串。 示例 1&#xf…

图论入门题题解

✨欢迎来到脑子不好的小菜鸟的文章✨ &#x1f388;创作不易&#xff0c;麻烦点点赞哦&#x1f388; 所属专栏&#xff1a;刷题_脑子不好的小菜鸟的博客-CSDN博客 我的主页&#xff1a;脑子不好的小菜鸟 文章特点&#xff1a;关键点和步骤讲解放在 代码相应位置 拓扑排序 / 家谱…

基于Docker搭建Maven私服仓库(Linux)详细教程

文章目录 1. 下载镜像并启动容器2. 配置Nexus3. 配置本地Maven仓库 1. 下载镜像并启动容器 下载Nexus3镜像 docker pull sonatype/nexus3查看Nexus3镜像是否下载成功 docker images创建Nexus3的挂载文件夹 mkdir /usr/local/nexus-data && chown -R 200 /usr/local…

cadence 之 Allegro PCB封装 3D模型

Allegro PCB封装怎样赋3D模型 1、方式一 —— 设置器件高度 2、方式二 —— 指定STEP模型 2.1、Step 3D模型库 2.2、软件环境的设置和 STEP 模型库路径设置 D:\Cadence\Cadence_SPB_17.4-2019\share\local\pcb\step 2.3、指定STEP模型 即可打开 STEP 模型指定的对话框&…

【HarmonyOS】ArkTS-对象方法

目录 对象方法实例 对象方法 方法作用&#xff1a;描述对象的具体行为 约定方法类型 interface 接口名称 { 方法名: (参数:类型) > 返回值类型 }interface Person{dance: () > voidsing: (song: string) > void}添加方法&#xff08;箭头函数&#xff09; let ym: P…

服务器配置禁止IP直接访问,只允许域名访问

联网信息系统需设置只允许通过域名访问&#xff0c;禁止使用IP地址直接访问&#xff0c;建议同时采用云防护技术隐藏系统真实IP地址且只允许云防护节点IP访问服务器&#xff0c;提升网络安全防护能力。 一、Nginx 修改配置文件nginx.conf&#xff0c;在server段里插入正则表达式…

【C++ 学习】构造函数详解!!!

1. 类的6个默认成员函数的引入 ① 如果一个类中什么成员都没有&#xff0c;简称为空类。 ② 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 ③ 默认成员函数&#xff1a;用户没有显式实现&…

LoadBalancer 客户端的负载均衡器+openFeign 请求转发

LoadBalancer Spring Cloud LoadBalancer是Spring Cloud中负责客户端负载均衡的模块&#xff0c;其主要原理是从nacos中获取服务列表通过选择合适的服务实例来实现负载均衡。 源码跟踪 可以看到这里的intercept()方法&#xff0c;拦截了用户的HttpRequest请求&#xff0c;然…

在IDEA使用HBase Java API连接

一、下载安装Maven并加载到IDEA中 官网地址:Maven – Download Apache Maven 将对应版本的压缩包下载到本地,并新建一个文件夹Localwarehouse&#xff0c;用来保存下载的依赖文件 配置maven的系统环境配置&#xff0c;将maven安装的bin目录地址写入path环境变量&#xff1a; …

机器学习--循环神经网络(RNN)4

一、RNN的学习方式 如果要做学习&#xff0c;需要定义一个损失函数&#xff08;loss function&#xff09;来评估模型的好坏&#xff0c;选一个参数要让损失最小。 以槽填充为例&#xff0c;如上图所示&#xff0c;给定一些句子&#xff0c;给定一些标签&#xff0c;告诉机器…

【软件工程导论】——软工学绪论及传统软件工程(学习笔记)

&#x1f4d6; 前言&#xff1a;随着软件产业的发展&#xff0c;计算机应用逐步渗透到社会生活的各个角落&#xff0c;使各行各业都发生了很大的变化。这同时也促使人们对软件的品种、数量、功能和质量等提出了越来越高的要求。然而&#xff0c;软件的规模越大、越复杂&#xf…

测试环境搭建整套大数据系统(九:docker学习)

一&#xff1a;为什么学习dockder&#xff1f; 对于组件的搭建和部署&#xff0c;可以简化。 二&#xff1a;什么是docker&#xff1f; docker是一个平台。 三&#xff1a;怎么使用docker&#xff1f; 1. 安装&#xff0c;切换仓库。 安装 curl -fsSL https://test.docke…

[java基础揉碎]继承

为什么需要继承: > 继承就可以解决代码复用的问题 继承的基本介绍: 继承的使用细节: 1.子类继承了所有的属性和方法&#xff0c;但是私有属性和方法不能在子类直接访问&#xff0c;要通过公共的方法去访问 解决, 提供公共的方法返回: 2.子类必须调用父类的构造器,完成父…

CACLP预告 | 飞凌嵌入式与您相约山城重庆

第二十一届中国国际检验医学暨输血仪器试剂博览会&#xff08;CACLP&#xff09;将于2024年3月16日-18日在重庆国际博览中心举行。本次会议将探讨科技创新趋势&#xff0c;展示最新成果&#xff0c;发现和挖掘颠覆性技术和创新产品&#xff0c;引领实验医学体外诊断科技创新和未…

利用IP地址信息提升网络安全

在计算机网络中&#xff0c;IP地址是用于唯一标识网络设备的重要标识符。然而&#xff0c;由于网络中存在大量设备&#xff0c;有时会出现IP地址冲突的情况&#xff0c;即两个或多个设备在同一网络中使用了相同的IP地址&#xff0c;这可能导致网络连接故障和通信中断。本文将介…