首页 > 其他分享 >+63+条消息++狂神+docker+学习笔记_GaleTeng+的博客+-+CSDN+博客

+63+条消息++狂神+docker+学习笔记_GaleTeng+的博客+-+CSDN+博客

时间:2024-05-08 18:02:56浏览次数:26  
标签:容器 ++ GaleTeng 博客 -- 镜像 docker root localhost

+63+条消息++狂神+docker+学习笔记_GaleTeng+的博客+-+CSDN+博客

文章目录

前言

在学习 Docker 前先把 Linux 基本命令复习一下:狂神 Linux 学习笔记

Docker 概述

1.Docker 为什么会出现?

一款产品:开发上线两套环境!应用环境,应用配置!
开发一运维。问题:我在我的电脑上可以运行!版本更新,导致服务不可用!对于运维来说,考验就十分大?
环境配置是十分的麻烦,每一个机器都要部署环境(集群 Redis、ES、Hadoop.…)! 费时费力。
发布一一
顷目 (jar+(Redis MySQL jdk ES))
项目能不能都带上环境安装打包!
之前在服务器配置一个应用的环境 Redis MySQL jdk ES Hadoop, 配置超麻烦了,不能够跨平台。
Windows, 最后发布到 Linux
传统:开发 jar, 运维来做!
现在:开发打包部署上线,一套流程做完!
java…apk… 发布(应用商店)- 张三使用 apk - 安装即可用!
java –
jar(环境)- 打包项目带上环境(镜像)…(Docker 仓库:商店)–下载我们发布的镜像 - 直接运行即可!

Docker 给以上问题,提出了解决方案!

Docker 的思想就来自于集装箱!
RE… 多个应用(端口冲突)… 原来都是交叉的!
隔离:Docker 核心思想!打包装箱!每个箱子是互相隔离的。
水果
生化武器
Docker 通过隔离机制,可以将服务器利用到极致!

2.Docker 历史

2010 年,几个搞 T 的年轻人,就在美国成立了一家公司 dotC1oud
做一些 paas 的云计算服务!LXC 有关的容器技术
他们将自己的技术(容器化技术)命名就是 Docker!
Docker 刚刚诞生的时候,没有引起行业的注意!dotCloud, 就活不下去!
开源
开发源代码!
2013 年,Docker 开源!
Dockeri 越来越多的人发现了 docker 的优点!火了,Docker 每个月都会更新一个版本!
2014 年 4 月 9 日,Docker1.0 发布!
Docker 为什么这么火?十分的轻巧 I
在容器技术出来之前,我们都是使用虚拟机技术!
虚拟机:在 window 中装一个 Vmware, 通过这个软件我们可以虚拟出来一台或者多台电脑!笨重!
虚拟机也是属于虚拟化技术,Docker 容器技术,也是一种虚拟化技术!

vm:	linux centos原生镜像(一个电脑!)隔离,需要开启多个虚拟机!  几个G几分钟
docker:	隔离,镜像(最核心的环境4m+jdk+mysq1)十分的小巧,运行镜像就可以了!小巧!几个M  KB秒级启动!

聊聊 Docker

3.Docker 能干嘛

虚拟机技术

虚拟机技术缺点:

  • 资源占用十分多
  • 冗余步骤多
  • 启动很慢!

容器化技术

容器化技术不是模拟一个完整的操作系统

比较 Docker 和虚拟机技术的不同:

  • 传统虚拟机,虚拟出一条硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件
  • 容器内的应用直接运行在宿主机的内容,容器是没有自己的内核的,也没有虚拟我们的硬件,所以就轻便了
  • 每个容器间是互相隔离,每个容器内都有一个属于自己的文件系统,互不影响

DevOps(开发、运维)

应用更快速的交付和部署

  • 传统:一对帮助文档,安装程序。
  • Docker:打包镜像发布测试一键运行。

更便捷的升级和扩缩容

  • 使用了 Docker 之后,我们部署应用就和搭积木一样
    项目打包为一个镜像,扩展服务器 A!服务器 B

更简单的系统运维

  • 在容器化之后,我们的开发,测试环境都是高度一致的

更高效的计算资源利用

  • Docker 是内核级别的虚拟化,可以在一个物理机上可以运行很多的容器实例!服务器的性能可以被压榨到极致。

Docker 安装

1. Docker 的基本组成

镜像(image):

  • docker 镜像就好比是一个目标,可以通过这个目标来创建容器服务,tomcat 镜像 >run> 容器(提供服务器),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)。

容器 (container):

  • Docker 利用容器技术,独立运行一个或者一组应用,通过镜像来创建的.
    启动,停止,删除,基本命令
    目前就可以把这个容器理解为就是一个简易的 Linux 系统。

仓库 (repository):

  • 仓库就是存放镜像的地方!
    仓库分为公有仓库和私有仓库。(很类似 git)
    Docker Hub 是国外的。
    阿里云… 都有容器服务器 (配置镜像加速!)

2. 安装 Docker

环境

  1. Linux 要求内核 3.0 以上
  2. CentOS 7
[root@localhost ~]# uname -r
3.10.0-1160.el7.x86_64

[root@localhost ~]# cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

安装

帮助文档:https://docs.docker.com/engine/install/

#1.	卸载旧版本
yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
#2.	需要的安装包
yum install -y yum-utils
 #3.	设置镜像的仓库
yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
# 上述方法默认是从国外的,不推荐
 # 推荐使用国内的
yum-config-manager \
    --add-repo \
    https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
 #4.	更新yum软件包索引
yum makecache fast
 #5.	安装docker相关的 docker-ce 社区版 而ee是企业版
yum install docker-ce docker-ce-cli containerd.io # 这里我们使用社区版即可
 #6.	启动docker
systemctl start docker
 #7. 使用docker version查看是否按照成功
docker version
 #8. 测试
docker run hello-world
[root@localhost ~]# systemctl start docker
[root@localhost ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
hello-world   latest    feb5d9fea6a5   15 months ago   13.3kB

卸载 Docker

#1. 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
#2. 删除资源
rm -rf /var/lib/docker
# /var/lib/docker 是docker的默认工作路径!

3. 阿里云镜像加速

由于所使用的并非阿里云服务器,使用 Vmware+CentOS7 本地电脑学习,所以略!

4. 回顾 HelloWorld 流程

5. 底层原理

Docker 是一个 Client-Server 结构的系统,Docker 的守护进程运行在主机上。通过 Socket 从客户端访问!

Docker-Server 接收到 Docker-Client 的指令,就会执行这个命令!

为什么 Docker 比 Vm 快?

  1. docker 有着比虚拟机更少的抽象层。由于 docker 不需要 Hypervisor 实现硬件资源虚拟化, 运行在 docker 容器上的程序直接使用的都是实际物理机的硬件资源。因此在 CPU、内存利用率上 docker 将会在效率上有明显优势。

  2. docker 利用的是宿主机的内核, 而不需要 Guest OS。

  3. 当新建一个 容器时, docker 不需要和虚拟机一样重新加载一个操作系统内核。仍而避免引导、加载操作系统内核返个比较费时费资源的过程, 当新建一个虚拟机时, 虚拟机软件需要加载 GuestOS, 返个新建过程是分钟级别的。而 docker 由于直接利用宿主机的操作系统, 则省略了这个复杂的过程, 因此新建一个 docker 容器只需要几秒钟。

Docker 常用命令

1. 帮助命令

帮助文档地址:https://docs.docker.com/engine/reference/commandline/version/

docker version    	  #显示docker的版本信息。
docker info       	  #显示docker的系统信息,包括镜像和容器的数量
docker 命令 --help     #帮助命令

2. 镜像命令

  • docker images 查看所有本地的主机的镜像

    [root@localhost ~]# systemctl start docker
    [root@localhost ~]# docker images
    REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
    hello-world   latest    feb5d9fea6a5   15 months ago   13.3kB
    [root@localhost ~]# docker images --help
    
    Usage:  docker images [OPTIONS] [REPOSITORY[:TAG]]
    
    List images
    
    Options:
      -a, --all             Show all images (default hides intermediate images)
          --digests         Show digests
      -f, --filter filter   Filter output based on conditions provided
          --format string   Pretty-print images using a Go template
          --no-trunc        Don't truncate output
      -q, --quiet           Only show image IDs
    
    # 解释
    REPOSITORY      # 镜像的仓库
    TAG             # 镜像的标签
    IMAGE ID        # 镜像的ID
    CREATED         # 镜像的创建时间
    SIZE            # 镜像的大小
    
    # 可选项
    --all , -a      # 列出所有镜像
    --quiet , -q    # 只显示镜像的id
    
  • docker search 搜索镜像

    [root@localhost ~]# docker search --help
    
    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
    
    # 可选项	通过搜索来过滤
    --filter=STARS=3000		# 搜索出来的镜像就是STARS大于3000的
    
    [root@localhost ~]# docker search mysql --filter=STARS=3000
    NAME      DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
    mysql     MySQL is a widely used, open-source relation…   13690     [OK]       
    mariadb   MariaDB Server is a high performing open sou…   5229      [OK]
    
  • docker pull 下拉镜像

    # 下载镜像,docker pull 镜像名[:tag]
    [root@localhost ~]# docker pull mysql
    Using default tag: latest			 #如果不写tag,默认就是最新的latest
    latest: Pulling from library/mysql
    0ed027b72ddc: Pull complete 
    0296159747f1: Pull complete 		 # 分层下载,docker images的核心,联合文件系统
    3d2f9b664bd3: Pull complete 
    df6519f81c26: Pull complete 
    36bb5e56d458: Pull complete 
    054e8fde88d0: Pull complete 
    f2b494c50c7f: Pull complete 
    132bc0d471b8: Pull complete 
    135ec7033a05: Pull complete 
    5961f0272472: Pull complete 
    75b5f7a3d3a4: Pull complete 
    Digest: sha256:3d7ae561cf6095f6aca8eb7830e1d14734227b1fb4748092f2be2cfbccf7d614 #签名
    Status: Downloaded newer image for mysql:latest
    docker.io/library/mysql:latest		 # 真实地址
    
    docker pull mysql
    # 等价于
    docker pull docker.io/library/mysql:latest
    
    # 指定版本下载
    [root@localhost ~]# docker pull mysql:5.7
    5.7: Pulling from library/mysql
    d26998a7c52d: Pull complete 
    4a9d8a3567e3: Pull complete 
    bfee1f0f349e: Pull complete 
    71ff8dfb9b12: Pull complete 
    bf56cbebc916: Pull complete 
    2e747e5e37d7: Pull complete 
    711a06e512da: Pull complete 
    3288d68e4e9e: Pull complete 
    49271f2d6d15: Pull complete 
    f782f6cac69c: Pull complete 
    701dea355691: Pull complete 
    Digest: sha256:6306f106a056e24b3a2582a59a4c84cd199907f826eff27df36406f227cd9a7d
    Status: Downloaded newer image for mysql:5.7
    docker.io/library/mysql:5.7
    
    # 查看本地镜像
    [root@localhost ~]# docker images
    REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
    mysql         5.7       d410f4167eea   5 weeks ago     495MB
    mysql         latest    7484689f290f   5 weeks ago     538MB
    hello-world   latest    feb5d9fea6a5   15 months ago   13.3kB
    
  • docker rmi 删除镜像

    # 删除指定镜像
    [root@localhost ~]# docker rmi -f IMAGE ID 
    # 删除多个镜像
    [root@localhost ~]# docker rmi -f IMAGE ID1 IMAGE ID2 IMAGE ID3 
    # 删除全部镜像
    [root@localhost ~]# docker rmi -f $(docker images -aq)
    

3. 容器命令

说明: 我们有了镜像才可创建容器,linux,下载一个 centos 镜像来测试学习

docker pull centos

1. 新建容器并启动

docker run [可选参数] image

# 参数说明
--name=“Name”   容器名字    tomcat01    tomcat02    用来区分容器
-d      		后台方式运行
-it     		使用交互方式运行,进入容器查看内容
-p      		指定容器的端口     -p 8080:8080
    -p  ip:主机端口:容器端口
    -p  主机端口:容器端口(常用)
    -p  容器端口
    容器端口
-P      		随机指定端口
 
# 测试,启动并进入容器
[root@localhost ~]# docker run -it centos /bin/bash
[root@31225df28944 /]# ls	 # 查看容器内的centos,基础版本,很多命令是不完善的
bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr

# 从容器中退回主机
[root@31225df28944 /]# exit
exit
[root@localhost ~]# ls
anaconda-ks.cfg       公共  视频  文档  音乐
initial-setup-ks.cfg  模板  图片  下载  桌面

2. 列出所有的运行的容器

# docker ps 命令
        # 列出当前正在运行的容器
-a      # 列出正在运行的容器包括历史容器
-n=?    # 显示最近创建的容器
-q      # 只显示当前容器的编号
 
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE         COMMAND       CREATED         STATUS                     PORTS     NAMES
31225df28944   centos        "/bin/bash"   8 minutes ago   Exited (0) 3 minutes ago             blissful_leavitt
7be2b60ed0c5   hello-world   "/hello"      9 days ago      Exited (0) 9 days ago                agitated_goodall

[root@localhost ~]# docker ps -a -n=1
CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS                     PORTS     NAMES
31225df28944   centos    "/bin/bash"   11 minutes ago   Exited (0) 6 minutes ago             blissful_leavitt

[root@localhost ~]# docker ps -aq
31225df28944
7be2b60ed0c5

4. 退出容器

exit            # 直接容器停止并退出
Ctrl + P + Q    # 容器不停止退出

# 目前无正在运行的容器
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

# 运行容器
[root@localhost ~]# docker run -it centos /bin/bash

# 按住 右Ctrl +P +Q 输入 docker ps  可以看到容器在运行
[root@2f0fad47b419 /]# [root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED              STATUS              PORTS     NAMES
2f0fad47b419   centos    "/bin/bash"   About a minute ago   Up About a minute             vigorous_curie
[root@localhost ~]#

5. 删除容器

docker rm  容器id                    # 删除指定容器,不能删除正在运行的容器,如果要强制删除  rm -f
docker rm -f 容器id                  # 强制删除指定容器
docker rm -f $(docker ps -aq)       # 删除所有容器
docker ps -a -q|xargs docker rm -f  # 删除所有容器(通过管道符)

启动和停止容器

docker start 容器id           # 启动容器
docker restart 容器id         # 重启容器
docker stop 容器id            # 停止当前正在运行的容器
docker kill 容器id            # 强制停止当前的容器

# 测试
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS          PORTS     NAMES
2f0fad47b419   centos    "/bin/bash"   12 minutes ago   Up 12 minutes             vigorous_curie

# 停止当前正在运行的 centos
[root@localhost ~]# docker stop 2f0fad47b419
2f0fad47b419

[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

# 启动 centos容器
[root@localhost ~]# docker start 2f0fad47b419
2f0fad47b419

[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS         PORTS     NAMES
2f0fad47b419   centos    "/bin/bash"   15 minutes ago   Up 7 seconds             vigorous_curie
# 测试成功

4. 常用的其他命令

后台启动容器

# 命令	docker run -d 镜像名
[root@localhost ~]# docker run -d centos
93772655bd0709c65767c128e939a090ee0be4c317125557967a63d0aae2cdf7
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@localhost ~]# 
 
# 问题 docker ps, 发现centos停止了
 
# 常见的坑, docker 容器使用后台运行, 就必须要有一个前台进程,docker发现没有应用,就会自动停止
# nginx, 容器启动后,发现自己没有提供服务,就会立即停止,就是没有程序了

查看日志

# 命令	docker logs -tf --tail number 容器id

[root@localhost ~]# docker logs -tf --tail 3 2f0fad47b419    # 查到两条日志
2023-01-14T12:33:59.839621096Z [root@2f0fad47b419 /]# exit
2023-01-14T12:45:03.884332494Z [root@2f0fad47b419 /]# exit
 
# 自己编写一段shell脚本
[root@localhost ~]#  docker run -d centos /bin/sh -c "while true;do echo kuangshen;sleep 1;done"
91973e3049338501c282d003c4b8703243aed3ca9362cfda486eefd10f4adc6a

[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
91973e304933   centos    "/bin/sh -c 'while t…"   13 seconds ago   Up 13 seconds             dazzling_einstein
2f0fad47b419   centos    "/bin/bash"              37 minutes ago   Up 4 minutes              vigorous_curie
                           lucid_black
 
# 显示日志
-tf                 # 显示日志
--tail number       # 显示日志条数

# 测试
[root@localhost ~]# docker logs -tf --tail 3 91973e304933
2023-01-14T12:58:48.930057833Z kuangshen
2023-01-14T12:58:49.935107229Z kuangshen
2023-01-14T12:58:50.937433583Z kuangshen

查看容器中进程信息 ps

# 命令	docker top 容器id
[root@localhost ~]# docker top 91973e304933
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                11967               11948               0                   20:56               ?                   00:00:00            /bin/sh -c while true;do echo kuangshen;sleep 1;done
root                12617               11967               0                   21:01               ?                   00:00:00            /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1

查看镜像的元数据

# 命令	docker inspect 容器id

[root@localhost ~]# docker inspect 91973e304933
[ {
        "Id": "91973e3049338501c282d003c4b8703243aed3ca9362cfda486eefd10f4adc6a",
        "Created": "2023-01-14T12:56:59.250226079Z",
        "Path": "/bin/sh",
        "Args": [
            "-c",
            "while true;do echo kuangshen;sleep 1;done" ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 11967,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2023-01-14T12:56:59.55789447Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6",
        "ResolvConfPath": "/var/lib/docker/containers/91973e3049338501c282d003c4b8703243aed3ca9362cfda486eefd10f4adc6a/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/91973e3049338501c282d003c4b8703243aed3ca9362cfda486eefd10f4adc6a/hostname",
        "HostsPath": "/var/lib/docker/containers/91973e3049338501c282d003c4b8703243aed3ca9362cfda486eefd10f4adc6a/hosts",
        "LogPath": "/var/lib/docker/containers/91973e3049338501c282d003c4b8703243aed3ca9362cfda486eefd10f4adc6a/91973e3049338501c282d003c4b8703243aed3ca9362cfda486eefd10f4adc6a-json.log",
        "Name": "/dazzling_einstein",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "CgroupnsMode": "host",
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "KernelMemory": 0,
            "KernelMemoryTCP": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/b7dad1bc183c3adb6f7a5cbf8a70721cf9b0e8f3d62d8540915ed8d1f5c68ca9-init/diff:/var/lib/docker/overlay2/801b2a142dff6f902ebf17068deb5be4c9f5e981a009dbb4ce35148f59eeea3a/diff",
                "MergedDir": "/var/lib/docker/overlay2/b7dad1bc183c3adb6f7a5cbf8a70721cf9b0e8f3d62d8540915ed8d1f5c68ca9/merged",
                "UpperDir": "/var/lib/docker/overlay2/b7dad1bc183c3adb6f7a5cbf8a70721cf9b0e8f3d62d8540915ed8d1f5c68ca9/diff",
                "WorkDir": "/var/lib/docker/overlay2/b7dad1bc183c3adb6f7a5cbf8a70721cf9b0e8f3d62d8540915ed8d1f5c68ca9/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "91973e304933",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "while true;do echo kuangshen;sleep 1;done"
            ],
            "Image": "centos",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.build-date": "20210915",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS"
            }
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "8b2e7c3b25b65c123340dfb5d2679c0fa4df1542e41a05921fb368a0aa6602aa",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "/var/run/docker/netns/8b2e7c3b25b6",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "bd4b04b336a71f1067ea878d931323144833f4243079c225e25082c531a5ce13",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.3",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:03",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "aa8b4f2abf1e12ea0106ded5e1f4c73ab4f3297c15bc530a9d1b0a69b3b4992e",
                    "EndpointID": "bd4b04b336a71f1067ea878d931323144833f4243079c225e25082c531a5ce13",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:03",
                    "DriverOpts": null
                }
            }
        }
    }
]

进入当前正在运行的容器

# 我们通常容器使用后台方式运行的, 需要进入容器,修改一些配置
 
# 命令	docker exec -it 容器id /bin/bash
 
# 测试
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
91973e304933   centos    "/bin/sh -c 'while t…"   10 minutes ago   Up 10 minutes             dazzling_einstein
2f0fad47b419   centos    "/bin/bash"              47 minutes ago   Up 14 minutes             vigorous_curie

[root@localhost ~]# docker exec -it 91973e304933 /bin/bash

[root@91973e304933 /]# ls
bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr

[root@91973e304933 /]# ps -ef
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 12:56 ?        00:00:00 /bin/sh -c while true;do echo kua
root        673      0  0 13:08 pts/0    00:00:00 /bin/bash
root        698      1  0 13:08 ?        00:00:00 /usr/bin/coreutils --coreutils-pr
root        699    673  0 13:08 pts/0    00:00:00 ps -ef

 
# 方式二
# 命令	docker attach 容器id

[root@localhost ~]# docker attach 91973e304933
正在输出 kuangshen...		# docker stop 91973e304933

# docker exec       # 进入容器后开启一个新的终端,可以在里面操作
# docker attach     # 进入容器正在执行的终端,不会启动新的进程

从容器中拷贝文件到主机

# 命令	docker cp 容器id:容器内路径 目的地主机路径
 
# 测试
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS          PORTS     NAMES
2f0fad47b419   centos    "/bin/bash"   58 minutes ago   Up 26 minutes             vigorous_curie

# 启动并进入 centos 容器
[root@localhost ~]# docker exec -it 2f0fad47b419 /bin/bash

# 在 centos 容器 /home 目录下 新建 kuangshen.java
[root@2f0fad47b419 /]# cd /home

[root@2f0fad47b419 home]# ls

[root@2f0fad47b419 home]# touch kuangshen.java

[root@2f0fad47b419 home]# ls
kuangshen.java

[root@2f0fad47b419 home]# exit
exit

# 在主机上 拷贝 centos 容器 /home 目录下 kuangshen.java 文件 到主机 /home 目录
[root@localhost ~]# docker cp 2f0fad47b419:/home/kuangshen.java /home

[root@localhost ~]# cd /home

[root@localhost home]# ls
kuangshen.java  kuangstudy  test  xiaotengteng

[root@localhost home]# 
# 拷贝成功

5. 小结

命令总结

attach    Attach to a running container  #当前shell下attach连接指定运行镜像
build     Build an image from a Dockerfile  #通过Dockerfile定制镜像
commit    Create a new image from a container's changes  #提交当前容器为新的镜像
# 从容器中拷贝指定文件或者目录到宿主机中
cp    	  Copy files/folders from a container to a HOSTDIR or to STDOUT 
create    Create a new container  #创建一个新的容器,同run 但不启动容器
diff      Inspect changes on a container's filesystem  #查看docker容器变化
events    Get real time events from the server#从docker服务获取容器实时事件
exec      Run a command in a running container#在已存在的容器上运行命令
# 导出容器的内容流作为一个tar归档文件(对应import)
export    Export a container's filesystem as a tar archive 
history   Show the history of an image  #展示一个镜像形成历史
images    List images  #列出系统当前镜像
# 从tar包中的内容创建一个新的文件系统映像(对应export)
import    Import the contents from a tarball to create a filesystem image 
info      Display system-wide information  #显示系统相关信息
inspect   Return low-level information on a container or image  #查看容器详细信息
kill      Kill a running container  #kill指定docker容器
# 从一个tar包中加载一个镜像(对应save)
load      Load an image from a tar archive or STDIN 
login     Register or log in to a Docker registry#注册或者登陆一个docker源服务器
logout    Log out from a Docker registry  #从当前Docker registry退出
logs      Fetch the logs of a container  #输出当前容器日志信息
pause     Pause all processes within a container#暂停容器
# 查看映射端口对应的容器内部源端口
port      List port mappings or a specific mapping for the CONTAINER 
ps        List containers  #列出容器列表
# 从docker镜像源服务器拉取指定镜像或者库镜像
pull      Pull an image or a repository from a registry 
# 推送指定镜像或者库镜像至docker源服务器
push      Push an image or a repository to a registry 
rename    Rename a container  #重命名容器
restart   Restart a running container  #重启运行的容器
rm        Remove one or more containers  #移除一个或者多个容器
# 移除一个或多个镜像(无容器使用该镜像才可以删除,否则需要删除相关容器才可以继续或者-f强制删除)
rmi       Remove one or more images 
run       Run a command in a new container  #创建一个新的容器并运行一个命令
save      Save an image(s) to a tar archive#保存一个镜像为一个tar包(对应load)
search    Search the Docker Hub for images  #在docker hub中搜索镜像
start     Start one or more stopped containers#启动容器
# 统计容器使用资源
stats     Display a live stream of container(s) resource usage statistics 
stop      Stop a running container  #停止容器
tag       Tag an image into a repository  #给源中镜像打标签
top       Display the running processes of a container #查看容器中运行的进程信息
unpause   Unpause all processes within a container  #取消暂停容器
version   Show the Docker version information#查看容器版本号
# 截取容器停止时的退出状态值
wait      Block until a container stops, then print its exit code

6. 作业练习

Docker 安装 Nginx

# 1. 搜索镜像 search 建议去docker hub搜索,可以看到帮助文档
[root@localhost ~]# docker search nginx

# 2. 下载镜像 pull
[root@localhost ~]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
8740c948ffd4: Pull complete 
d2c0556a17c5: Pull complete 
c8b9881f2c6a: Pull complete 
693c3ffa8f43: Pull complete 
8316c5e80e6d: Pull complete 
b2fe3577faa4: Pull complete 
Digest: sha256:b8f2383a95879e1ae064940d9a200f67a6c79e710ed82ac42263397367e7cc4e
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

# 3. 查看镜像
[root@localhost ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
nginx         latest    a99a39d070bf   4 days ago      142MB
mysql         5.7       d410f4167eea   5 weeks ago     495MB
mysql         latest    7484689f290f   5 weeks ago     538MB
hello-world   latest    feb5d9fea6a5   15 months ago   13.3kB
centos        latest    5d0da3dc9764   16 months ago   231MB

# 4. 运行测试 
-d 	  后台运行
-name 给容器命名
-p 	  宿主机端口:容器内部端口
# 通过公网3344端口 访问 80端口
[root@localhost ~]# docker run -d --name nginx01 -p 3344:80 nginx
6f67ce367ab96638678306847487f3aeebbfdc5d42ee22715c8922e26aa3c418

# 5. 查看正在运行的镜像
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                                   NAMES
6f67ce367ab9   nginx     "/docker-entrypoint.…"   22 seconds ago   Up 22 seconds   0.0.0.0:3344->80/tcp, :::3344->80/tcp   nginx01

# 本机测试
[root@localhost ~]# curl localhost:3344
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style> html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; } </style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# vmware 浏览器输入 localhost:3344 测试结果如下

 
# 进入容器
[root@localhost ~]# docker exec -it nginx01 /bin/bash
root@6f67ce367ab9:/# whereis nginx		# 找到 Nginx 位置
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@6f67ce367ab9:/# cd /etc/nginx
root@6f67ce367ab9:/etc/nginx# ls
conf.d	fastcgi_params	mime.types  modules  nginx.conf  scgi_params  uwsgi_params

# 退出容器
root@6f67ce367ab9:/etc/nginx# exit
exit

端口暴露

思考问题:我们每次改动 nginx 配置文件,都需要进入容器内部?十分麻烦,我要是可以在容器外部提供一个映射路径,达到在容器外部修改文件名,容器内部就可以自动修改?-v 数据卷 技术!

Docker 安装 Tomcat

# 官方的使用
docker run -it --rm tomcat:9.0
 
# 我们之前的启动都是后台的,停止了容器之后, 容器还是可以查到,docker run -it --rm 一般用来测试,用完就删
 
# 下载再启动
[root@localhost ~]# docker pull tomcat
Using default tag: latest
latest: Pulling from library/tomcat
6e3729cf69e0: Pull complete 
4d8d923227d8: Pull complete 
eda8241fd25f: Pull complete 
35dccabde73d: Pull complete 
978c906bcdda: Pull complete 
08704f8dfd0f: Pull complete 
ebe8c94df885: Pull complete 
Digest: sha256:c44757f6f0838ad3a4bb3788d9eddaabadf3476e99058320ab5b3beb2f223315
Status: Downloaded newer image for tomcat:latest
docker.io/library/tomcat:latest
 
# 启动运行
[root@localhost ~]# docker run -d -p 3355:8080 --name tomcat01 tomcat
709c9a405c5a1d70c429cdb77afba60541dd8338eada85aa8af9279297d5fd2a
 
# 测试访问没有问题
[root@localhost ~]# curl localhost:3355
<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 – Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.</p><hr class="line" /><h3>Apache Tomcat/10.1.5</h3></body></html>
# 这里404是因为 webapps 目录下没有文件可访问

# 进入容器
[root@localhost ~]# docker exec -it tomcat01 /bin/bash
 
# 发现问题:
# 1. linux命令少了
# 2. webapps下内容为空,阿里云镜像的原因默认是最小的镜像,所有不必要的都剔除了,保证最小可运行环境即可
# 解决办法:
# 将 webapps.dist 下的文件都拷贝到webapps下即可

# 查看 /tomcat目录下有哪些文件
root@709c9a405c5a:/usr/local/tomcat# ls
bin           CONTRIBUTING.md  logs            README.md      temp          work
BUILDING.txt  lib              native-jni-lib  RELEASE-NOTES  webapps
conf          LICENSE          NOTICE          RUNNING.txt    webapps.dist

# 查看 webapps 目录,发现是空文件夹
root@709c9a405c5a:/usr/local/tomcat# cd webapps/
root@709c9a405c5a:/usr/local/tomcat/webapps# ls

# 进入并查看 webapps.dist 目录
root@709c9a405c5a:/usr/local/tomcat/webapps# cd ..
root@709c9a405c5a:/usr/local/tomcat# cd webapps.dist/
root@709c9a405c5a:/usr/local/tomcat/webapps.dist# ls
docs  examples  host-manager  manager  ROOT

# 拷贝 webapps.dist 目录下所有文件到 webapps 目录下
root@709c9a405c5a:/usr/local/tomcat/webapps.dist# cd ..
root@709c9a405c5a:/usr/local/tomcat# cp webapps.dist/* webapps
cp: -r not specified; omitting directory 'webapps.dist/docs'
cp: -r not specified; omitting directory 'webapps.dist/examples'
cp: -r not specified; omitting directory 'webapps.dist/host-manager'
cp: -r not specified; omitting directory 'webapps.dist/manager'
cp: -r not specified; omitting directory 'webapps.dist/ROOT'
root@709c9a405c5a:/usr/local/tomcat# cp -r webapps.dist/* webapps

# 拷贝完成后进入 webapps 目录下查看是否拷贝成功
root@709c9a405c5a:/usr/local/tomcat# cd webapps/
root@709c9a405c5a:/usr/local/tomcat/webapps# ls
docs  examples  host-manager  manager  ROOT

# 拷贝成功后 vmware浏览器 输入 localhost:3355 访问
root@709c9a405c5a:/usr/local/tomcat/webapps#

# 测试成功

思考问题: 我们以后要部署项目,如果每次都要进入容器是不是十分麻烦?要是可以在容器外部提供一个映射路径,比如 webapps,我们在外部放置项目,就自动同步内部就好了!

Docker 部署 es + kibana

# es 暴露的端口很多
# es 十分的耗内存
# es 的数据一般需要放置到安全目录! 挂载
# --net somenetwork 网络配置
 
# 启动elasticsearch
docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
 
[root@localhost ~]# docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
Unable to find image 'elasticsearch:7.6.2' locally
7.6.2: Pulling from library/elasticsearch
ab5ef0e58194: Pull complete 
c4d1ca5c8a25: Pull complete 
941a3cc8e7b8: Pull complete 
43ec483d9618: Pull complete 
c486fd200684: Pull complete 
1b960df074b2: Pull complete 
1719d48d6823: Pull complete 
Digest: sha256:1b09dbd93085a1e7bca34830e77d2981521a7210e11f11eda997add1c12711fa
Status: Downloaded newer image for elasticsearch:7.6.2
094aee7e49285d0d80901950ae1699ed7ebc62a18b16a9072950fb2f27c196e2
 
# 启动了linux就卡主了,docker stats 查看cpu状态
 
# 测试一下es成功了
[root@localhost ~]# curl localhost:9200
{
  "name" : "094aee7e4928",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "HDEz88sKRcKdKBAcdS14gg",
  "version" : {
    "number" : "7.6.2",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
    "build_date" : "2020-03-26T06:34:37.794943Z",
    "build_snapshot" : false,
    "lucene_version" : "8.4.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}
# 查看CPU状态

# 测试成功就关掉elasticSearch,可以添加内存的限制,修改配置文件 -e 环境配置修改
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED          STATUS          PORTS                                                                                  NAMES
094aee7e4928   elasticsearch:7.6.2   "/usr/local/bin/dock…"   20 minutes ago   Up 20 minutes   0.0.0.0:9200->9200/tcp, :::9200->9200/tcp, 0.0.0.0:9300->9300/tcp, :::9300->9300/tcp   elasticsearch
[root@localhost ~]# docker stop 094aee7e4928
094aee7e4928

# 添加内存限制命令
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2

# 由于第一次启动容器时名字为 elasticsearch 需要修改名称
[root@localhost ~]# docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
docker: Error response from daemon: Conflict. The container name "/elasticsearch" is already in use by container "094aee7e49285d0d80901950ae1699ed7ebc62a18b16a9072950fb2f27c196e2". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.

# 容器名改为 elasticsearch02 后再启动
[root@localhost ~]# docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
2cd96d37d925cd872667fe3eddcfe85be574d415ca6504c35e2a3027560ebb3e

# 启动成功,再次查看CPU状态

# elasticsearch02 可以正常访问
[root@localhost ~]# curl localhost:9200
{
  "name" : "2cd96d37d925",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "9pHj-2gPR3qphsoeqn_ipg",
  "version" : {
    "number" : "7.6.2",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
    "build_date" : "2020-03-26T06:34:37.794943Z",
    "build_snapshot" : false,
    "lucene_version" : "8.4.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

使用 kibana 连接 es (elasticSearch)?思考网络如何才能连接

7. 可视化

  • portainer(先用这个)

    docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
    
    
    [root@localhost ~]# docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
    Unable to find image 'portainer/portainer:latest' locally
    latest: Pulling from portainer/portainer
    772227786281: Pull complete 
    96fd13befc87: Pull complete 
    0bad1d247b5b: Pull complete 
    b5d1b01b1d39: Pull complete 
    Digest: sha256:47b064434edf437badf7337e516e07f64477485c8ecc663ddabbe824b20c672d
    Status: Downloaded newer image for portainer/portainer:latest
    96a0e9a04cef8f2caa97d7918b591abeb9aed95a81198f323cb381996ceb0e33
    
    # 测试
    [root@localhost ~]# curl localhost:8088
    
    # 外网访问 http://ip:8088
    
  • Rancher(CI/CD 再用)

Docker 镜像

1. 镜像是什么

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时库、环境变量和配置文件。所有应用,直接打包 docker 镜像,就可以直接跑起来!

如何得到镜像

  • 从远程仓库下载
  • 别人拷贝给你
  • 自己制作一个镜像 DockerFile

2. Docker 镜像加载原理

UnionFs (联合文件系统)

UnionFs(联合文件系统):Union 文件系统(UnionFs)是一种分层、轻量级并且高性能的文件系统,他支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下( unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

Docker 镜像加载原理

docker 的镜像实际上由一层一层的文件系统组成,这种层级的文件系统 UnionFS。

  • boots(boot file system)主要包含 bootloader 和 Kernel, bootloader 主要是引导加 kernel, Linux 刚启动时会加 bootfs 文件系统,在 Docker 镜像的最底层是 boots。这一层与我们典型的 Linux/Unix 系统是一样的,包含 boot 加载器和内核。当 boot 加载完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs 转交给内核,此时系统也会卸载 bootfs。
  • rootfs(root file system), 在 bootfs 之上。包含的就是典型 Linux 系统中的 / dev,/proc,/bin,/etc 等标准目录和文件。 rootfs 就是各种不同的操作系统发行版,比如 Ubuntu, Centos 等等。

平时我们安装进虚拟机的 CentOS 都是好几个 G,为什么 Docker 这里才 231M?

[root@localhost ~]# docker images centos
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
centos       latest    5d0da3dc9764   16 months ago   231MB

对于个精简的 OS,rootfs 可以很小,只需要包合最基本的命令,工具和程序库就可以了,因为底层直接用 Host 的 kernel,自己只需要提供 rootfs 就可以了。由此可见对于不同的 Linux 发行版, boots 基本是一致的, rootfs 会有差別,因此不同的发行版可以共用 bootfs.

虚拟机是分钟级别,容器是秒级!

3. 分层理解

分层的镜像

我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层层的在下载

[root@localhost ~]# docker pull redis
Using default tag: latest
latest: Pulling from library/redis
8740c948ffd4: Already exists 			# 分层下载 之前下载过的不再重新下载 资源共享
a2271c958e57: Pull complete 
495af11a3eac: Pull complete 
20d8f888dfb3: Pull complete 
43f7f644570b: Pull complete 
95e0e23bb0c6: Pull complete 
Digest: sha256:bb474c35022ca2c5618f4c49ca759bd2c0eea1daf5d934c560bd30092b97b498
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest

思考:为什么 Docker 镜像要采用这种分层的结构呢?

最大的好处,我觉得莫过于资源共享了!比如有多个镜像都从相同的 Base 镜像构建而来,那么宿主机只需在磁盘上保留一份 base 镜像,同时内存中也只需要加载一份 base 镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。

查看镜像分层的方式可以通过 docker image inspect 命令

[root@localhost ~]# docker image inspect redis
[ {
        "Id": "sha256:5f2e708d56aa0ee930aad29e8d7ca3dd7d39e89a376082df2361cdaa9f8c492b",
        "RepoTags": [
            "redis:latest" ],
        "RepoDigests": [
            "redis@sha256:bb474c35022ca2c5618f4c49ca759bd2c0eea1daf5d934c560bd30092b97b498"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2023-01-11T09:15:57.520201738Z",
        "Container": "0fba760b1e45121c88c49b4b14b5361a311eecd157b67065e580967658b8b7be",
        "ContainerConfig": {
            "Hostname": "0fba760b1e45",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "6379/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOSU_VERSION=1.14",
                "REDIS_VERSION=7.0.7",
                "REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-7.0.7.tar.gz",
                "REDIS_DOWNLOAD_SHA=8d327d7e887d1bb308fc37aaf717a0bf79f58129e3739069aaeeae88955ac586"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"redis-server\"]"
            ],
            "Image": "sha256:f7745bb085fa0a06b36fa09f14c4c1e30dba93fc2dcbf31c5023734964e37455",
            "Volumes": {
                "/data": {}
            },
            "WorkingDir": "/data",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {}
        },
        "DockerVersion": "20.10.12",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "6379/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOSU_VERSION=1.14",
                "REDIS_VERSION=7.0.7",
                "REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-7.0.7.tar.gz",
                "REDIS_DOWNLOAD_SHA=8d327d7e887d1bb308fc37aaf717a0bf79f58129e3739069aaeeae88955ac586"
            ],
            "Cmd": [
                "redis-server"
            ],
            "Image": "sha256:f7745bb085fa0a06b36fa09f14c4c1e30dba93fc2dcbf31c5023734964e37455",
            "Volumes": {
                "/data": {}
            },
            "WorkingDir": "/data",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 116956061,
        "VirtualSize": 116956061,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/f736edbecb4586afed4fbc88e2b28dae16e235e3eb29f95f374e4ae1bdb0fa0d/diff:/var/lib/docker/overlay2/05d45c7b49c27f02b93f78e4f02f302e0f9f2f939605e3de2e435ae8273a1f83/diff:/var/lib/docker/overlay2/b768536996b4186de0ad5333d795da0eeceb1ecc2c749983656b10b941d759a8/diff:/var/lib/docker/overlay2/6a83d79d5b44dd27e017b4a7b87f17e3958f5959c12fc95a8d8e45f57fad0c46/diff:/var/lib/docker/overlay2/edd138d6a958d219b2aa47f70e107f24b21084dbc57d587fe10daa91c6c7e499/diff",
                "MergedDir": "/var/lib/docker/overlay2/8d204166cf47b6b42007d106ae25fa4d2a1093e85440c39b10c00a4628c68236/merged",
                "UpperDir": "/var/lib/docker/overlay2/8d204166cf47b6b42007d106ae25fa4d2a1093e85440c39b10c00a4628c68236/diff",
                "WorkDir": "/var/lib/docker/overlay2/8d204166cf47b6b42007d106ae25fa4d2a1093e85440c39b10c00a4628c68236/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:67a4178b7d47beb6a1f697a593bd0c6841c67eb0da00f2badefb05fd30671490",
                "sha256:9185b51f7cba08c174012626d7f279551badfc0a196dd6af8ccd63a521ce2a17",
                "sha256:f699114ed8adc0a3c0dcc3e12795e887eb0304553d028bb52fed3ea8afc975b4",
                "sha256:751b224c6ef67ce8b22d4f77f852fc82b9daa4428278bd9e7ebba15aa32082d4",
                "sha256:bf099afb8c49d295e431fa9eddb66606d3cc1045d2c31ace32e96e4652e2157f",
                "sha256:77a6f6646d90c7ba85e542601fd902c85dfd3f4c4c1b1058cf27251e66edefba"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

理解:

所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或培加新的内容时,就会在当前镜像层之上,创建新的镜像层。

举一个简单的例子,假如基于 Ubuntu Linux16.04 创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python 包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创健第三个镜像层该像当前已经包含 3 个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。

在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点.

在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含 3 个文件,而镜像包含了来自两个镜像层的 6 个文件。

上图中的镜像层跟之前图中的略有区別,主要目的是便于展示文件
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有 6 个文件,这是因为最上层中的文件 7 是文件 5 的一个更新版。

这种情況下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中

Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统

Linux 上可用的存储引撃有 AUFS、 Overlay2、 Device Mapper、Btrfs 以及 ZFS。顾名思义,每种存储引擎都基于 Linux 中对应的文件系统或者块设备技术,井且每种存储引擎都有其独有的性能特点。

Docker 在 Windows 上仅支持 windowsfilter 一种存储引擎,该引擎基于 NTFS 文件系统之上实现了分层和 CoW [1]。

下图展示了与系统显示相同的三层镜像。所有镜像层堆并合井,对外提供统一的视图。

特点

Docker 镜像都是只读的,当容器启动时,一个新的可写层加载到镜像的顶部!

这一层就是我们通常说的容器层,容器之下的都叫镜像层!

4. commit 镜像

docker commit 提交容器成为一个新的版本
 
# 命令 和 git 原理类似
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG]
 
docker commit -a="kuangshen" -m="add webapps app" a7507d192a52 tomcat02:1.0

实战测试

# 1. 启动一个默认的tomcat
[root@localhost ~]# docker run -it -p 8080:8080 tomcat
# 注意:此时tomcat 正在运行,需要新开一个 xshell 窗口

# 2. 发现这个默认的tomcat是没有webapps应用, 镜像的原因,官方镜像默认webapps下面是没有内容的
# 查看 开启的 tomcat 容器 id
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE                 COMMAND             CREATED              STATUS              PORTS                                                                                            NAMES
a7507d192a52   tomcat                "catalina.sh run"   About a minute ago   Up About a minute   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp                                                        elastic_leavitt
7b3d52e39f4d   portainer/portainer   "/portainer"        2 hours ago          Up 39 minutes       0.0.0.0:8000->8000/tcp, :::8000->8000/tcp, 0.0.0.0:9000->9000/tcp, :::9000->9000/tcp, 9443/tcp   portainer

# 进入容器里面
[root@localhost ~]# docker exec -it a7507d192a52 /bin/bash
root@a7507d192a52:/usr/local/tomcat# ls
bin           CONTRIBUTING.md  logs            README.md      temp          work
BUILDING.txt  lib              native-jni-lib  RELEASE-NOTES  webapps
conf          LICENSE          NOTICE          RUNNING.txt    webapps.dist
root@a7507d192a52:/usr/local/tomcat# cd webapps/
root@a7507d192a52:/usr/local/tomcat/webapps# ls
# webapps 目录为空

# 3. 我自己拷贝进去了基本的文件
root@a7507d192a52:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@a7507d192a52:/usr/local/tomcat# cd webapps/
root@a7507d192a52:/usr/local/tomcat/webapps# ls
docs  examples  host-manager  manager  ROOT
root@a7507d192a52:/usr/local/tomcat/webapps# exit
exit

# 4. 将我们操作过的容器通过commit提价为一个镜镜像!我们以后就使用我们自己制作的镜像了
docker commit -m="描述信息" -a="作者" 容器id 镜像名:[TAG]

[root@localhost ~]# docker commit -a="kuangshen" -m="add webapps app" a7507d192a52 tomcat02:1.0
sha256:066dacdc61c5ef9f3ae441c67737e8fc94931dcd9fbe93ff117c0bbe36ea08e0

[root@localhost ~]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
tomcat02              1.0       066dacdc61c5   9 seconds ago   479MB
tomcat                latest    ad4994520144   41 hours ago    475MB
redis                 latest    5f2e708d56aa   4 days ago      117MB
nginx                 latest    a99a39d070bf   4 days ago      142MB
mysql                 5.7       d410f4167eea   5 weeks ago     495MB
mysql                 latest    7484689f290f   5 weeks ago     538MB
portainer/portainer   latest    5f11582196a4   7 weeks ago     287MB
hello-world           latest    feb5d9fea6a5   15 months ago   13.3kB
centos                latest    5d0da3dc9764   16 months ago   231MB
elasticsearch         7.6.2     f29a1ee41030   2 years ago     791MB

学习方式说明:理解概念,但是一定要实践,最后实践和理论相结合一次搞定这个知识

如果你想要保存当前容器的状态,就可以通过 commit 来提交,获得一个镜像,就好比我们我们使用虚拟机的快照(这个狂神老师在讲 Linux 的时候演示过)。

学到这里才算入门 Docker!

容器数据卷

1. 什么是容器数据卷

Docker 的理念回顾

将应用和环境打包成一个镜像!

数据?如果数据都在容器中,那么我们容器删除,数据就会丢失!需求:数据可以持久化

MySQL,容器删除了,删库跑路!需求:MySQL 数据可以存储在本地!

容器之间可以有一个数据共享的技术!Docker 容器中产生的数据,同步到本地!

这就是卷技术!目录的挂载,将我们容器内的目录,挂载到 Linux 上面!

总结一句话:容器的持久化和同步操作!容器间也是可以数据共享的!

2. 使用数据卷

方式一:直接使用命令来挂载 -v

docker run -it -v 主机目录:容器目录
 
[root@localhost home]# docker run -it -v /home/ceshi:/home centos /bin/bash

# 启动起来我们可以通过 docker inspect 容器id
[root@localhost home]# docker inspect ba89afec3284

测试文件的同步(容器内创建文件,主机上查看是否存在该文件)

再来测试:

  1. 停止容器
  2. 宿主机上修改文件
  3. 启动容器
  4. 容器内的数据依旧是同步的

好处:我们以后修改只需要在本地修改即可,容器内会自动同步!

3. 实战:安装 MySQL

思考:MySQL 的数据持久化的问题!

# 获取镜像
[root@localhost home]# docker pull mysql:5.7
 
# 运行容器, 需要做数据挂载! # 安装启动mysql,需要配置密码(注意)
# 官方测试, docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
 
# 启动我们的
-d      # 后台运行
-p      # 端口隐射
-v      # 卷挂载
-e      # 环境配置
--name  # 容器的名字
[root@localhost ~]# docker run -d -p 3310:3306 -v /home/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
3d46c92da4aecb58d65932b9ac67e663c1592ba12c1b19cd9b0abefbcd0318aa
[root@localhost ~]# 
 
# 启动成功之后,我们在本地使用navicat链接测试一下
# navicat链接到服务器的3310 --- 3310 和 容器的3306映射,这个时候我们就可以连接上mysql了
 
# 在本地测试创建一个数据库,查看下我们的路径是否ok!

当我们在本地用 navicat 新建名称为 test 的数据库时候,容器容器也会创建

[root@localhost mysql]# cd data/
[root@localhost data]# ls
auto.cnf         ib_buffer_pool  mysql               server-cert.pem
ca-key.pem       ibdata1         mysql.sock          server-key.pem
ca.pem           ib_logfile0     performance_schema  sys
client-cert.pem  ib_logfile1     private_key.pem
client-key.pem   ibtmp1          public_key.pem
[root@localhost data]# ls
auto.cnf         ib_buffer_pool  mysql               server-cert.pem
ca-key.pem       ibdata1         mysql.sock          server-key.pem
ca.pem           ib_logfile0     performance_schema  sys
client-cert.pem  ib_logfile1     private_key.pem     test	# 测试成功
client-key.pem   ibtmp1          public_key.pem

假设我们将包含 mysql 的容器删除时,发现我们挂载到本地的数据卷依旧没有丢失,这就实现了容器数据持久化功能

# 删除容器
[root@localhost home]# docker rm -f mysql01
mysql01
[root@localhost home]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@localhost home]# 

# 再次查看发现数据没有丢失
[root@localhost mysql]# cd data/
[root@localhost data]# ls
auto.cnf         ib_buffer_pool  mysql               server-cert.pem
ca-key.pem       ibdata1         mysql.sock          server-key.pem
ca.pem           ib_logfile0     performance_schema  sys
client-cert.pem  ib_logfile1     private_key.pem     test
client-key.pem   ibtmp1          public_key.pem
# 测试成功

4. 具名和匿名挂载

# 匿名挂载
-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx     # -P 随机指定端口
 
# 查看所有volume的情况
[root@localhost ~]# docker volume ls
DRIVER    VOLUME NAME
local     69e89930157ed8062e49efa5231040e72398665bdf899222893bc81407dedc77
local     b0ff91bba6f22437de470859a4dd9117651a08bb995db250439e70cc941c60e8
local     b559b9830c0d90ad738d8752a1d4ea747544cd092c6ccebde863add8d6ef3f7c
local     ec97a3bd9c839c70581bc8ded7b7e46702c23f9f1de2a1324843030a0b7f3214
local     portainer_data
 
# 这里发现,这种情况就是匿名挂载,我们在-v 后面只写了容器内的路径,没有写容器外的路径!
 
# 具名挂载
[root@localhost ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
2a0e9d11f935616ce5dbd033cb9e20bfba5109c2d5c10c37947f550fbcb41a9f
[root@localhost ~]# docker volume ls
DRIVER    VOLUME NAME
local     69e89930157ed8062e49efa5231040e72398665bdf899222893bc81407dedc77
local     b0ff91bba6f22437de470859a4dd9117651a08bb995db250439e70cc941c60e8
local     b559b9830c0d90ad738d8752a1d4ea747544cd092c6ccebde863add8d6ef3f7c
local     ec97a3bd9c839c70581bc8ded7b7e46702c23f9f1de2a1324843030a0b7f3214
local     juming-nginx
local     portainer_data
 
# 通过-v 卷名:容器内的路径
# 查看一下这个卷
# docker volume inspect juming-nginx
 
[root@localhost ~]# docker volume inspect juming-nginx
[
    {
        "CreatedAt": "2023-01-16T20:23:16+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
        "Name": "juming-nginx",
        "Options": null,
        "Scope": "local"
    }
]

所有 docker 容器内的卷,没有指定目录的情况下都是在/var/lib/docker/volumes/xxxxx/_data

[root@localhost ~]# cd /var/lib/docker

[root@localhost docker]# ls
buildkit    image    overlay2  runtimes  tmp    volumes
containers  network  plugins   swarm     trust

[root@localhost docker]# cd volumes/

[root@localhost volumes]# ls
69e89930157ed8062e49efa5231040e72398665bdf899222893bc81407dedc77
b0ff91bba6f22437de470859a4dd9117651a08bb995db250439e70cc941c60e8
b559b9830c0d90ad738d8752a1d4ea747544cd092c6ccebde863add8d6ef3f7c
backingFsBlockDev
ec97a3bd9c839c70581bc8ded7b7e46702c23f9f1de2a1324843030a0b7f3214
juming-nginx
metadata.db
portainer_data

[root@localhost volumes]# cd juming-nginx/

[root@localhost juming-nginx]# ls
_data

[root@localhost juming-nginx]# cd _data/

[root@localhost _data]# ls
conf.d          mime.types  nginx.conf   uwsgi_params
fastcgi_params  modules     scgi_params
[root@localhost _data]#

我们通过具名挂载可以方便的找到我们的一个卷,大多数情况下使用的是具名挂载

# 如何确定是具名挂载还是匿名挂载,还是指定路径挂载!
-v  容器内路径                  # 匿名挂载
-v  卷名:容器内路径              # 具名挂载
-v /宿主机路径:容器内路径           # 指定路径挂载

拓展:

# 通过 -v 容器内容路径 ro rw 改变读写权限
ro  readonly    # 只读
rw  readwrite   # 可读可写
 
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
 
# ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内容无法操作

5. 初识 DockerFile

Dockerfile 就是用来构建 docker 镜像的构建文件!命令脚本!先体验一下!

通过这个脚本可以生成镜像,镜像是一层一层的,脚本是一个个的命令,每个命令都是一层!

# 创建一个dockerfile文件, 名字可以随机
# 文件的内容 指定(大写) 参数
 
FROM centos
 
VOLUME ["volume01", "volume02"]
 
CMD echo "----end----"
CMD /bin/bash
 
# 这里的每一个命令都是镜像的一层!

# 演示
[root@localhost home]# ls
ceshi  kuangshen.java  kuangstudy  mysql  test  xiaotengteng
[root@localhost home]# mkdir docker-test-volume
[root@localhost home]# ls
ceshi               kuangshen.java  mysql  xiaotengteng
docker-test-volume  kuangstudy      test
[root@localhost home]# cd docker-test-volume/
[root@localhost docker-test-volume]# vim dockerfile1
[root@localhost docker-test-volume]# cat dockerfile1 
FROM centos

VOLUME ["volume01","volume02"]

CMD echo "------end------"
CMD /bin/bash

[root@localhost docker-test-volume]# docker build -f dockerfile1 -t kuangshen/centos:1.0 .
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM centos
 ---> 5d0da3dc9764
Step 2/4 : VOLUME ["volume01","volume02"]
 ---> Running in 84103fc77779
Removing intermediate container 84103fc77779
 ---> 477dccc5f4c6
Step 3/4 : CMD echo "------end------"
 ---> Running in 8c70e98453fc
Removing intermediate container 8c70e98453fc
 ---> e12765888029
Step 4/4 : CMD /bin/bash
 ---> Running in 4da6cf3c101a
Removing intermediate container 4da6cf3c101a
 ---> f07cc199aa83
Successfully built f07cc199aa83
Successfully tagged kuangshen/centos:1.0
[root@localhost docker-test-volume]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
kuangshen/centos      1.0       f07cc199aa83   49 seconds ago   231MB	# 自制镜像
tomcat02              1.0       066dacdc61c5   23 hours ago     479MB
tomcat                latest    ad4994520144   2 days ago       475MB
redis                 latest    5f2e708d56aa   5 days ago       117MB
nginx                 latest    a99a39d070bf   5 days ago       142MB
mysql                 5.7       d410f4167eea   5 weeks ago      495MB
mysql                 latest    7484689f290f   5 weeks ago      538MB
portainer/portainer   latest    5f11582196a4   8 weeks ago      287MB
hello-world           latest    feb5d9fea6a5   15 months ago    13.3kB
centos                latest    5d0da3dc9764   16 months ago    231MB
elasticsearch         7.6.2     f29a1ee41030   2 years ago      791MB
[root@localhost docker-test-volume]#

启动自己的容器

这个卷和外部一定有一个同步的目录!

查看一下卷挂载的路径

[root@localhost home]# docker inspect 7358cddaa2cc

测试一下刚才的文件是否同步出去了!

这种方式使用的十分多,因为我们通常会构建自己的镜像!

假设构建镜像时候没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径!

6. 数据卷容器

多个 MySQL 同步数据!

# 测试 启动3个容器,通过刚才自己写的镜像启动
$ docker run -it --name docker01 kuansgehn/centos:latest

[root@localhost ~]# docker run -it --name docker01 kuangshen/centos:1.0

# 查看容器docekr01内容
$ ls -l
[root@947075f57b0d /]# ls -l
total 0
lrwxrwxrwx.   1 root root   7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x.   5 root root 360 Jan 16 13:35 dev
drwxr-xr-x.   1 root root  66 Jan 16 13:35 etc
drwxr-xr-x.   2 root root   6 Nov  3  2020 home
lrwxrwxrwx.   1 root root   7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx.   1 root root   9 Nov  3  2020 lib64 -> usr/lib64
drwx------.   2 root root   6 Sep 15  2021 lost+found
drwxr-xr-x.   2 root root   6 Nov  3  2020 media
drwxr-xr-x.   2 root root   6 Nov  3  2020 mnt
drwxr-xr-x.   2 root root   6 Nov  3  2020 opt
dr-xr-xr-x. 192 root root   0 Jan 16 13:35 proc
dr-xr-x---.   2 root root 162 Sep 15  2021 root
drwxr-xr-x.  11 root root 163 Sep 15  2021 run
lrwxrwxrwx.   1 root root   8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x.   2 root root   6 Nov  3  2020 srv
dr-xr-xr-x.  13 root root   0 Jan 16 09:19 sys
drwxrwxrwt.   7 root root 171 Sep 15  2021 tmp
drwxr-xr-x.  12 root root 144 Sep 15  2021 usr
drwxr-xr-x.  20 root root 262 Sep 15  2021 var
drwxr-xr-x.   2 root root   6 Jan 16 13:35 volume01
drwxr-xr-x.   2 root root   6 Jan 16 13:35 volume02

# docker01 volume01 目录下 创建 volume01.java
[root@947075f57b0d /]# cd volume01
[root@947075f57b0d volume01]# touch volume01.java
[root@947075f57b0d volume01]# ls
volume01.java

# 不关闭该容器退出
CTRL + Q + P  

# 创建docker02: 并且让docker02 继承 docker01
$ docker run -it --name docker02 --volumes-from docker01 kuangshen/centos:1.0

# 查看容器docker02内容
$ ls -l

# docker03 volume01 目录下新建 volume03.java
[root@1445b38660a7 volume01]# touch docker03.java
[root@1445b38660a7 volume01]# ls
docker03.java  volume01.java

# 测试 docker01 docker02 docker03 同步

docker01 volume01 目录下 创建 volume01.java 测试 docker02

docker03 volume01 目录下 创建 volume03.java 测试 docker01

# 测试:删除docker01,查看一下docker02和docker03是否可以访问这个文件
# 结果:数据依旧保留在docker02和docker03中,没有被删除

多个 mysql 实现数据共享

[root@localhost home]# docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
 
[root@localhost home]# docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7

# 这个时候,可以实现两个容器数据同步!

结论

容器之间配置信息的传递, 数据卷容器的声明周期一直持续到没有容器使用为止。

但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的!

DockerFile

1. DockerFile 介绍

dockerfile 是用来构建 docker 镜像的文件!命令参数脚本!

构建步骤:

  1. 编写一个 dockerfile 文件
  2. docker build 构建称为一个镜像
  3. docker run 运行镜像
  4. docker push 发布镜像(DockerHub 、阿里云仓库)

很多官方镜像都像是基础包,很多功能都不具备,我们通常会自己搭建自己的镜像!

官方既然可以制作镜像,能我们一样可以!

2. DockerFile 构建过程

基础知识

  1. 每个保留关键字(指令)都是必须大写字母
  2. 执行从上到下顺序执行
  3. # 表示注释
  4. 每个指令都会创建提交一个新的镜像层,并提交!

dockerFile 是面向开发的, 我们以后要发布项目, 做镜像, 就需要编写 dockefile 文件, 这个文件十分简单!

Docker 镜像逐渐成为企业的交互标准,必须要掌握!

步骤:开发,部署, 运维… 缺一不可!

  • DockerFile: 构建文件, 定义了一切的步骤,源代码
  • DockerImages: 通过 DockerFile 构建生成的镜像, 最终发布和运行的产品!
  • Docker 容器:容器就是镜像运行起来提供服务器

3. DockerFile 指令

FROM			# 基础镜像,一切从这里开始构建
MAINTAINER		# 镜像是谁写的,	姓名 + 邮箱
RUN				# 镜像构建的时候需要运行的命令
ADD				# 步骤:tomcat镜像,这个tomcat压缩包!添加内容
WORKDIR			# 镜像的工作目录
VOLUME			# 挂载的目录
EXPOSE			# 保留端口配置
CMD				# 指定这个容器地动的时候需要运行的命令,只有最后一个会生效,可被替代
ENTRYROINT		# 指定这个容器启动的时候需要运行的命令,可以追加命令
ONBUILD			# 当构建一个被继承 DockerFile 这个时候就会运行 ONBUILD 指令,触发指令
COPY			# 类似 ADD 将我们文件拷贝到镜像中
ENV				# 构建的时候设置环境变量

4. 实战测试

Docker Hub 中 99% 的镜像都是从这个基础镜像过来的 FROM scratch,然后配置需要的软件和配置来进行构建。

FROM scratch Docker hub 地址:scratch - Official Image | Docker Hub

创建一个自己的 centos

# 1. 编写Dockerfile的文件
[root@localhost ~]# cd /home
[root@localhost home]# ls
ceshi  docker-test-volume  kuangshen.java  kuangstudy  mysql  test  xiaotengteng
[root@localhost home]# mkdir dockerfile
[root@localhost home]# cd dockerfile/
[root@localhost dockerfile]# ls
[root@localhost dockerfile]# vim mydockerfile-centos
[root@localhost dockerfile]# cat mydockerfile-centos 
FROM centos				# 这里改为 FROM centos:7
MAINTAINER kuangshen<[email protected]>

ENV MYPATH /usr/local	# 镜像的工作目录
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80 
CMD echo $MYPATH
CMD echo "------end------"
CMD /bin/bash

# 2. 通过这个文件构建镜像
# 命令 docker build -f dockerfile文件路径 -t 镜像名:[tag] .
 
[root@localhost dockerfile]# docker build -f mydockerfile-centos -t mycentos:0.1 .
 
# 注意:出现这个错误:Error: Failed to download metadata for repo 'appstream': Cannot prepare internal mirrorlist: No URLs in mirrorlist
# 修改 mydockerfile-centos 文件 第一行改为:FROM centos:7 再次 build 成功~
# Successfully built dc383b355742
# Successfully tagged mycentos:0.1

# 3. 测试

对比之前原生的 centos:

我们自己创建的 mycentos:

我们可以列出本地进行的变更历史

# 命令
docker history IMAGE ID
docker history REPOSITORY:[TAG]		# 需要指定版本号,不然默认最新找不到
# 研究一下 mycentos 怎么做的?

CMD 和 ENTRYPOINT 区别?

CMD				# 指定这个容器地动的时候需要运行的命令,只有最后一个会生效,可被替代
ENTRYROINT		# 指定这个容器启动的时候需要运行的命令,可以追加命令

测试 CMD:

# 1. 编写dockerfile文件
[root@localhost dockerfile]# vim dockerfile-cmd-test 
FROM centos
CMD ["ls","-a"]
 
# 2. 构建镜像
[root@localhost dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .
Sending build context to Docker daemon  3.072kB
Step 1/2 : FROM centos
 ---> 5d0da3dc9764
Step 2/2 : CMD ["ls","-a"]
 ---> Running in ad8a41710c48
Removing intermediate container ad8a41710c48
 ---> 70716c929ec4
Successfully built 70716c929ec4
Successfully tagged cmdtest:latest
 
# 3. run运行, 发现我们的ls -a 命令生效
[root@localhost dockerfile]# docker run cmdtest
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
 
# 想追加一个命令 -l 变成 ls -al
[root@localhost dockerfile]# docker run cmdtest -l
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-l": executable file not found in $PATH: unknown.
 
# cmd的情况下 -l替换了CMD["ls", "-a"]命令, -l不是命令,所以报错了

# 解决办法,输入完整的命令
[root@localhost dockerfile]# docker run 70716c929ec4 ls -al
total 0
drwxr-xr-x.   1 root root   6 Jan 17 08:57 .
drwxr-xr-x.   1 root root   6 Jan 17 08:57 ..
-rwxr-xr-x.   1 root root   0 Jan 17 08:57 .dockerenv
lrwxrwxrwx.   1 root root   7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x.   5 root root 340 Jan 17 08:57 dev
drwxr-xr-x.   1 root root  66 Jan 17 08:57 etc
drwxr-xr-x.   2 root root   6 Nov  3  2020 home
lrwxrwxrwx.   1 root root   7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx.   1 root root   9 Nov  3  2020 lib64 -> usr/lib64
drwx------.   2 root root   6 Sep 15  2021 lost+found
drwxr-xr-x.   2 root root   6 Nov  3  2020 media
drwxr-xr-x.   2 root root   6 Nov  3  2020 mnt
drwxr-xr-x.   2 root root   6 Nov  3  2020 opt
dr-xr-xr-x. 187 root root   0 Jan 17 08:57 proc
dr-xr-x---.   2 root root 162 Sep 15  2021 root
drwxr-xr-x.  11 root root 163 Sep 15  2021 run
lrwxrwxrwx.   1 root root   8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x.   2 root root   6 Nov  3  2020 srv
dr-xr-xr-x.  13 root root   0 Jan 17 05:24 sys
drwxrwxrwt.   7 root root 171 Sep 15  2021 tmp
drwxr-xr-x.  12 root root 144 Sep 15  2021 usr
drwxr-xr-x.  20 root root 262 Sep 15  2021 var

测试 ENTRYPOINT:

# 1. 编写dockerfile文件
[root@localhost dockerfile]# vim dockerfile-entrypoint-test 
FROM centos
ENTRYPOINT ["ls","-a"]
 
# 2. 构建文件
[root@localhost dockerfile]# docker build -f dockerfile-entrypoint-test -t entrypoint-test .
Sending build context to Docker daemon  4.096kB
Step 1/2 : FROM centos
 ---> 5d0da3dc9764
Step 2/2 : ENTRYPOINT ["ls","-a"]
 ---> Running in 8503248ef636
Removing intermediate container 8503248ef636
 ---> 663643713ed3
Successfully built 663643713ed3
Successfully tagged entrypoint-test:latest

 
# 3. run运行 发现我们的ls -a 命令同样生效
[root@localhost dockerfile]# docker run entrypoint-test
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

 
# 4. 我们的追加命令, 是直接拼接到ENTRYPOINT命令的后面的!
[root@localhost dockerfile]# docker run entrypoint-test -l
total 0
drwxr-xr-x.   1 root root   6 Jan 17 09:08 .
drwxr-xr-x.   1 root root   6 Jan 17 09:08 ..
-rwxr-xr-x.   1 root root   0 Jan 17 09:08 .dockerenv
lrwxrwxrwx.   1 root root   7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x.   5 root root 340 Jan 17 09:08 dev
drwxr-xr-x.   1 root root  66 Jan 17 09:08 etc
drwxr-xr-x.   2 root root   6 Nov  3  2020 home
lrwxrwxrwx.   1 root root   7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx.   1 root root   9 Nov  3  2020 lib64 -> usr/lib64
drwx------.   2 root root   6 Sep 15  2021 lost+found
drwxr-xr-x.   2 root root   6 Nov  3  2020 media
drwxr-xr-x.   2 root root   6 Nov  3  2020 mnt
drwxr-xr-x.   2 root root   6 Nov  3  2020 opt
dr-xr-xr-x. 187 root root   0 Jan 17 09:08 proc
dr-xr-x---.   2 root root 162 Sep 15  2021 root
drwxr-xr-x.  11 root root 163 Sep 15  2021 run
lrwxrwxrwx.   1 root root   8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x.   2 root root   6 Nov  3  2020 srv
dr-xr-xr-x.  13 root root   0 Jan 17 05:24 sys
drwxrwxrwt.   7 root root 171 Sep 15  2021 tmp
drwxr-xr-x.  12 root root 144 Sep 15  2021 usr
drwxr-xr-x.  20 root root 262 Sep 15  2021 var

Dockerfile 中很多命令都十分的相似,我们需要了解它们的区别,我们最好的学习就是对比他们然后测试效果!

5. 实战:Tomcat 镜像

  1. 准备镜像文件 tomcat 压缩包,jdk 的压缩包!

  1. 编写 Dockerfile 文件,官方命名Dockerfile, build 会自动寻找这个文件,就不需要 - f 指定了!

    [root@localhost kuangstudy]# cat Dockerfile 
    FROM centos:7
    MAINTAINER xiaotengteng<[email protected]>
    
    COPY readme.txt /usr/local/readme.txt
    
    ADD apache-tomcat-9.0.45.tar.gz /usr/local/
    ADD jdk-8u202-linux-x64.tar.gz /usr/local
    
    RUN yum -y install vim
    
    ENV MYPATH /usr/local
    WORKDIR $MYPATH
    
    ENV JAVA_HOME /usr/local/jdk1.8.0_202
    ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
    ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.45
    ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.45
    ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
    
    EXPOSE 8080
    
    CMD /usr/local/apache-tomcat-9.0.45/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.45/logs/catalina.out
    
  2. 构建镜像

    [root@localhost kuangstudy]# docker build -t divtomcat .
    
    # 成功
    Successfully built 64df1594a9e0
    Successfully tagged divtomcat:latest
    
  3. 运行镜像

    [root@localhost kuangstudy]# docker run -d -p 8888:8080 --name tomcat01 -v /home/kuangstudy/test:/usr/local/apache-tomcat-9.0.45/webapps/test -v /home/kuangstudy/tomcatlogs/:/usr/local/apache-tomcat-9.0.45/logs divtomcat
    b4b5dfdcdd6bfc9ae0194654493e07ea34261e5ba60aa8651d8909c3f1bbd9ce
    [root@localhost kuangstudy]# ls
    apache-tomcat-9.0.45.tar.gz  Dockerfile  jdk-8u202-linux-x64.tar.gz  readme.txt  test  tomcatlogs
    
  4. 测试

    [root@localhost kuangstudy]# curl localhost:8888
    # 测试通过(vmware虚拟机浏览器)
    

  1. 发布项目

    在本地编写 web.xml 和 index.jsp 进行测试

    [root@localhost kuangstudy]# cd test/
    
    # test 目录下新建 WEB-INF 文件夹
    [root@localhost test]# mkdir WEB-INF
    [root@localhost test]# ls
    WEB-INF
    [root@localhost test]# cd WEB-INF/
    
    [root@localhost WEB-INF]# vim web.xml
    [root@localhost WEB-INF]# ls
    web.xml
    [root@localhost WEB-INF]# cd ..
    
    # test 目录下 新建 index.jsp
    [root@localhost test]# vim index.jsp
    [root@localhost test]# ls
    index.jsp  WEB-INF			
    [root@localhost test]# 
    
    # 注意:如果 divtomcat 可以正常访问 ,添加页面后显示不出来,大概率文件位置不对
    # index.jsp  WEB-INF	同级
    

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4" 
        xmlns="http://java.sun.com/xml/ns/j2ee" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
            http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    
    </web-app>
    

    index.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>hello,divtomcat</title>
    </head>
    <body>
    Hello World!<br/>
    <%
    System.out.println("-----my test web logs------");
    %>
    </body>
    </html>
    

发现:项目部署成功, 可以直接访问 ok!

我们以后开发的步骤:需要掌握 Dockerfile 的编写! 我们之后的一切都是使用 docker 进行来发布运行的!

6. 发布自己的镜像

发布到 Docker Hub

  1. 注册账号:Choose plan | Docker Hub

  2. 登录账号

    [root@localhost ~]# docker login -u xiaotengteng
    Password: 
    WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
    Configure a credential helper to remove this warning. See
    https://docs.docker.com/engine/reference/commandline/login/#credentials-store
    
    Login Succeeded
    
    [root@localhost ~]# docker login --help
    
    Usage:  docker login [OPTIONS] [SERVER]
    
    Log in to a Docker registry.
    If no server is specified, the default is defined by the daemon.
    
    Options:
      -p, --password string   Password
          --password-stdin    Take the password from stdin
      -u, --username string   Username
    
  3. 提交镜像

    # push 自己的镜像到服务器上!
    [root@localhost ~]# docker push divtomcat
    Using default tag: latest
    The push refers to repository [docker.io/library/divtomcat]
    88f9efa396da: Preparing 
    56a91cea6bab: Preparing 
    ce8582d676b6: Preparing 
    6216c86fdcb5: Preparing 
    174f56854903: Preparing 
    denied: requested access to the resource is denied		# 被拒绝
    
    # 解决,增加一个 tag
    [root@localhost ~]# docker tag 64df1594a9e0 xiaotengteng/tomcat:1.0
    
    # docker push 上去即可 自己发布的镜像带上版本号
    [root@localhost ~]# docker push xiaotengteng/tomcat:1.0
    The push refers to repository [docker.io/xiaotengteng/tomcat]
    88f9efa396da: Pushing [==========================================>        ]    211MB/248.6MB
    56a91cea6bab: Pushing [=========================>                         ]  205.3MB/402.5MB
    ce8582d676b6: Pushed 
    6216c86fdcb5: Pushed 
    174f56854903: Pushed
    

发布到阿里云镜像上

由于使用 vmware + centos7 学习 docker,省略!

7. 小结

Docker 网络

1. 理解 Docker0

清空所有环境

# 删除所有容器
[root@localhost ~]# docker rm -f $(docker ps -aq)

# 删除所有镜像
[root@localhost ~]# docker rmi -f $(docker images -aq)

# 查看是否删除干净
[root@localhost ~]# docker images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@localhost ~]#

测试

三个网络

docker 是如何处理容器访问的?

注意:如果出现 OCI runtime exec failed: exec failed: unable to start container process: exec: “xxx”: executable file not found in $PATH: unknown

解决办法:参考我的文章:Docker 报错:OCI runtime exec failed: exec failed: unable to start container process: exec: “xxx“: exec

# 测试  运行一个tomcat
[root@localhost ~]# docker run -d -P --name tomcat01 tomcat

# 查看容器内部网络地址
[root@localhost ~]# docker exec -it tomcat01 ip addr

# 发现容器启动的时候会得到一个 eth0@if15 ip地址,docker分配!
[root@localhost ~]# docker exec -it tomcat01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
       
# 思考? linux能不能ping通容器内部! 可以 容器内部可以ping通外界吗? 可以!
[root@localhost ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=1.79 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.073 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.047 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.062 ms
64 bytes from 172.17.0.2: icmp_seq=5 ttl=64 time=0.042 ms
64 bytes from 172.17.0.2: icmp_seq=6 ttl=64 time=0.049 ms
64 bytes from 172.17.0.2: icmp_seq=7 ttl=64 time=0.051 ms
64 bytes from 172.17.0.2: icmp_seq=8 ttl=64 time=0.054 ms
64 bytes from 172.17.0.2: icmp_seq=9 ttl=64 time=0.049 ms
64 bytes from 172.17.0.2: icmp_seq=10 ttl=64 time=0.045 ms
64 bytes from 172.17.0.2: icmp_seq=11 ttl=64 time=0.048 ms
^C
--- 172.17.0.2 ping statistics ---
11 packets transmitted, 11 received, 0% packet loss, time 10017ms
rtt min/avg/max/mdev = 0.042/0.210/1.790/0.499 ms

原理

  1. 我们每启动一个 docker 容器, docker 就会给 docker 容器分配一个 ip, 我们只要安装了 docker,就会有一个网卡 docker0 桥接模式,使用的技术是 veth-pair 技术!

  1. 再启动一个容器测试,发现又多了一对网络

# 我们发现这个容器带来网卡,都是一对对的
# veth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
# 正因为有这个特性 veth-pair 充当一个桥梁,连接各种虚拟网络设备的
# OpenStac,Docker容器之间的连接,OVS的连接,都是使用evth-pair技术
  1. 我们来测试下 tomcat01 和 tomcat02 是否可以 ping 通

网络模型图

结论:tomcat01 和 tomcat02 共用一个路由器,docker0。

所有的容器不指定网络的情况下,都是 docker0 路由的,docker 会给我们的容器分配一个默认的可用 ip。

小结

Docker 使用的是 Linux 的桥接,宿主机是一个 Docker 容器的网桥 docker0

Docker 中的所有的网络接口都是虚拟的,虚拟的转发效率高!(内网传递文件!)

只要容器删除,对应的网桥一对就没有了!

思考一个场景,我们编写了一个微服务,database url =ip; 项目不重启,数据 ip 换掉了,我们希望可以处理这个问题,可以按名字来进行访问容器

[root@localhost ~]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
 
# 如何可以解决呢?
# 通过--link既可以解决网络连通问题
[root@localhost ~]# docker run -d -P  --name tomcat03 --link tomcat02 tomcat

[root@localhost ~]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.088 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.052 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=3 ttl=64 time=0.059 ms
^C
--- tomcat02 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 0.052/0.066/0.088/0.015 ms

 
# 反向可以ping通吗?
[root@localhost ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known

探究:inspect!

[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
b50bcd7c98f3   bridge    bridge    local
25281b130c59   host      host      local
6cf909ffc700   none      null      local
[root@localhost ~]# docker network inspect b50bcd7c98f3

[root@localhost ~]# docker inspect tomcat03

查看 tomcat03 里面的 / etc/hosts 发现有 tomcat02 的配置

[root@localhost ~]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.3	tomcat02 bc31af7e3491
172.17.0.4	a75f916dfc11

本质探究: –link 就是我们在 hosts 配置中增加了一个 172.17.0.3 tomcat02 bc31af7e3491

我们现在玩 Docker 已经不建议使用–link 了!

自定义网络!不使用 Docker0!

Docker0 的问题:它不支持容器名链接访问!

3. 自定义网络

[root@localhost ~]# docker network --help

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

Run 'docker network COMMAND --help' for more information on a command.

查看所有的 Docker 网络

网络模式

  • bridge: 桥接模式,桥接 docker 默认,自己创建的也是用 brdge 模式
  • none: 不配置网络
  • host: 和宿主机共享网络
  • container:容器网络连通!(用的少, 局限很大)

测试:

# 我们直接启动的命令默认有一个 --net bridge,而这个就是我们的docker0
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat
 
# docker0特点,默认,容器名不能访问, --link可以打通连接!
# 我们可以自定义一个网络!
# --driver bridge
# --subnet 192.168.0.0/16 可以支持255*255个网络 192.168.0.2 ~ 192.168.255.254
# --gateway 192.168.0.1

[root@localhost ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
69a7c50526f18db92a33c21f41e0e471f5386d28dbfb431e5a344f3037339ff7
[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
0e75846d6fba   bridge    bridge    local
25281b130c59   host      host      local
69a7c50526f1   mynet     bridge    local
6cf909ffc700   none      null      local

我们自己创建的网络就 ok 了!

在自己创建的网络里面启动两个容器

[root@localhost ~]# docker run -d -P --name tomcat-net-01 --net mynet tomcat
f68749f62a9098bc7e075a02ac5143a95f960ea12d4ce9f0ceae6f2aba31550e
[root@localhost ~]# docker run -d -P --name tomcat-net-02 --net mynet tomcat
d19200bfb48e26bc0bb86bd1229f26ab46f0d66bd6f92f90c2bebdf3fd049bc5
[root@localhost ~]# docker network inspect mynet

# 再次 ping 连接
[root@localhost ~]# docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.113 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.093 ms
^C
--- 192.168.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.093/0.103/0.113/0.010 ms

# 现在不使用 --link也可以ping名字了!
[root@localhost ~]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.068 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.096 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.094 ms

我们自定义的网络 docker 都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络

好处:

  • redis - 不同的集群使用不同的网络,保证集群时安全和健康的
  • mysql - 不同的集群使用不同的网络,保证集群时安全和健康的

4. 网络连通

命令

测试打通 tomcat01 和 mynet

[root@localhost ~]# docker network connect  mynet tomcat01
 
# 连通之后就是讲tomcat01 放到了mynet网路下
# 一个容器两个ip地址:
# 阿里云服务器,公网ip,私网ip

# 连通
[root@localhost ~]# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.100 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.085 ms
^C
--- tomcat-net-01 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.085/0.092/0.100/0.012 ms
# 依旧无法连通,没有connect
[root@localhost ~]# docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known

结论:假设要跨网络 操作别人,就要使用 docker network connect 连通…!

5. 实战:部署 Redis 集群

# 创建网卡
docker network create redis --subnet 172.38.0.0/16

[root@localhost ~]# docker network create redis --subnet 172.38.0.0/16
dde96d09df5fe3c20f1d4f8a7821d6bbe0a1e06fec84d3022fb334b832bddc74
[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
0e75846d6fba   bridge    bridge    local
25281b130c59   host      host      local
69a7c50526f1   mynet     bridge    local
6cf909ffc700   none      null      local
dde96d09df5f   redis     bridge    local		# 创建成功
 
# 通过脚本创建六个redis配置
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done

# 创建结点1
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
 
#创建结点2
docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
-v /mydata/redis/node-2/data:/data \
-v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
#创建结点3
docker run -p 6373:6379 -p 16373:16379 --name redis-3 \
-v /mydata/redis/node-3/data:/data \
-v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
#创建结点4
docker run -p 6374:6379 -p 16374:16379 --name redis-4 \
-v /mydata/redis/node-4/data:/data \
-v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
#创建结点5
docker run -p 6375:6379 -p 16375:16379 --name redis-5 \
-v /mydata/redis/node-5/data:/data \
-v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
#创建结点6
docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
-v /mydata/redis/node-6/data:/data \
-v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
 
# 创建集群
[root@localhost redis]# docker exec -it redis-1 /bin/sh
/data # ls
appendonly.aof  nodes.conf

redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1

/data # redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:63
79 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: 77b9c92e2e1a5f7f0b89f428df16aadef5f297fa 172.38.0.11:6379
   slots:[0-5460] (5461 slots) master
M: 49993e0ea79e508edba087bfea62331cd5f36917 172.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
M: 5df269fb48a94370d4fcf4d535fb4e3c02a36263 172.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
S: f0a376b90dd4b1503d2373879bd18f53f85c3029 172.38.0.14:6379
   replicates 5df269fb48a94370d4fcf4d535fb4e3c02a36263
S: b2cc61686a0fd381062657567769d4401f90ab6a 172.38.0.15:6379
   replicates 77b9c92e2e1a5f7f0b89f428df16aadef5f297fa
S: d90fd3cea39a5280f1682b68cc4ceef8907be317 172.38.0.16:6379
   replicates 49993e0ea79e508edba087bfea62331cd5f36917
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 172.38.0.11:6379)
M: 77b9c92e2e1a5f7f0b89f428df16aadef5f297fa 172.38.0.11:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: d90fd3cea39a5280f1682b68cc4ceef8907be317 172.38.0.16:6379
   slots: (0 slots) slave
   replicates 49993e0ea79e508edba087bfea62331cd5f36917
M: 5df269fb48a94370d4fcf4d535fb4e3c02a36263 172.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: b2cc61686a0fd381062657567769d4401f90ab6a 172.38.0.15:6379
   slots: (0 slots) slave
   replicates 77b9c92e2e1a5f7f0b89f428df16aadef5f297fa
M: 49993e0ea79e508edba087bfea62331cd5f36917 172.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: f0a376b90dd4b1503d2373879bd18f53f85c3029 172.38.0.14:6379
   slots: (0 slots) slave
   replicates 5df269fb48a94370d4fcf4d535fb4e3c02a36263
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
/data #

docker 搭建 redis 集群完成!

我们使用 docker 之后,所有的技术都会慢慢变得简单起来!

6. SpringBoot 微服务打包 Docker 镜像

  1. 构建 springboot 项目

    package com.kuang.docker.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloController {
    
        @GetMapping("/hello")
        public String hello(){
            return "hello,Docker!";
        }
    }
    // 本地 测试 成功
    
  2. 打包运行

    mvn package
    
  3. 编写 dockerfile

    FROM java:8
    
    COPY *.jar /app.jar
    
    CMD ["--server.port=8080"]
    
    EXPOSE 8080
    
    ENTRYPOINT ["java", "-jar", "/app.jar"]
    

    问题:

    [root@localhost idea]# docker build -t kuangshen666 .
    Sending build context to Docker daemon  17.57MB
    Step 1/5 : FROM java:8
    manifest for java:8 not found: manifest unknown: manifest unknown
    

    解决办法 (不推荐):

    # 修改 Dockerfile 文件
    [root@localhost idea]# cat Dockerfile 
    FROM openjdk:8			# 修改为 openjdk:8
    
    COPY *.jar /app.jar
    
    CMD ["--server.port=8080"]
    
    EXPOSE 8080
    
    ENTRYPOINT ["java", "-jar", "/app.jar"]
    
  4. 构建镜像

    [root@localhost idea]# docker build -t kuangshen666 .
    Sending build context to Docker daemon  17.57MB
    Step 1/5 : FROM openjdk:8
    8: Pulling from library/openjdk
    001c52e26ad5: Downloading [========>                                          ]  9.726MB/55MB
    d9d4b9b6e964: Download complete 
    2068746827ec: Download complete 
    9daef329d350: Downloading [======>                                            ]  7.551MB/54.58MB
    d85151f15b66: Download complete 
    52a8c426d30b: Download complete 
    8754a66e0050: Downloading [==>                                                ]  5.385MB/105.9MB
    ..............
    # 等待构建完成
    
  5. 发布运行

    # 查看镜像
    [root@localhost idea]# docker images
    
    # 运行容器
    [root@localhost idea]# docker run -d -P --name kuangshen-springboot-web kuangshen666
    fd9a353a80bfd61f6930c16cd92204532bfd734e003f3f9983b5128a27b0375e
    
    # 查看运行起来的容器端口(因为我们启动的时候没有指定)
    [root@iZ2zeg4ytp0whqtmxbsqiiZ idea]# docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
    fd9a353a80bf        kuangshen666          "java -jar /app.jar …"   9 seconds ago       Up 8 seconds        0.0.0.0:32779->8080/tcp   kuangshen-springboot-web
    
    # 本地访问
    [root@localhost idea]# curl localhost:32779/hello
    hello,Docker!
    

    以后我们使用了 Docker 之后,给别人交付就是一个镜像即可!

标签:容器,++,GaleTeng,博客,--,镜像,docker,root,localhost
From: https://www.cnblogs.com/sky-just-cloud/p/18180396/63-messages-docker-docker-learning-notes

相关文章

  • +63+条消息++狂神+docker+学习笔记_GaleTeng+的博客+-+CSDN+博客
    +63+条消息++狂神+docker+学习笔记_GaleTeng+的博客+-+CSDN+博客文章目录前言Docker概述1.Docker为什么会出现?2.Docker历史3.Docker能干嘛Docker安装1.Docker的基本组成2.安装Docker3.阿里云镜像加速4.回顾HelloWorld流程5.底......
  • 131. 分割回文串-c++
    给你一个字符串s,请你将s分割成一些子串,使每个子串都是回文串。返回s所有可能的分割方案。示例1:输入:s="aab"输出:[["a","a","b"],["aa","b"]]示例2:输入:s="a"输出:[["a"]]classSolution{public:vector<vector......
  • 一键自动化博客发布工具,用过的人都说好(阿里云篇)
    阿里云有个开发者社区,入驻过的朋友可能想要把自己的博客发布到阿里云社区上。今天我来介绍一下blog-auto-publishing-tools自动发布博客到阿里云的实现原理。阿里云的博客发布界面比较简单,只有标题,正文,摘要,关联试用产品,发布子社区,文章图片这几个选项。一起来看看如何实现吧。......
  • 79. 单词搜索-c++
    给定一个mxn二维字符网格board和一个字符串单词word。如果word存在于网格中,返回true;否则,返回false。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。示例1:输入......
  • C++基础-如何引入第三方静态库、动态库或自定义库 摘自 https://blog.csdn.net/u01310
    C++无论是内置库还是第三方库,都需要自己手动进行查找、配置、引入等工作。本文即是帮助完成C++项目对于库、框架如何完成依赖引入达成可调用的目的,重点讲述开发工具VisualStudio中的操作静态库(.lib)静态库引入适用用于大部分无开源的第三方库,开发者不需要关心库的具体实现如何,......
  • UEC++做拖拽时的UDragDropOperation 的PayLoad是什么
    在UnrealEngine中,使用C++进行拖拽操作时,UDragDropOperation类的Payload成员变量允许你传递与拖拽操作相关的任何类型的数据。它通常被用来存储一些关于被拖拽元素的信息,这些信息在拖拽开始时被设置,然后可以在拖拽结束时被检索和使用。Payload是一个UObject*类型的指针,这意......
  • 在UEC++中的FReply
    在UnrealEngine中,FReply是一个核心类,用于在UI事件处理中返回和控制事件的传播。它主要用于SlateUI框架,是处理输入事件(如点击、拖拽、鼠标移动等)时的回应类型。FReply用于告诉Slate事件系统一个特定的事件是否被处理,以及是否应该将事件继续传递给其他控件。例如,当一个按钮被点......
  • C++容器
    C++容器bitset构造函数//1.默认构造函数:0bitset<10>a; //a:0000000000//2.用一个数值初始化//(1)当用一个数值去构造的时候,其实就是将数值在内存中的存储方式显示出来。(数值在内存中是以补码形式存储的)//(2)若bitset的位数n小于数值的位数,只取数值(小端的)前n位......
  • c++ 模板模板参数("Template Template Parameters")
    #include<iostream>#include<vector>#include<list>usingnamespacestd;namespace_nmsp1{//T类型模板参数,代表容器中元素类型//Container代表的不是一个类型(不能是一个类型模板参数),而是一个类模板(类名)//Container不叫做类型模板参数,而叫做模板模......
  • C++ keywords
     一、C++98及以前  二、C++111.alignofa.简介:是一个运算符,用于确定类型的对齐要求。b.语法:i.alignof(type_id/object)       c.返回值:i.std::size_t        // 返回指定类型或......