Docker

2024-07-03

简介

  • Registries:仓库

  • Docker 对象(Docker Objects)

    • Image:镜像,docker可执行文件,包括代码、依赖库、环境变量、配置等

    • container:容器,镜像运行的实例

    • network:与宿主机或镜像间的网络通信方式

      • bridge:网桥
      • host
      • none
      • overlay
      • macvlan
    • volume:数据卷,与宿主机或镜像间的共享存储方式。如:映射到宿主机的文件夹

底层技术

使用Go实现,利用了如下Linux内核的特性(只能在Linux上运行。Win、Mac本质上通过虚拟化,在Linux虚拟机上运行)

  • Namespaces:为容器提供系统层面隔离(与宿主机或容器间的隔离)

    • 进程隔离:每个容器的进程号都从1开始
    • 网络隔离
    • 进程间通信隔离
    • 文件系统挂载隔离
    • 内核隔离
  • Control Groups:为容器提供硬件层面隔离:对容器进行约束

  • Union File Systems:镜像和容器的层级存储。当创建或构建一个 Docker 镜像时,Docker 会将每个 RUNCOPYADD 等操作都分配为单独的层

    • 示例:一个基础的 Ubuntu 镜像,之后你安装了一个 Python 环境和一个应用

      # 从基础镜像开始
      FROM ubuntu:20.04
      
      # 更新并安装 Python
      RUN apt-get update && apt-get install -y python3
      
      # 将应用程序文件添加到镜像中
      COPY myapp.py /app/myapp.py
      
      # 设置容器启动时执行的命令
      CMD ["python3", "/app/myapp.py"]
      
      • 基础Ubuntu镜像:层1
      • python:层2
      • 安装应用:层3

      每一层只记录变更,底层的 Ubuntu 镜像在多个容器之间共享,而每个容器只会记录自己的差异

    • 分层的优势

      • 效率:通过只保存差异层而不是复制整个文件
      • 快速启动:容器能够快速启动,因为它们仅仅是联合的不同层,而不是从头开始复制所有文件
      • 便于管理:Docker 镜像的层级结构使得每次镜像的构建都可以只包含差异,而不必重复前面已有的部分

容器格式(Contianer Format):通过将三个特性的内容组合成package。Docker通过控制package的三个特性的内容,实现对容器的创建与管理

镜像

  • 搜索 docker search [OPTIONS] TERM

    -f, --filter filter 根据提供的格式筛选结果

    --format string 利用Go语言的format格式化输出结果

    --limit int 展示最大的结果数,默认25个

    --no-trunc 内容全部显示

    E.g. docker seach -f is-official=true ubuntu

  • 查看本地 docker images (/ docker image ls) [OPTIONS] [REPOSITORY[:TAG]]

    -a, --all 展示所有(默认显示隐藏底层的镜像)

    --no-trunc 不缩略显示

    -q, --quiet 只显示镜像ID

    E.g. docker images centos:latest

  • 拉取 docker pull [OPTIONS] NAME[:TAG|@DIGEST]

    -a, --all-tags 下载所有符合给定tag的镜像

  • 删除 docker rmi (/ docker image rm) [OPTIONS] IMAGE [IMAGE...]

    -f, --force 强制删除

    E.g. 使用ID对镜像进行删除

    docker images
    # REPOSITORY		TAG			IMAGE ID			CREATED			SIZE
    # centos				latest	2zoi3uds09ad	2 days ago	200MB
    # ubuntu				latest	j89fashd101k	3 days ago	100MB
    docker image rm 2zoi j89f
    
  • 保存备份 docker save [OPTIONS] IMAGE [IMAGE...] 一个或多个镜像打包

    -o, --output string 指定写入的文件名和路径

    E.g. docker save -o output.tar centos ubuntu

  • 导入备份 docker load [OPTIONS]

    -i, --input string 指定要打入的文件,如没有指定,默认是STDIN

    -q, --quiet 不打印导入过程信息

  • 重命名 docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG] 修改镜像的name与tag信息

    E.g. docker tag 2zoi customname:customtag

  • 检视 docker (image) inspect [OPTIONS] IMAGE [IMAGE...] 查看镜像详情

    -f, --format string 利用特定Go语言的format格式输出结果

    E.g.

    # 输出信息json
    docker image inspect centos
    # 输出信息json中Id字段的内容
    docker image inspect -f "{{json .Id}}" centos
    # 数组信息json中Created的内容
    docker image inspect -f "{{json .Created}}" centos
    
  • 历史(历史分层)信息 docker history [OPTIONS] image

    -H, --human 将创建时间、大小进行优化打印(默认为true)

    -q, --quiet 只显示镜像ID

    --no-trunc 缩略显示

容器

轻量、可移植、将应用打包的技术。镜像运行后,产生的对象就是容器。相当于镜像运行后的实例。

类比虚拟机

  • 相同点
    • 共享物理资源
    • 生命周期类似
    • 内部可安装应用
    • 创建完成后物理存储在宿主机上(路径 /var/lib/docker/containers
  • 不同点
    • 虚拟机是完整独立的操作系统,容器是运行在宿主内核之上,只从bins/libs开始独立
    • 比虚拟机更加轻量

生命周期

生命周期

相关操作

  • 创建 docker create [OPTIONS] IMAGE [COMMAND] [ARG...] 利用镜像创建出一个Created 状态的待启动容器

    -t, --tty 分配一个伪TTY,也就是分配虚拟终端

    -i, --interactive 即使没有连接,也要保持STDIN打开

    --name 为容器起名,如果没有指定将会随机产生一个名称

    • [COMMAND]: 容器启动后,需要在容器中执行的命令,如ps、ls 等命令

    • [ARG...]: 执行 COMMAND 时需要提供的一些参数,如ps 命令的 aux、ls命令的-a等等

    E.g.

    docker create --name custom-container centos ps -A
    # 启动时执行 /bin/bash 常搭配-t使用
    docker create -it --name custom-container2 centos /bin/bash
    
  • 启动 docker start [OPTIONS] CONTAINER [CONTAINER...] 将创建(created)或关闭(exited)状态的容器启动

    -a, --attach 将当前shell的 STDOUT/STDERR 连接到容器上

    -i, --interactive 将当前shell的 STDIN连接到容器上

    E.g.

    # 查看列表
    docker ps -a
    # 使用容器ID选中STATUS是Created的容器启动, 并将当前终端连接到容器
    docker start -a 2zoi
    
  • 运行 docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

    -t, --tty 分配一个伪TTY,也就是分配虚拟终端

    -i, --interactive 即使没有连接,也要保持STDIN打开

    --name 为容器起名,如果没有指定将会随机产生一个名称

    -d, --detach 在后台运行容器并打印出容器ID

    --rm 当容器退出运行后,自动删除容器

    • [COMMAND]: 容器启动后,需要在容器中执行的命令,如ps、ls 等命令

    • [ARG...]: 执行 COMMAND 时需要提供的一些参数,如ps 命令的 aux、ls命令的-a等等

    P.S.

    • docker run 相当于 docker create + docker start –a 前台模式,自动连接命令行

    • docker run -d 相当于 docker create + docker start 后台模式,不连接命令行

    E.g.

    # 执行 ps -A 命令来列出所有的进程,没有-d,执行完 ps 后自动进入 exited 状态
    docker run centos ps -A
    # std输出容器id,ps -A 在后台执行,不会直接看到结果,执行完 ps 后自动进入 exited 状态
    docker run -d centos ps -A
    # std输出容器id,后台执行完 ps -A 后,由于 --rm 直接删除
    docker run --rm -d centos ps -A
    
  • 暂停 docker pause CONTAINER [CONTAINER...] 将 running 状态的容器切换到 paused 状态

  • 恢复 docker unpause CONTAINER [CONTAINER...] 将 paused 状态的容器切换到 running 状态

  • 关闭 docker stop [OPTIONS] CONTAINER [CONTAINER...] 将 paused 状态的容器切换到 exited 状态

    -t, --time int 关闭前,等待的时间,单位秒(默认 10s)

  • 强制关闭 docker kill [OPTIONS] CONTAINER [CONTAINER...] 强制并立即将一个或多个 paused 状态容器切换到 exited 状态

    -s, --signal string 指定发送给容器的关闭信号 (默认“KILL”信号)

    P.S.

    • stop 使用 SIGTERM 信号,如果设置了-t且超出时间,则使用 SIGKILL

    • kill 默认使用 SIGKILL 信号

    • 异常原因会导致容器关闭

  • 重启 docker restart [OPTIONS] CONTAINER [CONTAINER...] 将 running/exited/paused/created 状态容器重新进入 running状态

    -t, --time int 重启(关闭)前,等待的时间,单位秒(默认 10s)

  • 删除 docker (container) rm [OPTIONS] CONTAINER [CONTAINER...]

    -f, --force 强行删除容器(会使用 SIGKILL信号)

    -v, --volumes 同时删除绑定在容器上的数据卷

  • 检视 docker container inspect [OPTIONS] CONTAINER [CONTAINER...] 查看容器详情

    -f, --format string 利用特定Go语言的format格式输出结果

    -s, --size 显示总大小

    E.g.

    # 使用容器ID输出信息json
    docker container inspect 2zoi
    # 输出信息json中State字段的内容
    docker container inspect -f "{{json .State.Status}}" 2zoi
    
  • 日志 docker logs [OPTIONS] CONTAINER 容器主进程的输出STDOUT\STDERR

    --details 显示日志的额外信息

    -f, --follow 动态跟踪显示日志信息

    --since string 只显示某事时间节点之后的

    --tail string 显示倒数的行数(默认全部)

    -t, --timestamps 显示timestamps时间

    --until string 只显示某事时间节点之前的

  • 重命名 docker rename CONTAINER NEW_NAME

  • 连接 docker attach [OPTIONS] CONTAINER 将当前终端的标准输入输出流连接到容器内

    --no-stdin 不绑定STDIN

  • 执行命令 docker exec [OPTIONS] CONTAINER COMMAND [ARG...] 容器中允许一个命令

    -d, --detach 后台运行命令

    -i, --interactive 即使没连接容器,也将当前的STDIN绑定上

    -t, --tty 分配一个虚拟终端

    -w, --workdir string 指定在容器中的工作目录

    -e, --env list 设置容器中运行时的环境变量

容器与镜像的关系

容器与镜像

  • 提交 docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] 根据容器生成一个新的镜像

    -a, --author string 作者

    -c, --change list 为创建的镜像加入Dockerfile命令

    -m, --message string 提交信息,类似git commit -m

    -p, --pause 提交时暂停容器 (default true)

    E.g.

    # 启动一个容器
    docker run --rm -dit centos bash
    # 通过容器ID为容器安装软件
    docker exec -d 2zoi yum -y install net-tools
    # 通过容器ID提交生成一个新镜像
    docker commit -m 'install net-tools' 2zoi centos-net-tools:latest
    # 查看镜像列表,可发现刚刚生成的镜像
    docker images
    
  • 导出 docker export [OPTIONS] CONTAINER 将容器当前的文件系统导出成一个tar文件

    -o, --output string 指定写入的文件,默认是STDOUT

  • 导入 docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]] 从一个tar文件中导入内容创建一个镜像

    -c, --change list 为创建的镜像加入Dockerfile命令

    -m, --message string 导入时,添加提交信息

    P.S.: commitimport 构建出镜像的区别

    • 使用 history 查看分层信息可查出区别

      • commit 生成的镜像拥有多个层。保留了原本镜像的分层信息,后续操作在其上构建了新层 (保留历史信息)

      • import 只有一个层。将原本镜像的分层与操作后的内容合并为一个层 (无历史信息,创建全新)

    • 使用 inspect 查看详细信息中的 config 字段 与 RootFS 中的 Layers

      • commit 的镜像会保留并更新原始镜像的 config 数据,Layers 会保留并新增层

      • import 会丢失 config 字段数据,

生成镜像的层级inspect 详细信息 RootFS 中的 Layers 数组,按照 history 层级从底向上, 记录文件发生变动的层(即:只有 history 的层级中,文件发生变动的层才会在 RootFS 中的 Layers 数组里存在)。镜像中的每一层都是只读的

容器的层级create/run 会在镜像顶层的只读层上,再创建一个可读写层(联合文件系统,下方所有层的叠加,访问时访问的是前面所有层叠加的结果)。在执行 commit 之后(容器变成镜像),顶层的可读写层会转换成只读层

网络

容器与宿主,容器间的网络默认是隔离的

网络驱动模式

  • bridge network 模式(网桥):默认的网络模式。类似虚拟机的nat模式

    • 宿主机上需要单独的bridge网卡(新建bridge网络后,通过ifconfig可查看该网卡),如默认docker默认创建的docker0

    • 容器之间、容器与主机之间的网络通信,是借助为每一个容器生成的一对veth pair虚拟网络设备对,进行通信的。一个在容器上,另一个在宿主机上

    • 每创建一个基于bridge网络的容器,都会自动在宿主机上创建一个veth...虚拟网络设备(ifconfig可查看该虚拟网卡)

    • 外部无法直接访问容器。需要建立 端口映射 才能访问

      -P, --publish-all 将容器内部所有暴露端口进行随机映射,docker ps -a 查看映射情况

      -p, --publish list 手动指定端口映射 [HOST_IP]:[HOST_PORT]:CONTAINER_PORT

    • 容器借由veth虚拟设备通过如docker0这种bridge网络设备进行通信

    • 每一容器具有单独的IP

    • 容器间通信: 使用同一个bridge,可使用 http://容器名:暴露端口 进行访问

  • host network 模式(主机):容器与宿主机之间的网络无隔离,即容器直接使用宿主机网络,容器的IP就是宿主机的IP

    • 容器完全共享宿主机的网络。网络没有隔离。宿主机的网络就是容器的网络

    • 容器、主机上的应用所使用的端口不能重复。例如:如果宿主机已经占用了8090端口,那么任何一个host模式的容器都不可以使用8090端口了;反之同理

    • 外部可以直接使用宿主机IP+容器端口端口访问对应容器,不需要端口映射。此时启动容器与启动本地应用的感知一样

  • None network 模式:容器禁用所有网络。高度定制网络时使用该模式自行安装与配置

  • Overlay network 模式(覆盖网络): 利用VXLAN实现的bridge模式。常用于不同主机内容器的通信(虽然前两种也能实现,但多容器时,bridge容器IP过多且端口映射复杂,host容易端口占用且网卡压力大)

    Overlay

    • 在容器内网络层封装数据包时,额外多封装了一个IP头部。而后将报文提交到宿主机

    • 宿主机将报文作为VXLAN,再次封装,传输层增加了UDP头,网络层增加IP头,以此类推。而后进行发送

  • Macvlan network 模式:容器具备Mac地址,使其显示为网络上的物理设备。宿主机充当交换机,采用mac地址表,根据mac地址进行转发。容器对外相当于一台独立的设备

  • Container network 模式。容器使用其他容器的网络,来实现间的网络不隔离。容器1使用host,容器2使用Container则也为host;容器1为bridge,容器2使用Container则会与容器1同IP(使用容器1的veth pair)。若容器暴露相同端口,将由于端口占用而容器启动失败

P.S.:host模式性能最好,overlay需要再次封装,性能低于bridge

网络管理命令

  • 查看 docker network ls [OPTIONS] 查看已经建立的网络对象

    -f, --filter filter 过滤条件(如 'driver=bridge’)

    --format string 格式化打印结果

    --no-trunc 不缩略显示

    -q, --quiet 只显示网络对象的ID

    E.g. docker network ls -f 'driver=host' 查看 host 模式的网络对象列表

  • 创建 docker network create [OPTIONS] NETWORK 创建网络对象

    -d, --driver string 指定网络的驱动(默认 "bridge")

    --subnet strings 指定子网网段(如192.168.0.0/16、172.88.0.0/24)

    --ip-range strings 执行容器的IP范围,格式同subnet参数(subnet子集)

    --gateway strings 子网的IPv4 or IPv6网关,如(192.168.0.1)

    P.S.

    • host和none模式网络对象只能存在一个
    • docker自带的overlay 网络创建依赖于docker swarm(集群负载均衡)服务
    • 192.168.0.0/16(前16位固定,0.0-255.255) 192.168.8.0/24(0-255)

    E.g. 定制化一个bridge类型网络

    # 定制化网段 ,ip范围,网关地址
    docker network create --subnet 172.168.0.0/16 --ip-range 172.168.50.0/24 --gateway 172.168.50.1 my-bridge
    
  • 删除 docker network rm NETWORK [NETWORK...] 支持name或id

  • 检视 docker (network) inspect [OPTIONS] NETWORK [NETWORK...] 查看一个或多个网络的详细信息

    -f, --format string 根据format输出结果

  • 使用 docker run/create --network NETWORK 容器默认使用bridge网络

    E.g.

    # 使用自创建的网络启动FastDFS中的tracker服务, 端口映射 宿主机端口:容器端口
    docker run -d -p :22122:22122 --name tracker --net=my-net  -v /var/fdfs/tracker:/var/fdfs delron/fastdfs tracker
    # 使用Container模式 --network container:CONTAINER
    docker run 
    
  • 连接与断开 docker network connect/(disconnect) [OPTIONS] NETWORK CONTAINER host与overlay网络无法连接。none可以连接。none与bridge不能共存。overlay不能与其他模式共存

数据卷

为了解决容器内文件的存储与访问时产生的各种问题,引入了数据卷机制。

  • 数据卷存在于宿主机中,与容器隔离

  • 可利用数据卷解决容器与宿主,和容器间的数据共享问题

  • 容器启动初始化时,如果容器使用的镜像包含了数据,这些数据会拷贝到数据卷中

  • 容器对数据卷的修改是实时的

  • 数据卷变化不会影响镜像。数据卷独立与联合文件系统,镜像基于联合文件系统

挂载方式

在执行 docker create / run 时,使用 OPTION 声明数据卷挂载方式(声明路径必须是绝对路径)

  • bind mounts:将宿主机上的一个文件或目录被挂载到容器上(目录映射)

    方法1: -v, --volume参数 -v <宿主机文件或文件夹路径>:<容器中的文件或者文件夹路径> 自动在宿主机创建文件夹

    方法2: --mount type=bind,src=<宿主机文件或文件夹路径>,dst=<容器中的文件或者文件夹路径> 要求宿主机声明路径必须存在

  • volumes:数据卷对象在宿主机的映射, docker volume 统一管理,可理解为bind方式基础上做了额外封装

    方法1: -v, --volume参数 -v VOLUME-NAME:<容器中的文件或者文件夹路径> 名称不存在的volume对象会自动创建

    方法2: --mount type=volume,src=VOLUME-NAME,dst=<容器中的文件或者文件夹路径> 名称不存在的volume对象会自动创建

    volume对象管理

    # 查看对象列表
    docker volume ls
    # 创建
    docker volume create VOLUMENAME
    # 检视 - 可查看该数据卷的本地目录
    docker volume inspect VOLUMENAME
    # 删除未使用的对象
    docker volume prune
    # 删除
    docker volume rm VOLUMENAME[..VOLUMENAME]
    
  • tmpfs mounts:tmpfs 是一种基于内存的临时文件系统。tmpfs mounts 数据不会存储在磁盘上,而是宿主机的内存

    --mount type=tmpfs, dst=PATH

  • 使用其他容器的数据卷方式 --volumes from CONTAINER

数据卷挂载注意点

Docker的数据卷更多会是使用volumes方式

  • 使用bind方式,通过 --mount 创建时可能会出现异常
  • 数据卷对象可以使用 docker volume 进行管理

使用时需注意:

  • 如果挂载一个空的数据卷到容器中的一个非空目录中,那么这个目录下的文件会被复制到数据卷中(数据卷的初始化)
  • 如果挂载一个非空的数据卷到容器中的一个目录中,那么容器中的目录中会显示数据卷中的数据。如果原来容器中的目录中有数据,那么这些原始数据会被隐藏掉(已存在数据卷的优先)

仓库

存放镜像,并可使用pull下载镜像的环境 (DockerFile 使用 cloud 可以比仓库更便捷的构建镜像)

私有仓库相对于直接copy压缩包,更易于版本控制

仓库搭建

  • 安装docker

  • 获取创建仓库镜像 docker pull registry

  • 启动仓库(内部会有http服务)

    docker run -d -ti --restart always\  # 跟随docker服务一起重启
                --name my-registry\
                -p 8000:5000\  # 内部服务在5000端口,映射到宿主的8000上 - 本机IP:8000即为仓库地址
                -v /my-registry/registry:/var/lib/registry\  # 镜像存储在本地
    registry  # 镜像名称
    
  • 查看仓库镜像列表 curl <服务器IP>:8000/v2/_catalog

上传与下载

  • 上传

    • 重命名需要上传的镜像 docker tag IMAGE <服务器IP>:<端口>/IMAGE_NAME (注意:此处需要注明仓库地址)

    • 上传重命名的镜像 docker push <服务器IP>:<端口>/centos (注意:默认情况下为https服务,会出现异常)

    P.S.:处理HTTPS异常:将该仓库请求变更为http请求 修改docker配置文件 /etc/docker/daemon.json (mac地址 ~/.docker/daemon.json),添加内容解包添加 json { "insecure-registries":["<服务器IP>:<端口>"] }

    此时使用 docker image ls 可查看到镜像 <IP>:<端口>/镜像名

    通过请求 curl <服务器IP>:8000/v2/_catalog 可查看到上传完成的镜像

  • 下载 docker pull <服务器IP>:<端口>/IMAGE_NAME (注意:此处需要注明仓库地址,不表明默认从官方 docker hub 上拉取)

仓库的认证配置

  • 仓库认证
    • STEP0: 删除先前创建的无认证的仓库容器 docker rm -f my-registry P.S. 如需删除镜像还需删除数据卷,也可直接映射新仓库来继承其镜像
    • 创建存放认证用户名和密码的文件路径 mkdir /my-registry/auth -p
    • 创建密码验证文件。USERNAME和PASSWORD替换为设置的用户名和密码
      # 运行容器内的 htpasswd 来设置账号密码 写入指定路径
      docker run --entrypoint htpasswd registry -Bbn USERNAME PASSWORD > /my-registry/auth/htpasswd
      
    • 重新启动仓库镜像
      docker run -d -p 8000:5000 --restart=always --name docker-registry \
      -v /my-registry/registry:/var/lib/registry \  # 映射镜像文件夹
      -v /my-registry/auth:/auth \  # 映射密码文件夹
      -e "REGISTRY_AUTH=htpasswd" \  # 环境变量
      -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \  # 环境变量:认证方式
      -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \  # 环境变量:密钥路径
      registry
      
  • 上传与下载
    • 登录 docker login -u <username> -p <password> <IP>:<端口>
    • 执行上传 下载操作 (与不带认证的私有仓库操作一致)
    • 退出登录 docker logout <IP>:<端口>

DockerFile

包含 docker build 命令的文本文件,通常名称为 Dockerfile ,运行时会依次执行其中命令创建一个新的镜像

运行:docker build <Dockerfile文件所在文件夹路径> -t NAME:TAG P.S. 如果文件名不为 Dockerfile ,需使用 -f 指明文件名

官方镜像的dockerfile地址 https://github.com/docker-library/docs/open in new window,点击任意仓库文件夹后,打开README中Dockerfile超链接即可查看

构建

Dockerfile的构建(镜像 -> 临时容器 -> 镜像)类似于 docker commit 操作(容器 -> 镜像),其中 每个 FROM 外的命令会在原镜像上新增一层(dockerfile中的命令对应着 docker history 中的一层,FROM 对应着基础镜像的层级,可能为多个)

构建缓存:在二次构建时,若dockerfile未发生变动,则直接使用第一次构建的缓存(docker images 中存在的上一次构建的镜像)。若dockerfile发生变动,则变动处及后方都是重新执行(变动处开始不使用缓存,之前位置使用上次构建的镜像)。 在更新Dockerfile时,一般在文件末尾添加,不会变动到之前的内容,以防止二次初始化造成数据丢失

命令

dockerfile 命令官方文档open in new window

  • FROM: 指定基础镜像。在指定镜像上构建新的镜像

  • RUN: 构建镜像过程( docker build 过程)中需要执行的命令。可以有多条。在 docker build 时调用 RUN 中的命令

    # shell方式运行命令(子进程):RUN + 命令 (推荐)
    RUN echo 'test'
    # exec方式运行命令(当前进程):RUN + 命令数组
    RUN ["yum", "install", "-y", "net-tools"]
    

    说明: linux执行方式

    • shell方式执行 /bin/sh -c echo "test" ,此时会开辟子进程执行,当前窗口无法看到输出

    • exec方式执行 exec echo "test" ,此时会先kill当前在当前窗口执行,且执行完成后终端被结束(dockerfile中的环境变量会受影响 / 可使用 exec sh -c 避免)

  • CMD: 添加启动容器时需要执行的命令( docker inspect 检视镜像CMD信息 Config.Cmd 字段 )。多条只有最后一条生效。可以在启动容器时被覆盖和修改(当执行 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 时,没有提供 COMMAND ,将默认执行 Config.Cmd 中的内容)

    
    # 命令(子进程)将以shell方式运行:CMD + 命令
    CMD echo 'test'
    # 命令(当前进程)将exec方式运行:CMD + 命令数组 (推荐,通常使用CMD启动程序主程序,绑定容器生命周期)
    CMD ["yum", "install", "-y", "net-tools"]
    # 后续内容作为 ENTRYPOINT 命令的参数
    CMD ["params1", "params2"]
    
  • ENTRYPOINT: 同CMD,但这个一定会被执行,不会被覆盖修改

    # 命令(子进程)将以shell方式运行:ENTRYPOINT + 命令
    ENTRYPOINT echo 'test'
    # 命令(当前进程)将exec方式运行:ENTRYPOINT + 命令数组 (推荐,通常使用ENTRYPOINT启动程序主程序,绑定容器生命周期)
    ENTRYPOINT ["yum", "install", "-y", "net-tools"]
    
  • LABEL: 为镜像添加对应的数据。docker inspect 检视镜像Labels信息 Config.Labels 字段。版本、名称、协议等说明信息

  • MAINTAINER: 表明镜像的作者。将被遗弃,被LABEL代替。docker inspect 检视镜像Author信息 Author 字段

  • EXPOSE: 设置对外暴露的端口。docker inspect 检视镜像暴露端口 Config.ExposedPorts 字段

    # 暴露端口(默认TCP)
    EXPOSE 6379
    # 指定端口协议
    EXPOSE 80/tcp
    EXPOSE 80/udp
    
  • ENV: 设置执行命令时的环境变量,并且在构建完成后,仍然生效

  • ARG: 设置只在构建过程( docker build 过程 )中使用的环境变量(如 docker build 时传入的参数值),构建完成后,将消失

    使用arg动态接收username值 docker build --build-arg username=what_user .

    FROM busybox
    USER ${username:-some_user}
    ARG username
    USER $username
    
  • ADD: 将本地文件或目录拷贝到镜像的文件系统中。能解压特定格式文件,能将URL作为要拷贝的文件

  • COPY: 将本地文件或目录拷贝到镜像的文件系统中。

  • VOLUME: 添加数据卷(自动创建数据卷)如:docker run -dit redis ,由于其dockerfile内设置了VOLUME,将自动创建数据,等效为 docker run -dit -v /data redis

  • USER: 指定以哪个用户的名义执行RUN, CMD 和ENTRYPOINT等命令

  • WORKDIR: 设置工作目录。明确 RUN 的工作路径

  • ONBUILD: 如果制作的镜像被另一个Dockerfile使用(创建出的镜像被另一个dockerfile FROM),将在那里被执行Docekrfile命令

  • STOPSIGNAL: 设置容器退出时发出的关闭信号。kill -l 可查看全部关闭信号

  • HEALTHCHECK: 设置容器状态检查。设置指定时间间隔执行指定命令用于检测运行状态并记录

  • SHELL: 更改执行shell命令的程序。Linux的默认shell是["/bin/sh", "-c"],Windows的是["cmd", "/S", "/C"]。例如 SHELL ["powershell", "-command"] 切换到powershell

    FROM microsoft/windowsservercore
    
    # Executed as cmd /S /C echo default
    RUN echo default
    
    # Executed as cmd /S /C powershell -command Write-Host default
    RUN powershell -command Write-Host default
    
    # 切换到 powershell
    SHELL ["powershell", "-command"]
    RUN Write-Host hello
    
    # 切换会cmd
    SHELL ["cmd", "/S", "/C"]
    RUN echo hello
    

Docker Compose

docker compose用于解决容器固定化流程启动、多容器启动等容器启动的问题。通常名称为 docker-compose.yaml

Docker Compose File 配置启动文件,配置镜像/Dockerfile,网络等信息

Docker Compose Cli - 与docker cli类型

与Dockerfile的不同: Dockerfile用于构造镜像。镜像在运行成容器时,需要使用cli管理其网络,数据卷,生命周期(容器起停)。Docker Compose可以对这些内容进行管理(与Docker cli类型,但可一次管理多个)

安装

  • windows 与 mac 系统的 docker desktop 自带docker compose

  • Linux 系统需要额外安装

    • sudo curl -L https://github.com/docker/compose/releases/download/版本/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose

    • sudo chmod +x /usr/local/bin/docker-compose

    • 确定是否安装成功 docker-compose --version

docker compose file

docker compose file 采用yaml进行配置。语法目前共3个大版本,且向后兼容(新版本docker引擎支持老版本语言)

  • 常用配置项
    • version(必须声明): 指定Docker Compose File版本号

    • services(必须声明): 定义多个服务并配置启动参数

      • build: 容器使用 dockerfile 启动时,dockerfile 相关内容

        version: '3'
        services:
            webapp:  # 服务名
                build:
                    context: ./dir  # dockerfile所在路径
                    dockerfile: Dockerfile-alternate  # dockerfile名称
                    args:
                        buildno: 1  # dockerfile ARG参数
        
      • command: 重写 inspect 镜像 CMD参数(一些镜像默认配置了CMD)

      • container_name: 容器名称

      • deploy: 多台主机的多容器部署使用

      • depends_on: 容器间的依赖关系,控制容器启动顺序

        version: '3'
        services:
            webapp:  # 服务名
                build: .  # 使用dockerfile启动,声明 dockerfile 路径
                depends_on:  # 声明该服务依赖的其他容器,在下列容器启动后再启动
                    - redis
                    - db
            redis:
                image: redis  # 使用镜像启动,声明镜像名
            db:
                image: postgres  # 使用镜像启动,声明镜像名
        
      • entrypoint: 重写 inspect 镜像 ENTRYPOINT 参数重写(一些镜像默认配置了ENTRYPOINT)

      • env_file: 环境变量文件

        env_file: .env  # 支持单文件导入
        env_file:  # 支持多文件导入
            - ./common.env
            - ./apps/web.env
            - ./opt/secrets.env
        
      • environment: 环境变量

        environment:
            - FLASK_ENV=development
            - SECRET=****
        
      • expose: 容器暴露端口,此配置项不做映射(一些镜像默认绑定了数据卷)

        expose:
            - "5000"
            - "8000"
        
      • ports: 容器暴露端口,并进行映射(一些镜像默认绑定了数据卷)

        ports:
            - "3000"  # 暴露3000 做随机映射
            - "3000-3005"  # 暴露3000-3005 做随机映射
            - "8000:8000"  # 8000映射8000
        
      • image: 同级含有build,则表示dockerfile构建出的镜像的名称。否则,表示启动指定名称的镜像

      • volumes: 绑定数据卷

        P.S.

        • 一些镜像默认绑定了数据卷,不进行变动时无需再此处再次声明
        • 在不进行声明时,更新 compose file 后使用 up 而触发容器重构,不会更新数据卷。但 down 会更新数据卷(可能导致数据丢失)
        version: "3.2"
        services:
          web:
            image: nginx:alpine
            volumes:  # 引用声明的数据卷
              - type: volume
                source: mydata
                target: /data
                volume:
                    nocopy: true
              - type: bind
                source: ./static
                target: /opt/app/static
        
          db:
            image: postgres:latest
            volumes:
              - "/var/run/postgres/postgres.sock:/var/run/postgres/postgres.sock"
              - "dbdata:/var/lib/postgresql/data"
        
        volumes:  # 数据卷声明
          mydata:  # 数据卷名1
          dbdata:  # 数据卷名2
        
      • restart: 重启规则

        restart: "no"
        restart: always
        restart: on-failure
        restart: unless-stopped
        
    • volumes: 声明或创建在多个服务中共同使用的数据卷对象

    • networks: 定义在多个服务中共同使用的网络对象

      P.S.: compose中多服务的相互访问:使用同一个网络,访问时直接使用 http://<服务名>:<端口>` 即可

    • configs: 声明将在本服务中要使用的一些配置文件(多镜像共用的全局配置文件)

    • secrets: 声明将在本服务中要使用的一些秘钥、密码文件(密码等敏感信息,写入文件,用该字段导入)

    • x-***: 自定义配置。主要用于复用相同的配置(多镜像在compose file中使用相同的配置,用此进行抽象)

案例

flask项目环境搭建

flask代码位于服务器 /code/flaskapp 文件夹内,并包含 requirements.txt 依赖包说明文件

  • 编写 dockerfile

    # 获取python镜像 查看docker library官方python镜像,可选alpine(linux内核轻量版本)
    FROM python:apline3.6
    
    # 服务端代码添加到镜像 ADD/COPY 本地文件夹到容器内指定文件夹
    COPY ./flask-web-code /code
    
    # 安装服务端依赖环境
    WORKDIR /code  # 容器内cd
    RUN pip install -r requirements.txt
    
    # 运行 - 设置CMD 执行服务程序 推荐exec方式
    CMD ["python", "app.py"]
    
  • (可选)构建镜像 docker build . -t my-flask-img(此处不进行,在 compose 加载 dockerfile 时也会自动构建)

  • 编写 docker compose file docker-compose.yaml

    version: "3.6"
    service:
        # flask服务
        flask-web:
            build: .  # dockerfile位于当前文件夹
            ports:
                - "5000:5000"
            container_name: flask-web  # 可选,指定运行后的容器名称
            networks:  # 可选,引用声明的网络,不指定默认创建一个桥接网络用于services内所有容器,实现容器间通信
                - web
        # redis服务
        redis:
            image: redis # 该镜像已自己暴露6379
            # 如需宿主机以外的服务访问,需要配置端口映射:ports
            # 此处只需要flask服务访问,不做端口映射
            container_name: redis  # 可选,指定运行后的容器名称
            networks:  # 可选,引用声明的网络,不指定默认创建一个桥接网络用于services内所有容器,实现容器间通信
                - web
            volumes:  # 可选。防止 compose down 导致的镜像数据卷重置
                - redis-data:/data  # 数据卷名: 路径 (路径通过inspect查看)
    
    # 可选 声明网络,供services引用,services内不指定默认创建一个桥接网络用于services内所有容器,实现容器间通信
    networks:
        web:  # 网络名
        driver: "bridge"
    
    # 可选 - 为了避免 compose down 时的数据丢失,一般都会声明
    volumes:
        redis-data:  # 数据卷名称
        driver: "local"
    
  • 检测当前文件夹内的 compose file 是否存在问题 docker-compose config

  • 启动当前文件夹内的 compose file 。更新 compose file 后,执行 up 会重新运行

    • 阻塞式启动 docker-compose up
    • 守护进程式启动 docker-compose up -d
  • 停止

    • docker-compose kill
    • docker-compose pause
    • docker-compose stop
    • docker-compose down 会删除容器与网络,并影响数据卷( compose 未声明数据卷情况下,若镜像声明了数据卷,会自动创建,down 后该数据卷不再使用,下次启动时新创建数据卷。可能引起数据丢失,一般是不再使用此 compose 时才使用)

单宿主机的ELK系统

日志数据处理分析平台,ES,Logstash,Kibana。Logstash(运输日志,将日志通过管道传输到对应服务,端口5000)获取日志存储到ES(存储日志,存储Logstash传输内容,端口9200),Kibana(呈现,提供一个前端页面,端口5601)提供页面对ES数据进行查看与管理

  • 注意点

    • ES,Logstash 多开提高吞吐量
    • Logstash暴露5000端口用于写入,并需连接9200端口的ES
    • ES需要暴露9200端口写入
    • Kibana需要暴露5601端口用于访问,并需要连接9200端口
    1. 获取镜像 在es官网open in new window点击复制按钮,复制拉取 ES,Logstash,Kibana 镜像的命令
    # 指定版本则使用此方式: elasticsearch:x.x.x
    docker pull docker.elastic.co/elasticsearch/elasticsearch:sha256-xxx
    docker pull docker.elastic.co/kibana/kibana:sha256-xxx
    docker pull docker.elastic.co/logstash/logstash-oss:sha256-xxx
    
    1. es官网open in new window点击打开按钮,查看运行es镜像的文档。此处已6.2版本为例,文档中的 compose fileopen in new window 可运行一个es集群
    version: '2.2'
    services:
        elasticsearch:
            image: docker.elastic.co/elasticsearch/elasticsearch:6.2.4
            container_name: elasticsearch
            environment:
                - cluster.name=docker-cluster  # 集群名,确保两个es在同一集群
                - bootstrap.memory_lock=true  # 内存锁,防止内存无限消耗
                - "ES_JAVA_OPTS=-Xms512m -Xmx512m"  # 内存最小与最大范围
            ulimits:  # 内存锁设置权限 - 与内存锁一起出现,不然会报错
                memlock:
                    soft: -1
                    hard: -1
            volumes:  # 使用数据卷保证 down 后数据不会丢失
                - esdata1:/usr/share/elasticsearch/data
            ports:  # 端口映射只打开一个,两个都可以访问到
                - 9200:9200
            networks:  # 设置同一个网络
                - esnet
        elasticsearch2:
            image: docker.elastic.co/elasticsearch/elasticsearch:6.2.4
            container_name: elasticsearch2
            environment:
                - cluster.name=docker-cluster  # 集群名,确保两个es在同一集群
                - bootstrap.memory_lock=true
                - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
                - "discovery.zen.ping.unicast.hosts=elasticsearch"  # 设置host与1的一致,以达成集群效果。此处为1的默认值
            ulimits:
                memlock:
                    soft: -1
                    hard: -1
            volumes:  # 使用数据卷保证 down 后数据不会丢失
                - esdata2:/usr/share/elasticsearch/data
            networks:
                - esnet
    
    volumes:
        esdata1:
            driver: local
        esdata2:
            driver: local
    
    networks:
        esnet:
    
    1. 测试ES服务
    # 启动 - 失败会自动重试
    docker-compose up -d
    
    # 查看是否运行成功
    docker ps -a
    
    # 查看compose日志 需在 compose file 目录中执行
    docker-compose logs  # 可以查看启动过程中可能出现的异常
    
    # 测试请求ES
    curl 127.0.0.1:9200
    

    P.S.: 可能出现的问题

    • max virtual memory areas vm.max_map_count [65536] is too low, increase to at least [262144]

      根据文档open in new window,需要修改系统配置

      # linux /etc/sysctl.conf
      sysctl -w vm.max_map_count=262144
      
      # mac
      sysctl -w vm.max_map_count=262144
      
    1. 查看Logstash的配置。此处以官方文档6.2open in new window为例,确认配置 pipeline(日志的来源与去向)及 settings(Logstash配置项)是否需要修改。由于默认es请求地址http://elasticsearch:9200 与实际配置的内网访问要求一致(http://<服务名>:<端口>),因此无需修改(其中x-pack相关配置需要付费使用,可进行异常监控与邮件通知等功能)
    1. compose file 中配置 Logstash 服务。完成后使用 docker-compose config 检测完成后。使用 dicker-compose up -d 启动
    ...重复内容省略...
    
    services:
        ...重复内容省略...
    
        logstash:
            image: docker.elastic.co/logstash/logstash:6.2.4
            container_name: logstash
            environment:
                - "LS_JAVA_OPTS=-Xms256m -Xmx256m"  # 设置内存使用量
            networks:
                - esnet  # 与es使用同一网络以保证可以相互访问
            depends_on:  # 保证es服务启动后再启动该服务
                - elasticsearch
                - elasticsearch2
    ...重复内容省略...
    
    1. 查看Kibana配置。确认官方文档6.2open in new window中的默认配置是否需要修改。由于默认es请求地址http://elasticsearch:9200 与实际配置的内网访问要求一致(http://<服务名>:<端口>),因此无需修改
    1. compose file 中配置 Kibana 服务
    ...重复内容省略...
    
    services:
        ...重复内容省略...
    
        kibana:
            image: docker.elastic.co/kibana/kibana:6.2.4
            container_name: kibana
            ports:
                - "5601:5601"  # 端口映射用于内部web服务在外部可进行启动
            networks:
                - esnet  # 与es使用同一网络以保证可以相互访问
            depends_on:  # 保证es服务启动后再启动该服务
                - elasticsearch
                - elasticsearch2
    
    ...重复内容省略...
    
    1. 启动ELK
    # 检测配置文件是否有语法问题
    docker-compose config
    # 启动
    docker-compose up -d
    # 查看容器情况
    docker ps -a
    # 查看日志
    docker-compose log
    # 查看ELK是否正常
    curl 127.0.0.1:9200  # 查看es
    curl 127.0.0.1:5601  # 查看kibana,可通过浏览器访问前端页面
    

P.S. logstash集群配置

...重复内容省略...
    
services:
    ...重复内容省略...

    logstash2:  # 更改服务名称防止重复
        image: docker.elastic.co/logstash/logstash:6.2.4
        container_name: logstash2  # 更改容器名称防止重复
        environment:
            - "LS_JAVA_OPTS=-Xms256m -Xmx256m"
        networks:
            - esnet
        depends_on:
            - elasticsearch
            - elasticsearch2

    ...重复内容省略...

多宿主机的ELK系统

swarm: docker内置的集群管理工具,使用overlay网络,支持负载均衡

此处已两台宿主机为例,通过 swarm 实现容器间通信

  • swarm的使用

    • swarm 初始化。宿主机A 执行 docker swarm init,得到加入 swarm 命令

      docker swarm join --token SWMTKN-1-******* 10.211.55.7:2377
      
    • 宿主机A查看当前节点 docker node ls。宿主机A在初始化时已自动加入

      ID          HOSTNAME        STATUS          AVAILABILITY           MANAGER STATUS(Leader表示主节点)       ENGINE VERSION
      宿主机A的信息
      
    • 宿主机B加入。执行 swarm 初始化得到的命令 docker swarm join --token SWMTKN-1-******* 10.211.55.7:2377

    • 宿主机A查看当前节点 docker node ls。可查看到到两条数据

    • 查看网络信息 docker network ls,可发现 docker_gwbridgeingress

      ID      NAME                DRIVER      SCOPE
      xxx     docker_gwbridge     bridge      local  # 用于容器访问外部网络
      xxx     ingress             overlay     swarm  # 用于容器间/集群间通信
      
  • 多宿主机compose 与 单宿主机compose 的不同

    • 使用 swarm 部署跨主机服务,不支持dockerfile,只能使用image镜像。dockerfile构建镜像必须在 compose 外单独执行生成出可用镜像

    • 一个服务可启动多个容器

    • compose file + docker stack/service (不使用单宿主机的 compose file + compose cli)

    • 部分 compose 配置项在 使用 stack 在 swarm 中无效。如 build / container_name / ulimits / depends_on

    • 使用 docker stack deploy 启动,而不是 docker-compose up

    • compose 必须配置 deploy ,且需要版本 3 或以上。以下为deploy的常用子配置项,详见官方文档open in new window

      services:
          frontend:
              image: example/webapp
              ports:
                  - "8080:80"
              deploy:
                  mode: replicated  # 默认mode就是replicated / global模式无法指定数量,而是在所有docker节点上都运行一个容器
                  replicas: 2  # 指定镜像启动多少个容器(所有docker节点上一共运行的容器数量)
                  endpoint_mode: vip
      
      • mode: 支持 replicated(指定启动数量,swarm自行判断容器运行在哪台宿主机,想控制只能是用constraints) / global(每个宿主机启动1个)

      • placement: 设置约束等

        • constraints 容器在满足约束的宿主机上运行,可使用==!=
          • 在指定 Node ID 的节点上运行容器 node.id==2ivku8v2gvtg4
          • 在 Node hostname 不是指定名称的节点上运行容器 node.hostname!=node-2
          • 在指定 Node role (manager-leader/worker-非leader) 的节点上运行容器 node.role==manager
          • 在指定 Node operating system 的节点上运行容器 node.platform.os==windows
          • 在指定 Node architecture 的节点上运行容器 node.platform.arch==x86_64
          • 在指定 User-defined node labels 的节点上运行容器 node.labels.security==high
          • 在指定 Docker Engine's labels 的节点上运行容器 engine.labels.operatingsystem==ubuntu-24.04
      • resources: 限制容器使用资源

        services:
          frontend:
            image: example/webapp
            deploy:
              resources:
                limits:
                  cpus: '0.50'
                  memory: 50M
                  pids: 1
              reservations:
                cpus: '0.25'
                memory: 20M
        
  • 多宿主机ELK compose file 的编写

    • deploy 配置

      version: '3.6'  # deploy 必须 3或以上
      services:
        elasticsearch:
          ...重复内容省略...
          deploy:
            placement:
              constraints:
                - node.role == manager  # 让此容器在主节点运行
        elasticsearch2:
          ...重复内容省略...
          deploy:
            placement:
              constraints:
                - node.role == worker  # 让此容器在从节点运行
        logstash:
          ...重复内容省略...
          deploy:
            replicas: 2  # 启动两台,mode默认为replicated,可省略
        logstash2:
          ...重复内容省略...
          deploy:
            replicas: 2  # 启动两台,mode默认为replicated,可省略
        kibana:
          ...重复内容省略...
          deploy:
            placement:
              constraints:  # web服务运行一个就够
                - node.role == manager  # 让此容器在主节点运行
      
    • 网络配置 - 将使用网络驱动修改为overlay

      networks:
        esnet:
          driver: "overlay"
      
    • 移除 ulimits / container_name 等不支持参数

      version: '3.6'
      services:
        elasticsearch:
          image: docker.elastic.co/elasticsearch/elasticsearch:6.2.4
          # container_name: elasticsearch  # 移除
          environment:
            - cluster.name-docker-cluster
            - bootstrap.memory_lock=false  # 由于ulimits无法使用,设置为false,保证容器正常启动
            - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
          # ulimits:  # 移除
          #   memlock:
          #     soft: -1
          #     hard: -1
          volumes:
            - esdata1:/usr/share/elasticsearch/data
          ports:
            - 9200:9200
          networks:
            - esnet
          deploy:
            placement:
              constraint:
                node.role == manager
        elasticsearch2:
          image: docker.elastic.co/elasticsearch/elasticsearch:6.2.4
          # container_name: elasticsearch2  # 移除
          environment:
            - cluster.name=docker-cluster
            - bootstrap.memory_lock=false  # 由于ulimits无法使用,设置为false,保证容器正常启动
            - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
            - "discovery.zen.ping.unicast.hosts=elasticsearch"
          # ulimits:  # 移除
          #   memlock:
          #     soft: -1
          #     hard: -1
          volumes:
            - esdata2:/usr/share/elasticsearch/data
          networks:
            - esnet
          deploy:
            placement:
              constraints:
                - node.role == worker
        logstash:
          image: docer.elastic.co/logstash/logstash:6.2.4
          environment:
            - "LS_JAVA_OPTS=-Xms256m -Xmx256m"
          # container)name: logstash  # 移除
          networks:
            - esnet
          # depends_on:  # 移除
          #   - elasticsearch
          #   - elasticsearch2
          deploy:
            replicas: 2
        logstash2:
          image: docer.elastic.co/logstash/logstash:6.2.4
          environment:
            - "LS_JAVA_OPTS=-Xms256m -Xmx256m"
          # container)name: logstash2  # 移除
          networks:
            - esnet
          # depends_on:  # 移除
          #   - elasticsearch
          #   - elasticsearch2
          deploy:
            replicas: 2
        kibana:
          image: docker.elastic.co/kibana/kibana:6.2.4
          # container_name: kibana  # 移除
          ports:
            - "5601:5601"
          networks:
            - esnet
          # depends_on:  # 移除
          #   - elasticsearch
          #   - elasticsearch2
      
      volumes:
        esdata1:
          driver: local
        esdata2:
          driver: local
      
      networks:
        esnet:
          driver: 
      
    • 检测语法异常 docker-compose config

  • 启动 docker stack deploy -c [compose file] [stack_name]。使用docker ps -a查看运行效果

    docker stack deploy -c docker-compose.yaml elk
    
  • 查看服务列表 docker service ls

  • 查看指定服务的日志 docker service logs elasticsearch(服务名) [-f (与tail -f类似)]。(由于容器反复重启失败,stack会自动移除并创建新容器,所以不能查看容器日志docker logs,而是查看服务日志docker service logs)

  • 删除stack docker stack rm [stack_name] 。容器会依次关闭并删除,需要一定时间

  • 重启,先 stack rm 删除stack,再启动 stack deploy -c 并创建stackstackss

  • 测试:swarm的端口映射,每个 docker node 的IP都可以访问到对应服务

    • ES curl 127.0.0.1:9200
    • kibana 浏览器访问 IP:5601

Python运行环境

Pycharm连接docker内的python环境

Pycharm通过配置远程docker服务,服务器2375端口连接docker服务(不是容器),在docker中获取镜像,创建python解释器容器

Pycharm配置sftp服务,将本地代码传到docker所在服务器,通过docker数据卷映射到容器

  • docker服务器修改docker配置文件 /etc/docker/daemon.json (如果没有该文件则手动创建),供pycharm远程连接

    {
      "hosts": [
        "tcp://0.0.0.0:2375"  // 在 hosts 中增加该行
        "unix:///var/run/docker.sock"  // 本地连接(默认),如果 hosts 中没有则手动添加该行
      ]
    }
    
  • 重启 docker 使配置生效 service docker restart

  • 配置Pycharm添加远程docker容器内的解释器 Preferences -> Python Interpreter -> add... -> Docker -> Server: New... -> TCP socket 填写tcp://<服务器IP>:2375