docker学习进阶

news2024/12/25 14:04:31

一、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)待补充

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【硬件工程师面经整理24_其它】

文章目录 1 功放线性指标调试方法2 功放线性指标之间的关系3 光衰减器的原理4 材料硬度由什么决定&#xff1f;5 晶振市场失效率&#xff1f;6 原码、反码和补码 1 功放线性指标调试方法 调试功放线性指标的方法可以根据具体的情况和要求而有所不同&#xff0c;以下是一般性的…

html--钢琴

代码 <!DOCTYPE html> <html> <head> <meta http-equiv"Content-Type" content"text/html; charsetutf-8" /> <title>html钢琴</title> <script src"js/js.js"></script> <link href"…

vscode setting.json 全局设置 工作区设置 位置 优先级

vscode中setting.json有两种配置权限 一、全局配置&#xff1a;setting.json文件位于C:\Users\Administrator\AppData\Roaming\Code\User\settings.json 二、工作区配置&#xff1a;setting.json文件位于工作区的.vscode\settings.json 当两种配置同时存在时&#xff0c;工作区…

IOS覆盖率报告info文件解读

一&#xff0c;IOS覆盖率报告的生成 在做前端精准测试的时候&#xff0c;对于iOS端&#xff0c;通常会做如下操作&#xff1a; &#xff08;1&#xff09;合并覆盖率数据 如下操作&#xff1a; xcrun llvm-profdata merge coverage_file1657885040728.profraw coverage_fil…

力扣hot100:240.搜索二维矩阵II(脑子)

吉大21级算法分析与设计的一道大题&#xff0c;由于每一行都是排好序的直接逐行二分 可以达到&#xff1a;O(mlogn)。但是这里追求更广的思路可以使用其他方法。 矩阵四分&#xff1a; 在矩阵中用中心点比较&#xff0c;如果target大于中心点的值&#xff0c;则由于升序排列&am…

Java面试(8)

三次握手与四次挥手 三次握手: 客户端与服务端建立TCP连接时总共需要发送三个包 三次握手过程中容易引发SYN(DDOS)攻击,所谓SYN攻击是指: 攻击客户端,在短时间内伪造大量不存在的IP地址,向服务端不断发送syn包,服务端收到包后向客户端发送确认包,但由于客户端IP不存在,导致服务…

FPGA FIFO 读取模式

FPGA FIFO 读取模式分两种&#xff1a; Normal Mode: In normal mode, the “rdreq” signal serves as the read request or read enable. When this signal goes high, the data output provides the first data from the FIFO.Essentially, in normal mode, data is availa…

Prompt进阶系列1:LangGPT(从编程语言反思LLM的结构化可复用提示设计框架)

Prompt进阶系列1:LangGPT(从编程语言反思LLM的结构化可复用提示设计框架) 大语言模型 (Large Language Models, LLMs) 在不同领域都表现出了优异的性能。然而&#xff0c;对于非AI专家来说&#xff0c;制定高质量的提示来引导 LLMs 是目前AI应用领域的一项重要挑战。现有的提示…

【经典案例】某大型公园构建检查监督机制项目纪实

——引入网格化监督管理机制&#xff0c;实现责任、人员、信息三位一体 公园管理由于其本身地域范围广的特性在工作中很难进行有效的监督检查&#xff0c;该公园的监督检查由不同的部门分别负责&#xff0c;同部门检查时往往会处于情面而使检查流于形式&#xff0c;并且公园的监…

VSCode搭建ARM开发环境

为了构建Cortex M系列单片机免费开源的开发环境&#xff0c;网络上了解来看VSCODEGCCJLINK是一套比较高效的组合方式&#xff0c;下面记录环境搭建的流程。 我这边的PC环境为 WIN7专业版64bit。 需要用到的工具 Visual Studio CodeSTM32CubemxARM GCC 交叉编译工具链&#x…

javaWebssh文玩竞价管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh文玩竞价管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0…

MySQL--索引底层数据结构详解

索引是什么&#xff1f; 索引是帮助MySQL高效获取数据的排好序的数据结构&#xff0c;因此可知索引是数据结构。 概念很抽象&#xff0c;但是类比生活中的例子就很容易理解&#xff0c;比如一本厚厚的书&#xff0c;我们想取找某一小节&#xff0c;我们可以根据目录去快速找到…

复试人工智能前沿概念总结

1.大模型相关概念&#xff08;了解即可&#xff09; 1.1 GPT GPT&#xff0c;全称为Generative Pre-training Transformer&#xff0c;是OpenAI开发的一种基于Transformer的大规模自然语言生成模型。GPT模型采用了自监督学习的方式&#xff0c;首先在大量的无标签文本数据上进…

Linux配置.bashrc文件导致各种命令(vim、sudo)失效。

Linux配置.bashrc文件导致各种命令&#xff08;vim、sudo&#xff09;失效。 起因是 nvcc-V一直报错&#xff1a;-bash&#xff1a;nvcc&#xff1a; command not found 踩坑记录&#xff1a;上网一查说是没有配置cuda的环境变量。于是去修改了bashrc文件&#xff0c;在最下面…

Imagination:RISC-V CPU的重要力量

根据SHD集团最近发布的报告显示&#xff0c;RISC-V正全速发展中。通过分析从2021年到2030年这十年间RISC-V核在不同应用和功能领域的潜在市场&#xff0c;作者Rich Wawrzyniak得出结论称&#xff0c;到2030年&#xff0c;22.3%的SoC将包含RISC-V CPU&#xff0c;RISC-V的收入预…

如何保证消息不丢之MQ重试机制消息队列

1. 简介 死信队列&#xff0c;简称&#xff1a;DLX&#xff0c;Dead Letter Exchange&#xff08;死信交换机&#xff09;&#xff0c;当消息成为Dead message后&#xff0c;可以被重新发送到另外一个交换机&#xff0c;这个交换机就是DLX 那么什么情况下会成为Dead message&a…

Unity中PICO实现移动交互

文章目录 前言一、在允许行走的地面加上对应的组件1、Teleportation Anchor 移动锚点2、Teleportation Area 移动区域 二、在 玩家&#xff08;需要移动的对象&#xff09;上挂载对应组件1、Teleportation Provider 被移动对象2、在 Teleportation Anchor 或 Teleportation Are…

<商务世界>《第9课 产品地图》

1 产品地图 产品地图的核心是产品或用户的业务流程或地图导航&#xff0c;从用户和产品两条路线出发&#xff0c;搭建业务架构&#xff0c;并划分明确的功能模块&#xff0c;用图形化方式记录、整理、表现出产品的清晰特点。其中&#xff0c;包括用户在使用过程中做了什么、感…

景联文科技:专业提供高质量大语言模型训练数据

2024年&#xff0c;数字经济被再次写入政府工作报告中&#xff0c;报告指出要深化大数据、人工智能等研发应用&#xff0c;打造具有国际竞争力的数字产业集群。 大模型作为生成式人工智能的基础&#xff0c;日益成为国际科技竞争的焦点。人大代表杨剑宇指出&#xff0c;尽管我国…

SHARE 100M PRO:航测领域的多面手

在无人机航测领域&#xff0c;SHARE 100M PRO单镜头航测相机以其1.02亿像素的中画幅传感器和创新技术&#xff0c;正在重塑倾斜摄影的精度和效率。这款相机不仅在城市规划和土地管理中发挥着重要作用&#xff0c;还在环境监测、基础设施建设、农业管理等多个航测领域展现出其卓…