Docker

Docker

参考

本文由于平时用作个人总结,参考了许多文章但因时间较久难以对应寻找,如有引用请见谅并联系我添加引用。

Dokcer概述

Motivation

  • 环境管理复杂 -> (一个应用牵涉到太多环境配置 若开发和生产环境都需要一一配置 不仅效率极低而且容易出错且难以跨平台 难以管理) -> Docker相当于将应用及其运行环境一起打包交付成镜像 且非常轻量级

  • 云计算时代 硬件管理问题解决 中间件相关问题依然存在

    虚拟化手段的变化 (虚拟化手段用于满足用户按需使用以及保证可用性和隔离性)用户只需运行环境而非OS -> 更加轻量级的LXC - Linux Container

  • Docker相比LXC的移动性 - LXC缺少标准化的描述手段和容器的可迁移性 导致其构建出的环境难于迁移和标准化管理 Docker在这个问题上做出实质性的革新 是docker最独特的地方

Docker简介

  • Docker 是一个开源的应用容器引擎 让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中 然后发布到任何流行的 Linux或Windows机器上 也可以实现虚拟化 容器是完全使用沙箱机制 相互之间不会有任何接口

  • 是 PaaS 提供商 dotCloud 开源的一个基于 LXC(Linux Container 一种内核虚拟化技术 ) 的高级容器引擎 源代码托管在 Github 上 基于go语言并遵从Apache2.0协议开源

  • 使用C/S架构 使用远程API来管理和创建Docker容器 Docker 容器通过 Docker 镜像来创建 容器与镜像的关系类似于面向对象编程中的对象与类

与传统虚拟化技术区别

image-20210805134717793
  • 传统虚拟机是虚拟一套硬件 在其上运行完整OS 再安装环境运行新的应用

  • Docker容器直接运行在宿主机上 没有自己的内核 也没有虚拟硬件(不准确地说可以理解为作为宿主机的进程运行

  • 容器间互相隔离 有一个属于自己的文件系统

    Docker

image-20210805112737114

典型场景

  • Automating the packaging and deployment of applications(使应用的打包与部署自动化)
  • Creation of lightweight, private PAAS environments(创建轻量、私密的PAAS环境)
  • Automated testing and continuous integration/deployment(实现自动化测试和持续的集成/部署)
  • Deploying and scaling web apps, databases and backend services(部署与扩展webapp、数据库和后台服务)

则对于DevOps

  • 应用更快速高效的交付和部署(打包成镜像
  • 更便捷的升级和扩缩容
  • 更简单运维
  • 更高效计算资源利用

局限

  1. Docker是基于Linux 64bit的 无法在32bit的linux/Windows/unix环境下使用
  2. LXC是基于cgroup等linux kernel功能的 因此container的guest系统只能是linux base的
  3. 隔离性相比KVM之类的虚拟化方案还是有些欠缺 所有container公用一部分的运行库
  4. 网络管理相对简单 主要是基于namespace隔离
  5. cgroup的cpu和cpuset提供的cpu功能相比KVM的等虚拟化方案相比难以度量(所以dotcloud主要是按内存收费)
  6. Docker对disk的管理比较有限
  7. container随着用户进程的停止而销毁 container中的log等用户数据不便收集

基础架构(重要)

Docker中三个基础概念

  • 镜像 - image 相当于一个root文件系统 包含了一些运行环境 是一个模版
  • 容器 - container 是image的实例 可以被创建、启动、暂停、停止、删除
  • 仓库 - 存放镜像的仓库 分为公有仓库和私有仓库 官方DockerHub

架构

C/S架构 使用远程API来管理和创建Docker容器 Docker 容器通过 Docker 镜像来创建

  • Client - Docker 客户端通过命令行或者其他工具使用 Docker SDK与 Docker 的守护进程通信
  • Host - 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器
  • Docker Registry 中可以包含多个仓库(Repository) 每个仓库可以包含多个标签(Tag)每个标签对应一个镜像
image-20210805115734341

工作原理

  • Docker Client 通过Socket 访问 Docker Server

  • Docker Server 接收到Docker Client的指令 执行

    image-20210805134456675

Docker安装

官方文档

安装前面主要是配置了其依赖包和设置默认仓库等

sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
                  
                  
sudo yum install -y yum-utils
sudo yum-config-manager \
    --add-repo \
    https://docker.mirrors.ustc.edu.cn
    # https://registry.docker-cn.com
    # http://hub-mirror.c.163.com 
    # https://download.docker.com/linux/centos/docker-ce.repo  # 默认镜像拉取地址 # 可以设为国内镜像
    
sudo yum install docker-ce docker-ce-cli containerd.io
sudo systemctl start docker

卸载

sudo yum remove docker-ce docker-ce-cli containerd.io
# 镜像、容器、自定义配置文件等并不会随着Docker的卸载自动删除,需要执行一下命令手动删除:
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd

原理

核心实现技术 都是Linux内核技术

  • 命名空间 namespace
  • 控制组 cgroup
  • 联合文件系统 UnionFS chroot

Docker是利用Namespace做资源隔离用Cgroup做资源限制 利用Union FS做容器文件系统的轻量级虚拟化技术

Docker容器的本质还是一个直接运行在宿主机上面的特殊进程 其文件系统是隔离后的 操作系统内核共享宿主机OS

命名空间 - Namespace

Linux 为我们提供的内核级别环境隔离的方法 用于分离进程树、网络接口、挂载点以及进程间通信等资源 使其中进程实现类似隔离的作用

Linux 的命名空间机制提供了七种不同的命名空间

这七个资源隔离选项分别对应七种系统调用 传入上表中的参数 调用clone函数来完成 我们能在创建新的进程时设置新进程应该在哪些资源上与宿主机器进行隔离

docker run or start时都会在createSpec方法中创建一个用于进程隔离的Spec 在setNamespaces方法中不仅会设置进程相关的命名空间 还会设置与用户、网络、IPC 以及 UTS 相关的命名空间 所有命名空间相关的设置 Spec 最后都会作为 Create函数的入参在创建新的容器时进行设置

控制组 - Cgroup

通过 Linux 的命名空间为新创建的进程隔离了文件系统、网络并与宿主机器之间的进程相互隔离 但是 Docker 容器中的进程仍然能够访问或者修改宿主机的其他目录(命名空间并不能够为我们提供物理资源上的隔离 比如CPU、内存、IO)

=> Control Groups 能够隔离宿主机器上的物理资源

每一个CGroup是一组被相同的标准和参数限制的进程(所有的资源控制都是以 CGroup 作为单位实现的,每一个进程都可以随时加入一个 CGroup 也可以随时退出一个 CGroup)

在早期版本中 可通过 libcgroup tools 来管理 cgroup 在 RedHat7 后 已经改为通过 systemctl 来管理

systemd 在 Linux 中的功能就是管理系统的资源 为了管理的方便衍生出了一个叫 Unit 的概念 可以表示抽象的服务、网络的资源、设备、挂载的文件系统等 Linux 将 Unit 的类型主要分为 12 种 Cgroup 中主要使用的是 slice, scope and service 三种类型

Linux实现CGroup(一切皆文件)

关于 docker 具体的限制可以在 sys/fs/cgroup/cpu/docekr/ 等文件夹来查看

image-20210805201414514

启动Docker容器时 Docker会为这个容器创建一个与容器标识符相同的CGroup(每个子系统下都会创建 cpu memory等子目录)

image-20210805201805011

想要控制 Docker 某个容器的资源使用率就可以在 docker 这个父控制组下面找到对应的子控制组并且改变它们对应文件的内容 也可以在启动Docker容器时指定参数去修改文件中的内容

每一个 CGroup 下面都有一个 tasks 文件 其中存储着属于当前控制组的所有进程的 pid 资源限制针对组中所有进程

容器停止后 该文件夹也会移除

示例

$ systemd-cgls  # 查看CGroup的信息

# 创建一个叫 toptest 的服务 在名为 test 的 slice 中运行
$ systemd-run --unit=toptest --slice=test top -b
Running as unit toptest.service.

$ systemctl status toptest # 查看其状态

$ systemctl set-property toptest.service CPUShares=600 MemoryLimit=500M # 对toptest服务进行资源限制

$ cat /proc/对应的pid/cgroup  # 一切皆文件 本质就是写了该文件

# 这时在 /sys/fs/cgroup/memory/test.slice 和 /sys/fs/cgroup/cpu/test.slice 目录下 多出了一个叫 toptest.service 的目录 在其目录下 cat toptest.service/cpu.shares 可以发现里面的 CPU 被限制了 600.

# Docker 和我们上面做的操作基本一致 具体需要限制哪些资源就是在 `docker run` 里指定
# 示例 
docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash

Docker文件系统

应该说Docker容器的文件系统是由rootfs(挂载)和union(分层、联合挂载)发展而来的

rootfs

开始说了Namespace隔离了容器间和容器间和宿主机间的文件系统 是通过Mount Namespace

Mount Namespace 除了在修改时需要进程对文件系统挂载点的认证 还需要显式声明需要挂载的目录 Linux中有一个叫 chroot 的命令 可以改变进程的根目录到指定的位置Mount Namespace 正是基于 chroot 的基础上发展出来的

容器的独立文件系统 就叫做容器镜像 更专业的名字叫 rootfs 包含了一个操作系统所需要的文件、配置和目录 但不包含系统内核 ** 在 Linux 中 文件和内核是分开存放的 操作系统只有在开启启动时才会加载指定的内核 这也就意味着所有的容器都会共享宿主机上操作系统的内核**

  • 有了rootfs 打包封装了依赖和应用本身 解决了环境配置问题
  • 有了rootfs 解决了可重用性问题 (通过引入分层概念 每次针对rootfs修改 只保存增量的内容)
UnionFS

层级的想法来自Linux的UnionFS

=> UnionFS是一种分层、轻量级、高性能的文件系统 支持对文件系统的修改作为一次提交来一层层地叠加 同时可以将不同目录挂载到同一个虚拟文件系统下 (最主要的功能) - 即主要用于把多个文件系统联合到同一个挂载点的文件系统服务

不同的环境有不同的UnionFS 如 AUFS、Overlay2(centos7)

AUFS

Advanced UnionFS 即UnionFS的升级版 它能够将不同文件夹中的层联合(Union)到了同一个文件夹中 这些文件夹在 AUFS 中称作分支 整个联合的过程被称为联合挂载

image-20210805203329666
  • 所有镜像层和容器层的内容都存储在 /var/lib/docker/aufs/diff/ 目录中
  • 每一个镜像层或者容器层都是 /var/lib/docker/ 目录下的一个子文件夹
  • /var/lib/docker/aufs/layers/ 中存储着镜像层的元数据 每一个文件都保存着镜像层的元数据
  • 最后的 /var/lib/docker/aufs/mnt/ 包含镜像或者容器层的挂载点 最终会被 Docker 通过联合的方式进行组装
Overlay2

centos7的docker默认存储引擎

结构

image-20210805210828085

Docker文件位置

image-20210805210724061

主要

  • container 容器

  • image 镜像 存放元数据

    image-20210805211216100

    • 如果实现了多种UnionFS 则image文件夹下会有对应的多个文件夹

    • imagedb用于存储image的每一层的引用

image-20210805211444749
  • layerdb用于存储最底层的层id 层之间的关联是通过 chainID 的方式保存的
  • overlay2 存放每个镜像下包含的lowerdir 真实的 rootfs 位置

则总的过程是

  • image/overlay2/imagedb/content/sha256/ 根据 image id 查看该 image 具有所有的层ID
  • 然后根据最底层ID和上一层ID通过 sha256 计算得到更上一层的ID 依次类推 关联所有的层 最后通过每一层的 cache-id 将元数据和真实的 rootfs 层数据对应起来了
镜像原理

联合文件系统是Docker镜像的基础

Docker中的每一个镜像都是由一系列只读的层组成的 Dockerfile 中的每一个命令都会在已有的只读层上创建一个新的层

即Docker run创建容器时 就会在镜像的最上层添加一个可写层 也就是容器层 所有对于运行时容器的修改都是对容器层的修改 可以用docker history查看镜像的组成层

image-20210805202656076

一个镜像可以创建多个容器

image-20210805202811272

Docker示意图

image-20210805203819535

面试问题

  1. 容器是如何进行隔离的?

    在创建新进程时,通过 Namespace 技术,如 PID namespaces 等,实现隔离性。让运行后的容器仅能看到本身的内容。

    比如,在容器运行时,会默认加上 PID, UTS, network, user, mount, IPC, cgroup 等 Namespace.

  2. 容器是如何进行资源限制的?

    通过 Linux Cgroup 技术,可为每个进程设定限制的 CPU,Memory 等资源,进而设置进程访问资源的上限。

  3. 简述下 docker 的文件系统?

    docker 的文件系统称为 rootfs,它的实现的想法来自与 Linux unionFS 。将不同的目录,挂载到一起,形成一个独立的视图。并且 docker 在此基础上引入了层的概念,解决了可重用性的问题。

    在具体实现上,rootfs 的存储区分根据 linux 内核和 docker 本身的版本,分为 overlay2 , overlay, aufs, devicemapper 等。rootfs(镜像)其实就是多个层的叠加,当多层存在相同的文件时,上层的文件会将下层的文件覆盖掉。

  4. 容器的启动过程?

    1. 指定 Linux Namespace 配置
    2. 设置指定的 Cgroups 参数
    3. 切换进程的根目录
  5. 容器内运行多个应用的问题?

    首先更正一个概念,我们都说容器是一个单进程的应用,其实这里的单进程不是指在容器中只允许着一个进程,而是指只有一个进程时可控的。在容器内当然可以使用 ping,ssh 等进程,但这些进程时不受 docker 控制的。

    容器内的主进程,也就是 pid =1 的进程,一般是通过 DockerFile 中 ENTRYPOINT 或者 CMD 指定的。如果在一个容器内如果存在着多个服务(进程),就可能出现主进程正常运行,但是子进程退出挂掉的问题,而对于 docker 来说,仅仅控制主进程,无法对这种意外的情况作出处理,也就会出现,容器明明正常运行,但是服务已经挂掉的情况,这时编排系统就变得非常困难。而且多个服务,在也不容易进行排障和管理。

    所以如果真的想要在容器内运行多个服务,一般会通过带有 systemd 或者 supervisord 这类工具进行管理,或者通过 --init 方法。其实这些方法的本质就是让多个服务的进程拥有同一个父进程。

    但考虑到容器本身的设计 就是希望容器和服务能够同生命周期 所以这样做 有点背道而驰的意味

Docker命令

官方文档

Docker仓库

Docker本身

# 启动docker:
systemctl start docker
# 停止docker:
systemctl stop docker
# 重启docker:
systemctl restart docker
# 查看docker状态:
systemctl status docker
# 开机启动:  
systemctl enable docker
systemctl unenable docker
# 查看docker概要信息
docker info
# 查看docker帮助文档
docker --help

总结

image-20210805153514504

帮助命令

docker version # docker版本信息
docker info #  docker 相关信息
docker help # docker 帮助
docker `command` --help # 具体命令的帮助

镜像命令(重要)

  • 查看镜像 docker images

    Usage:  docker images [OPTIONS] [REPOSITORY[:TAG]]
    
    List images
    
    Options:
      -a, --all             Show all images (default hides intermediate images)
      -q, --quiet           Only show image IDs
    
    [root@wanglingdu ~]# docker images
    REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
    hello-world   latest    d1165f221234   5 months ago   13.3kB
    # 仓库源 标签 镜像id 创建时间 大小
    
  • 搜索镜像 docker search

Usage:  docker search [OPTIONS] TERM

Search the Docker Hub for images

Options:
  -f, --filter filter   Filter output based on conditions provided
      --format string   Pretty-print search using a Go template
      --limit int       Max number of search results (default 25)
      --no-trunc        Don't truncate output

[root@wanglingdu ~]# docker search mysql -f stars=5000
NAME      DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql     MySQL is a widely used, open-source relation…   11213     [OK]
  • 拉取镜像 docker pull

    Usage:  docker pull [OPTIONS] NAME[:TAG|@DIGEST]
    
    Pull an image or a repository from a registry
    
    Options:
      -a, --all-tags                Download all tagged images in the repository
    
    [root@wanglingdu ~]# docker pull mysql
    Using default tag: latest
    latest: Pulling from library/mysql  # 拉取命令不指定tag 默认最新版
    33847f680f63: Pull complete  # 分层 docker image的核心 联合文件系统
    5cb67864e624: Pull complete
    1a2b594783f5: Pull complete
    b30e406dd925: Pull complete
    48901e306e4c: Pull complete
    603d2b7147fd: Pull complete
    802aa684c1c4: Pull complete
    715d3c143a06: Pull complete
    6978e1b7a511: Pull complete
    f0d78b0ac1be: Pull complete
    35a94d251ed1: Pull complete
    36f75719b1a9: Pull complete
    Digest: sha256:8b928a5117cf5c2238c7a09cd28c2e801ac98f91c3f8203a8938ae51f14700fd # 签名
    Status: Downloaded newer image for mysql:latest
    docker.io/library/mysql:latest # 真实地址
    
    docker pull mysql = docker.io/library/mysql:latest
    
  • 删除镜像 docker rmi

    Usage:  docker rmi [OPTIONS] IMAGE [IMAGE...]
    # IMAGE 可以是镜像名:tag 或者直接镜像id
    Remove one or more images
    
    Options:
      -f, --force      Force removal of the image  # 强制删除 
          --no-prune   Do not delete untagged parents  # 不删除未标签的父元素
    
    # 删除全部
    docker rmi -f $(docker images -aq)
    

容器命令

前提是有镜像 此处以centos镜像为例

  • 创建容器 会自动启动容器并进入(without -d) docker run (非常重要)

    Usage:  docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
    
    Run a command in a new container
    # -i 选项指示 docker 要在容器上打开一个标准的输入接口 -t 指示 docker 要创建一个伪tty终端 连接容器的标准输入接口 之后用户就可以通过终端进行输入 由于默认COMMAND为/bin/bash因此用户的输入是基于 bash shell 执行的
    --name=“cname" 											 Set Container name
    -i, --interactive                    Keep STDIN open even if not attached 
    -t, --tty                            Allocate a pseudo-TTY
    # 指定docker容器向宿主机开放映射的端口
    -p, --publish list                   Publish a container's port(s) to the host
    # -p 主机端口:容器端口
    -P, --publish-all                    Publish all exposed ports to random ports
    -d, --detach                         Run container in background and print container ID
    -e, --env list                       Set environment variables
    -h, --hostname string                Container host name
    
    # 示例 常用
    docker run -dit -p 8080:8080 --name="centos1" centos /bin/bash
    
  • 查看容器 docker ps

    docker ps  # 查看所有运行中的容器
    docker ps -a # 查看所有的容器 
    
  • 启动容器(停止的) docker start

    Usage:  docker start [OPTIONS] CONTAINER [CONTAINER...]
    
    Start one or more stopped containers
    
    Options:
      -a, --attach               Attach STDOUT/STDERR and forward signals
          --detach-keys string   Override the key sequence for detaching a container
      -i, --interactive          Attach container's STDIN
      
    # docker restart # 重启一个正在运行的容器
    
  • 停止容器(运行中的) docker stop

    Usage:  docker stop [OPTIONS] CONTAINER [CONTAINER...]
    
    Stop one or more running containers
    
    Options:
      -t, --time int   Seconds to wait for stop before killing it (default 10)
      
    # 也可以docker kill 强制结束
    
  • 进入容器(运行中的) docker exec

    Usage:  docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
    
    Run a command in a running container
    
    Options:
      -d, --detach               Detached mode: run command in the background
      -i, --interactive          Keep STDIN open even if not attached
      -t, --tty                  Allocate a pseudo-TTY
      
    docker exec -it id /bin/bash 
    
    # docker attach id  # 跟exec的区别是不会启动新的终端 而是用容器当前在用的终端 不会启动新的进程
    
  • 退出容器(不一定停止) exit

    exit # 直接退出容器 此时若没有指定后台运行 那么容器会自动停止
    # 也可以crtl + p + q 退出 不会停止容器
    
  • 删除容器 (停止的)docker rm

    Usage:  docker rm [OPTIONS] CONTAINER [CONTAINER...]
    
    Remove one or more containers
    
    Options:
      -f, --force     Force the removal of a running container (uses SIGKILL)
      -v, --volumes   Remove anonymous volumes associated with the container
    

常用其他命令

  • 容器日志 docker logs

    Usage:  docker logs [OPTIONS] CONTAINER
    
    Fetch the logs of a container
    
    Options:
          --details        Show extra details provided to logs
      -f, --follow         Follow log output
          --since string   Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)
      -n, --tail string    Number of lines to show from the end of the logs (default "all")
      -t, --timestamps     Show timestamps
          --until string   Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)
    
  • 查看容器内进程信息 docker top

    Usage:  docker top CONTAINER [ps OPTIONS]
    
    Display the running processes of a container
    
  • 查看容器的元数据信息 docker inspect

    Usage:  docker inspect [OPTIONS] NAME|ID [NAME|ID...]
    
    Return low-level information on Docker objects
    
    Options:
      -f, --format string   Format the output using the given Go template
      -s, --size            Display total file sizes if the type is container
          --type string     Return JSON for specified type
    
  • 容器和宿主机互相拷贝数据 docker cp

    Usage:  docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
    	docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
    
    Copy files/folders between a container and the local filesystem
    
    Use '-' as the source to read a tar archive from stdin
    and extract it to a directory destination in a container.
    Use '-' as the destination to stream a tar archive of a
    container source to stdout.
    
    Options:
      -a, --archive       Archive mode (copy all uid/gid information)
      -L, --follow-link   Always follow symbol link in SRC_PATH
    
  • 容器挂载目录到宿主机上 (相当于会同步)在run的时候 -v 去指定

  • 查看容器状态命令(cpu、内存等使用情况) docker stats

端口映射及数据卷挂载

单独提出来说一说 我个人感觉比较重要

端口映射

新建一个容器时 指定宿主机和容器的端口映射 即通过宿主机的端口访问容器的指定端口 之前实现了外网的访问(服务器防火墙开启端口以及服务器安全组设置)

docker run -p 宿主机端口 : 容器端口 示例 3344 : 80 即如果容器部署应用在80端口 那么服务器外网ip:3344 就能访问该应用

数据卷挂载

在容器内部批量处理文件之类的比较麻烦 要是能够像端口映射一样 在外部处理 更好处理 所以引入挂载 两个路径之间同步

部署应用测试

部署Nginx

docker pull nginx
docker run -dit --name nginx01 -p 3344:80 nginx
# 测试
curl localhost:3344
# 通过3344端口可访问了

部署Tomcat

步骤本质没什么区别

docker pull tomcat:9.0
docker run -dit --name tomcat01 -p 3355:80 tomcat
# 测试
# 通过3355端口可访问Tomcat默认页

这里需要注意一个点时 拉取的镜像默认的webapps目录下没有项目 是因为最小化拉取的镜像 将webapps.dist文件夹下的拷贝过来即可

部署ES + Kibana

ElasticSearch

使用的端口比较多、也比较耗内存 数据一般需要挂载到安全目录 --net somework 网络配置

docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.14.0

# 测试
curl localhost:9200

# 因为占用内存 可以在run的时候 指定-e选项配置一些环境 比如这 -e ES_JAVA__OPTS="-Xms64m -Xmx512m"

Kibana用于连接ES 要学习Docker网络原理

部署Portainer

一个Docker图像化界面管理工具 提供一个后台面板操作

docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

一般不使用

Docker镜像

镜像

镜像是一种轻量级、可执行的独立软件包(独立的文件系统) 用来打包软件运行环境和软件 它包含运行某个软件所需的所有内容 包括代码、运行时库、环境变量和配置文件 应用打包为镜像 就可以直接运行 一般从远程库、其他人拷贝、通过DockerFile制作

镜像加载原理

原理部分已经说了镜像实际上是独一个独立的文件系统(rootfs) 由一层一层的文件系统联合挂载而来(是UnionFS)

  • Docker镜像的最底层是bootfs 与典型的Linux系统相同 包含boot加载器和内核
  • Linux刚启动时会加载bootfs boot加载器加载内核完毕后 内存使用权由bootfs转到内核 同时卸载bootfs
  • bootfs之上即rootfs 原理部分已说 chroot或者说mount namespace 到了指定目录

提交镜像

前面已经说了run时新增了个容器层 所有修改都是针对容器层 那么如何提交作为一个新的镜像?

Usage:  docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
# 若指定的不是REPOSITORY而直接是目标镜像名 则提交到本地
Create a new image from a container's changes

Options:
  -a, --author string    Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")
  -c, --change list      Apply Dockerfile instruction to the created image
  -m, --message string   Commit message
  -p, --pause            Pause container during commit (default true)

容器数据卷

Motivation

容器中的数据在容器删除后也会丢失 -> 持久化数据到本地 防止删除容器数据丢失 或者删库跑路!

实现 : Docker容器中的数据 与本地进行同步 -> 数据卷技术 将容器内的目录挂载到宿主机的指定路径

总结:容器的持久化和同步操作 而且容器间可以数据共享(同一个

使用数据卷

docker run -v 主机目录: 容器内目录  # 可以挂载多个目录

测试mysql

docker run -d -p 3307:3306 -v /home/wld/myspace/mysql/conf:/etc/mysql/conf.d -v /home/wld/myspace/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7

# 然后就可以通过指定的3307端口从外网连接数据库
# 两边文件会同步
# 删除容器 本地目录也不会丢失

连接上后创建一个testDocker目录

image-20210805224505117

服务器直接有了这个目录

image-20210805224445556

容器中也有了这个目录image-20210805224612389

具名和匿名挂载

# 匿名挂载 -v 容器内路径
# 具名挂载是指 -v volume_name:docker_path 最好使用具名挂载
# 指定路径挂载 -v /host_path: docker_path

通过docker volume 查看数据卷 圈起来的是匿名挂载的

docker volume inspect volume_name 指定查看对应名字数据卷的详细信息(包括实际挂载目录 没有指定时默认是/var/lib/docker/volumes/ 下

image-20210805224913941

-v /宿主机路径:容器路径:ro / rw 设定只读或读写权限 若只读只能通过宿主机操作

通过DockerFile挂载

构建DockerFile的时候 用VOLUME命令 指定几个目录名 会自动匿名挂载到/var/lib/docker/volumes/ 下

相当于不用手动地去挂载 让构建的镜像自定义了几个需要挂载的目录 VOLUME [“/volume01”, “/volume02”]

数据卷容器

image-20210805231316053

一个容器挂载到宿主机指定位置 跟另一个容器挂载到该容器的指定位置没什么本质差别

只是使用–volumes-from 指令去实现而已 即A 挂载数据卷到宿主机某个位置 B容器使用该命令 docker run -dit --volumes-from A 则一同挂载了(只挂载数据卷) A就称为数据卷容器 专门用于指定挂载目录的

就算容器A删掉了 数据应依旧存在 本质应该是用了这个命令那么就是挂载到A挂载的宿主机本地目录 本地没删 那么就有

数据卷容器的生命周期一直到没有容器使用它

DockerFile

DockerFile 是用于构建镜像的命令脚本文件

构建镜像步骤

  • 编写dockerfile
    • 指令大写
    • 从上到下执行 一条指令一层
  • docker build
  • docker run
  • docker push

DockerFile指令

image-20210805234219081
image-20210805234924059

CMD和ENTRYPOINT的区别在于CMD只有最后一个会生效 可被替代 ENTRYPOINT可追加

实战部署项目

FROM centos

RUN yum -y install vim

ADD apache-tomcat-9.0.50.tar.gz /usr/local
ADD jdk-8u301-linux-x64.tar.gz /usr/local

ENV JAVA_HOME /usr/local/jdk1.8.0_301
ENV CLASS_PATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.50
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin:$CATALINA_HOME/lib

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.50/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.50/bin/logs/catalina.out

通过Dockerfile build 容器

创建容器 映射9090端口 挂载目录

docker run -dit -p 9090:8080 -v /home/wld/build/test:/usr/local/apache-tomcat-9.0.50/webapps/test -v /home/wld/build/testlogs:/usr/local/apache-tomcat-9.0.50/logs customcat

可以通过外网访问9090端口 默认的ROOT项目了

然后在宿主机修改test项目 将之改变为一个web项目 (添加/WEB-INF/web.xml index.jsp) 即可通过项目名访问

发布到DockerHub

  • DockerHub注册
  • 命令行登录
  • docker push (push之前要将镜像打标签)
image-20210806133304401

Docker网络

Docker如何处理容器和宿主机间、容器间网络访问的?

原理 Docker0

服务器的网卡

image-20210806134701240

只要安装了Docker 服务器就会多出docker0网卡 地址是172.17.0.1 使用桥接模式 使用evth-pair技术(一对虚拟网络设备接口 充当桥梁 连接各种虚拟网络设备)

以后每开一个容器 就会多出一对网卡(一个在服务器 一个在容器中) 会分配该网段的一个地址给该容器

原理图

image-20210806140321816

可以通过--link(run的时候) 直接通过容器名 ping通另一容器(可以这样做 但不推荐)

image-20210806140811429

tomcat03可以ping通tomcat02 反之不行 本质实现是在tomcat03容器中的/etc/hosts文件中直接将其写死

image-20210806141259524

自定义网络

docker网络模式

  • bridge 桥接 (默认 )
  • none 不配置网络
  • host 和宿主机共享网络
  • container 容器内网络互通(使用少)
容器互联
Usage:  docker network COMMAND # 容器网络相关命令 可以自定义网络等

Manage networks

Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks
  
  
# 示例
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 cusnetwork
# 创建容器时指定网络
docker run -d -P --name tomcat-net-01 cusnetwork tomcat

这时候网络内的多个容器可以互相ping通 且可以使用容器名直接ping 不用使用–link

好处 不同的集群使用不同的网络 保证集群安全和健康

网络连通

同一网段的容器已经可以互联了 如果想容器连通另一网络的容器 使用connect命令

Usage:  docker network connect [OPTIONS] NETWORK CONTAINER

Connect a container to a network

Options:
      --alias strings           Add network-scoped alias for the container
      --driver-opt strings      driver options for the network
      --ip string               IPv4 address (e.g., 172.30.100.104)
      --ip6 string              IPv6 address (e.g., 2001:db8::33)
      --link list               Add link to another container
      --link-local-ip strings   Add a link-local address for the container

本质上是将该容器直接同时放到另一网络即可 (一个容器两个ip

SpringBoot项目部署Docker

  • 项目

  • 打包应用

  • 编写Dockerfile

    示例

    FROM java:8
    
    COPY *.jar /app.jar
    
    CMD ["--server.port=8080"]
    
    EXPOSE 8080
    
    ENTRYPOINT ["java", "-jar", "/app.jar"]
    
  • 把jar和dockerfile上传到服务器 构建镜像

  • 发布运行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值