前端的Docker学习记录

Docker简介

  • Docker 是一个应用打包分发部署的工具,可以使应用部署更加轻量,可移植,可扩展,可以理解为一个轻量的虚拟机
    • 打包:就是把你软件运行所需的依赖、第三方库、软件打包到一起,变成一个安装包
    • 分发:你可以把你打包好的“安装包”上传到一个镜像仓库,其他人可以非常方便的获取和安装
    • 部署:拿着“安装包”就可以一个命令运行起来应用,自动模拟出一模一样的运行环境,不管是在Windows/Mac/Linux
  • docker架构图
  • docker client: 即docker命令行工具
  • docker host: 宿主机,docker daemon的运行环境服务器
  • docker daemon: docker的守护进程,docker client通过命令行与docker daemon交互
  • image: 镜像,可以理解为安装包,可以方便的进行传播和安装
  • container: 容器,镜像的运行实例,每个软件运行环境都是独立的,隔离的
  • registry: 镜像仓库,可以从镜像仓库拉取和推送镜像

底层原理

docker底层使用了一些linux内核的特性,namespacecgroupsunionFS

namespace

  • namespace,也叫命名空间,名称空间,它表示一个标识符的可见范围。一个标识符可在多个名字空间中定义,它在不同名字空间中的含义是互不相干的。这样,在一个新的名字空间中可定义任何标识符,它不会与任何已有的标识符发生冲突,因为已有的定义都处于其他命名空间中
  • docker使用linux namespace构建隔离的环境,它由以下namespace组成
    • pid:隔离进程
    • net:隔离网络
    • ipc:隔离IPC
    • mnt:隔离文件系统挂载
    • uts:隔离hostname
    • user:隔离uid/gid

cgroups

  • cgroups,是控制组群(control groups)的简写,是用来限制、控制与分离一个进程组的资源(如CPU、内存、磁盘输入输出等)
  • cgroups功能:
    • 资源限制:设置内存限制,包括虚拟内存
    • 优先级:一些资源可以得到大量的CPU或磁盘IO吞吐量
    • 结算:用来度量系统实际用了多少资源
    • 控制:冻结组或检查点和重启动

unionFS

  • unionFS(Union file systems)是一种分层、轻量级并且高性能的文件性能,支持对文件系统的修改作为一次提交来一层层的叠加。docker的镜像与容器就是分层存储,可用的存储引擎呦aufs,overlay等

镜像

  • 镜像是一份用来创造容器的配置文件,而容器可以视作最小型的一个操作系统
  • docker的镜像和容器都使用了unionFS做分层存储,镜像作为只读层是共享的,而容器在镜像之上附加了一层可写层,最大程度地减少了空间的浪费
  • 镜像的相关命令
    • 镜像拉取:docker pull node:alpine
    • 查看镜像信息:docker inspect node:alpine
    • 列出所有镜像:docker images
    • 镜像打包:docker build -t docker-app:v1.0.0
      • -t:设置镜像名字和版本号

Dockerfile

  • Dockerfile是docker构建镜像的配置文件,比如一个简单的Dockerfile如下
    FROM node:16
    MAINTAINER songlh
    
    ADD . /app
    WORKDIR /app
    
    RUN npm install pnpm -g
    RUN pnpm install
    
    CMD pnpm run dev
  • 常用指令
  • FROM:表示基于一个已有的基础镜像,FROM <image> [AS <name>]
  • MAINTAINER:声明dockerfile镜像构建的作者
  • ADD:表示把宿主机的文件或目录加入到镜像的文件系统,ADD [--chown=<user>:<group>] <src>... <dest>
  • RUN: 在镜像中执行命令,由于ufs的文件系统,它会在当前镜像的顶层新增一层,RUN <command>
  • CMD: 指定容器如何启动,一个Dockerfile中只允许有一个CMD
  • WORKDIR:设置工作目录
  • ENV:设置环境变量

容器

  • docker run:创建容器
    • docker run -p 8080:8080 --name docker-hello docker-app:v1.0.0表示基于docker-app镜像的v1.0.0版本创建一个容器并在本地的8080端口运行,容器名字叫docker-hellp
    • -p host-port:container-port:宿主机与容器端口映射,方便容器对外提供服务
    • --name:为容器指定名称
    • -d:后台运行
    • --rm:当停止容器时自动清除容器
  • docker stop:停止容器
  • docker rm:删除容器
  • docker exec -it container-name:进入容器环境
  • docker ps:列出所有容器
  • docker port:查看容器端口映射
  • docker stats:查看容器资源占用

目录挂载

  • 按照目前已有知识,如果改了项目代码不会立刻生效,需要重新build和run,很麻烦,而且容器产生的数据,如果容器删除了就会没有,目录挂载就是为了解决这些问题
  • 目前的挂载方式
    • bind mount:直接把宿主机目录映射到容器内,适合挂载代码目录和配置文件,可挂载到多个容器上
    • volume:由容器创建和管理,创建在宿主机,所以删除容器不会丢失,官方推荐,更高效,Linux文件系统,适合存储数据库数据。可挂载到多个容器上
    • tmpfs mount:适合存储临时文件,存储在宿主机内存中。不可多容器共享

bind mount

  • bind mount是通过-v参数来绑定宿主机目录,比如将外部的html文档挂载到Nginx容器的根目录下
    • docker run -v ~/html:/usr/share/nginx/html -p 81:80 -d --name nginx_bind nginx:latest
  • 这种方式的缺点就是被挂载的宿主机目录(或文件)不受保护,任何容器都可以随意修改

volume

  • volume也是一个文件,但是这个文件是在docker的管控范围内,docker可以通过挂载的设定来控制容器对volume的读写权限
  • 通过docker volume create volume-name创建一个Volume,实际上是在docker的/var/lib/docker/volumes/文件夹内创建一个相同名字的文件夹来保存数据
  • 比如设置一个只能读取volume
    • docker run --mount type=volume,source=nginx-volume,destination=/usr/share/nginx/html,readonly -p 82:80 -d --name nginx_volume nginx:latest

tmpfs mount

  • tmpfs挂载是临时的,仅保留在主机内存中。当容器停止时,tmpfs挂载被移除,写入的文件不会被持久化
  • docker run --mount type=tmpfs,destination=/usr/share/nginx/html -p 83:80 -d --name nginx-tempfs nginx:latest
  • tmpfs因为不是持久化,一般不使用

容器通信

  • 容器间的通信根据媒介可以分为:volume共享通信、网络通信
  • 根据通信范围可以分为:同主机通信、跨主机通信

网络通信

  • Docker的网络通信模型分为以下几种,在安装Docker以后,会默认创建三种网络,可以通过docker network ls查看
    • bridge:为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,默认为该模式
    • host:容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口
    • none:容器有独立的network namespace,但并没有对其进行任何网络设置,如分配veth pair和网桥连接,IP等
    • overlay:可以连接多个docker守护进程或者满足集群服务之间的通信,适用于不同宿主机上的docker容器之间的通信
    • macvlan: 可以为docker容器分配MAC地址,使其像真实的物理及一样运行
  • Docker内置的bridge network,也就是docker0接口所属的network,所有未指定network的容器,默认连接到此network中,其网段未172.17.0.1/16,所以两个未进行任何连接操作的容器是可以通过IP地址互相通信的,因为他们同在一个network下,但通信只能通过IP地址进行,不可以通过容器名通信
  • 创建自定义网络:docker network create custom_network
  • 查看网络模式:docker network ls
  • 通过自定义网络创建容器:docker run -di --name docker-app --net custom_network docker-app:v1.0.0
  • 查看容器的网络信息:docker inspect 容器名称|ID,然后在NetworkSettings节点中可以看到
  • 为容器连接新的网络:docker network connect 网络名称 容器名称
  • 断开网络:docker network disconnect 网络名称 容器名称

docker-compose

  • docker-compose是用于定义和运行多容器Docker应用程序的工具。通过compose,您可以使用YML文件来配置应用程序需要的所有服务,然后使用一个命令就可以从YML文件配置中创建并启动所有服务
  • 使用分三步
      1. 使用Dockerfile定义应用程序的环境
      1. 使用docker-compose.yml定义构成应用程序的服务,这样它们可以在隔离环境中一起运行
      1. 最后,执行docker-compose up命令启动并运行整个应用程序
  • 比如运行一个web项目和redis,可以编写一个如下的docker-compose.yml文件
    version: "3"
    
    services:
      app:
        build: ./
        ports:
          - 80:8080
        volumes:
          - ./:/app
      redis:
        image: redis:5.0.13
        volumes:
          - redis:/data
    volumes:
      redis:
  • version:指定本yml依从的compose哪个版本指定的
  • build: 指定构建镜像上下文路径
  • image:指定启动容器的镜像
  • volumes:卷挂载路径设置,如果跨多个服务并重用挂载卷,可以在volumes关键字中命名挂载卷
  • ports:暴露端口信息

参考资料