pdf版本笔记的下载地址: Docker学习笔记01(访问密码:3834)

Docker学习笔记总结

  • Docker的安装
    • Docker的基本组成
    • Docker的安装
      • 演示系统环境
      • 安装步骤
      • 配置阿里云镜像加速服务
    • 运行 HelloWorld的过程中发生了什么
    • Docker与VM的比较
  • Docker命令
    • 常用Dcoker命令
      • 帮助命令
      • 镜像命令
      • 容器命令
      • 其他常用命令
    • Docker命令小结
    • 练习1: 使用Docker安装Nginx
    • 练习2: 使用Docker安装Tomcat
    • 练习3: 使用Docker部署Elasticsearch
  • 容器数据卷
    • 容器数据卷的挂载
      • 指定路径挂载
      • 匿名挂载和具名挂载
      • 指定读写权限
    • 容器间数据共享
  • Docker镜像
    • Docker镜像原理
    • Docker镜像的创建
      • 镜像commit
      • Dockerfile
        • 练习1: 构建自定义CentOS镜像
        • 练习2:构建自定义Tomcat镜像
    • 发布镜像
  • Docker网络
    • 桥接网卡`docker0`
    • `--link`
    • 自定义网络
    • 练习1: 部署一个Redis集群
    • 练习2: 将SpringBoot项目打包成Docker镜像

Docker的安装

Docker的基本组成

首先要明确镜像(image),容器(container)仓库(repository)的概念:

  • 镜像(image): Docker镜像(image)就是一个只读的模板,用于创建 Docker 容器.

    Docker镜像和容器之间的关系可以类比为Java中类和对象的关系,一个镜像可以创建很多容器.

  • 容器(container): Docker容器(container)容器是用镜像创建的运行实例.它可以被启动,开始,停止,删除.每个容器之间是相互隔离的.可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)以及运行在其中的应用程序。

  • 仓库(repository): 仓库(repository)是集中存放镜像文件的场所,可以分为为公开仓库(public)和私有仓库(private)两种形式.最大的公开仓库是DockerHub.

Docker的安装

理论上Docker只能安装在Linux环境下,Windows系统和Macos系统的Docker本质上是安装了一个Linux虚拟机,因此本教程演示在Centos上安装Docker,在其它Linux发行版上安装Docker的方式大同小异,见Install Docker Engine | Docker Documentation

亲测使用(Windows Subsystem for Linux)的Ubuntu系统是安装不上Docker的.

演示系统环境

目前Docker要求CentOs版本在运CentOS 7以上,系统为64位,系统内核版本为 3.10 以上.使用下列命令可以查看当前操作系统的内核和版本信息:

  • 使用uname -r命令查看当前操作系统的内核版本号,输出如下:

    3.10.0-1127.19.1.el7.x86_64
    
  • 使用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"
    

安装步骤

确认系统环境满足条件后进行安装,安装步骤如下:

  1. 安装gcc相关环境

    sudo yum -y install gcc
    sudo yum -y install gcc-c++
    
  2. 卸载旧版本Docker

    sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine
    
  3. 设置yum仓库

    yum install -y yum-utils# Docker官方yum仓库,国内有可能访问不上
    yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo# 如果访问不上,就运行下面备注是的这一句,设置的是阿里云镜像Docker的yum仓库
    # yum-config-manager --add-repo http://mirrors.aliyun.com/dockerce/linux/centos/docker-ce.repo
    
  4. 更新yum软件包索引

    yum makecache fast
    
  5. 安装Docker CE

    yum install docker-ce docker-ce-cli containerd.io
    
  6. 启动Docker

    systemctl start docker
    
  7. 测试命令

    运行docker version输出如下

    Client: Docker Engine - CommunityVersion:           20.10.3API version:       1.41Go version:        go1.13.15Git commit:        48d30b5Built:             Fri Jan 29 14:34:14 2021OS/Arch:           linux/amd64Context:           defaultExperimental:      trueServer: Docker Engine - CommunityEngine:Version:          20.10.3API version:      1.41 (minimum version 1.12)Go version:       go1.13.15Git commit:       46229caBuilt:            Fri Jan 29 14:32:37 2021OS/Arch:          linux/amd64Experimental:     falsecontainerd:Version:          1.4.3GitCommit:        269548fa27e0089a8b8278fc4fc781d7f65a939brunc:Version:          1.0.0-rc92GitCommit:        ff819c7e9184c13b7c2607fe6c30ae19403a7affdocker-init:Version:          0.19.0GitCommit:        de40ad0
    

    运行docker run hello-world输出如下:

    Hello from Docker!
    This message shows that your installation appears to be working correctly.To generate this message, Docker took the following steps:1. The Docker client contacted the Docker daemon.2. The Docker daemon pulled the "hello-world" image from the Docker Hub.(amd64)3. The Docker daemon created a new container from that image which runs theexecutable that produces the output you are currently reading.4. The Docker daemon streamed that output to the Docker client, which sent itto your terminal.To try something more ambitious, you can run an Ubuntu container with:$ docker run -it ubuntu bashShare images, automate workflows, and more with a free Docker ID:https://hub.docker.com/For more examples and ideas, visit:https://docs.docker.com/get-started/
    

    运行docker images输出如下:

    REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
    hello-world   latest    bf756fb1ae65   13 months ago   13.3kB
    

    上述命令都正常执行不报错,说明Docker安装成功

  8. (如果有需要的话)卸载Docker的命令:

    systemctl stop docker
    yum -y remove docker-ce docker-ce-cli containerd.io
    rm -rf /var/lib/docker
    

配置阿里云镜像加速服务

安装好Docker后,默认是从DockerHub上下载镜像的,对于国内用户来说,下载会很慢(真的很慢),因此需要国内的容器镜像服务,配置容器镜像服务的步骤如下:

  1. 注册阿里云账号,进入容器镜像服务,获得自己的镜像加速器地址,比如我的镜像加速器地址就是https://2mpejt6c.mirror.aliyuncs.com

  2. 运行下面命令,配置镜像加速器:

    sudo mkdir -p /etc/docker
    sudo tee /etc/docker/daemon.json <<-'EOF'
    {"registry-mirrors": ["https://2mpejt6c.mirror.aliyuncs.com"]       #换成你自己的镜像加速器地址
    }
    EOF
    sudo systemctl daemon-reload
    sudo systemctl restart docker
    

这样镜像加速器就配置好了

运行 HelloWorld的过程中发生了什么

运行docker run hello-world可以下载并启动一个hello-world容器,其中的运行过程如下:

#mermaid-svg-OZD6j80dwwEdk7gM {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-OZD6j80dwwEdk7gM .error-icon{fill:#552222;}#mermaid-svg-OZD6j80dwwEdk7gM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OZD6j80dwwEdk7gM .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-OZD6j80dwwEdk7gM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OZD6j80dwwEdk7gM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OZD6j80dwwEdk7gM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OZD6j80dwwEdk7gM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OZD6j80dwwEdk7gM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OZD6j80dwwEdk7gM .marker.cross{stroke:#333333;}#mermaid-svg-OZD6j80dwwEdk7gM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OZD6j80dwwEdk7gM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-OZD6j80dwwEdk7gM .cluster-label text{fill:#333;}#mermaid-svg-OZD6j80dwwEdk7gM .cluster-label span{color:#333;}#mermaid-svg-OZD6j80dwwEdk7gM .label text,#mermaid-svg-OZD6j80dwwEdk7gM span{fill:#333;color:#333;}#mermaid-svg-OZD6j80dwwEdk7gM .node rect,#mermaid-svg-OZD6j80dwwEdk7gM .node circle,#mermaid-svg-OZD6j80dwwEdk7gM .node ellipse,#mermaid-svg-OZD6j80dwwEdk7gM .node polygon,#mermaid-svg-OZD6j80dwwEdk7gM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-OZD6j80dwwEdk7gM .node .label{text-align:center;}#mermaid-svg-OZD6j80dwwEdk7gM .node.clickable{cursor:pointer;}#mermaid-svg-OZD6j80dwwEdk7gM .arrowheadPath{fill:#333333;}#mermaid-svg-OZD6j80dwwEdk7gM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-OZD6j80dwwEdk7gM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-OZD6j80dwwEdk7gM .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-OZD6j80dwwEdk7gM .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-OZD6j80dwwEdk7gM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-OZD6j80dwwEdk7gM .cluster text{fill:#333;}#mermaid-svg-OZD6j80dwwEdk7gM .cluster span{color:#333;}#mermaid-svg-OZD6j80dwwEdk7gM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-OZD6j80dwwEdk7gM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

开始
Docker在本机中寻找该镜像
本机是否有该镜像?
去Docker Hub上查找该镜像
Docker Hub上是否能找到?
以该镜像为模板生产实例运行
返回失败错误,查不到该镜像
下载该镜像到本地

Docker与VM的比较

为什么Docker比较VM快

  1. Docker有着比虚拟机更少的抽象层,运行在Docker容器上的程序直接使用的都是实际物理机的硬件资源.
  2. Docker利用的是宿主机的内核,而不需要Guest OS.

虚拟机(VM) 容器(Dcoker)
占用磁盘空间 非常大,GB级 小,MB甚至KB级
启动速度 慢,分钟级 快,秒级
运行形态 运行于Hypervisor上 直接运行在宿主机内核上
并发性 一台宿主机上十几个,最对几十个 上百个,甚至数千个
性能 逊于宿主机 接近宿主机本地进程
资源利用率

Docker命令

常用Dcoker命令

帮助命令

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

镜像命令

  1. docker images: 列出本地主机上的镜像,运行该命令得到一个表格

    REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
    hello-world   latest    bf756fb1ae65   13 months ago   13.3kB
    

    表中各项的意义:

    意义
    REPOSITORY 镜像的仓库源
    TAG 镜像的标签
    IMAGE ID 镜像的ID
    CREATED 镜像创建时间
    SIZE 镜像大小

    常用参数:

    参数 意义
    -a 列出所有镜像
    -q 静默模式,只显示镜像id
    --digests 显示镜像的摘要信息
  2. docker search: 本质上与在Docker Hub仓库中搜索镜像是一致的,不常用.

  3. docker pull 镜像名[:tag]: 下载镜像

    下载镜像的时候是分层下载的,比如运行docker pull mysql下载mysql镜像,输出如下:

    Using default tag: latest         # 不写tag,默认下载tag为latest
    latest: Pulling from library/mysql
    54fec2fa59d0: Already exists    # 分层下载,前几层已经存在,故而不需要下载
    bcc6c6145912: Already exists
    951c3d959c9d: Already exists
    05de4d0e206e: Already exists
    319f0394ef42: Already exists
    d9185034607b: Already exists
    013a9c64dadc: Already exists
    42f3f7d10903: Pull complete     # 仅需要下载不存在的层即可
    c4a3851d9207: Pull completeDigest:sha256:61a2a33f4b8b4bc93b7b6b9e65e64044aaec594809f818aeffbff69a893d1944 # 摘要信息
    Status: Downloaded newer image for mysql:latest
    docker.io/library/mysql:latest          # 镜像真实位置
    

    也可以在镜像名后加tag,指定版本,如:docker pull mysql:5.7

  4. docker rmi 镜像id: 删除镜像

    命令 意义
    docker rmi -f 镜像id 删除单个镜像
    docker rmi -f 镜像名:tag 镜像名:tag 删除多个镜像
    docker rmi -f $(docker images -qa) 结合docker images命令,删除全部镜像

容器命令

  1. docker run: 新建容器并启动

    格式: docker run [OPTIONS] IMAGE [COMMAND][ARG...]

    常用参数:

    参数 意义 例子
    --name 给容器起名 --name="container01"
    -d 以后台方式运行容器,并返回容器的id
    -i 以交互模式运行容器,通常和-t一起使用
    -t 重新指定一个终端,通常和-i一起使用 docker run -it centos /bin/bash
    -P 随机端口映射 -P 3306将容器的3306端口随机映射到宿主机的某个端口
    -p 指定端口映射 -p 3310:3306将容器的3306端口映射到宿主机的3310端口
  2. docker ps: 列出所有(正在运行的)容器

    常用参数:

    参数 意义
    -a 列出所有容器(包括历史运行过的容器)
    -l 显示最近创建的容器
    -n=? 显示最近n个创建的容器
    -q 静默模式,只显示容器id
  3. 退出容器

    命令 意义
    exit 停止容器并退出交互模式
    Ctrl+P+Q 不停止容器并退出交互模式
  4. 启动停止容器

    命令 意义
    docker start (容器id or 容器名) 启动容器
    docker restart (容器id or 容器名) 重启容器
    docker stop (容器id or 容器名) 停止容器
    docker kill (容器id or 容器名) 强制停止容器
  5. docker rm 容器id: 删除容器

    命令 意义
    docker rm 容器id 删除单个容器
    docker rm 容器id 容器id 删除多个容器
    docker rm -f $(docker ps -qa) 结合docker ps命令,删除全部容器

其他常用命令

  1. 后台启动容器: docker run -d 容器名

    问题: 直接使用docker run -d centos以后台方式启动,结果发现该容器马上停止了,这是为什么呢?

    答案: Docker容器要想后台运行,就必须有一个前台进程.容器运行的命令如果不是那些一直挂起的命令,就会在命令执行完毕后自动退出.

  2. 查看日志: docker logs 容器id

    常用参数:

    参数 意义 例子
    -t 显示时间戳
    -f 显示最近创建的容器
    --tail 打印条数 显示多少条 -tail 10

    例子: docker logs -tf --tail 10 c8530dbbe3b4

  3. 查看容器中运行的进程信息: docker top 容器id

    使用docker top 8dc189995333命令查看某容器中运行的进程信息,输出结果如下:

    UID     PID     PPID        C       STIME       TTY     TIME        CMD
    polkitd 22370   22350       0       00:36       ?       00:00:03    mysqld
    
  4. 查看容器/镜像的元数据: docker inspect 容器id

    使用docker inspect 8dc189995333命令查看某容器的元数据如下:

    [{"Id": "8dc18999533348d6aeaa31b24f3d592f8c2a1738636d3a2eb53bdaf3efbbc4c0","Created": "2021-02-07T10:27:37.756580818Z","Path": "docker-entrypoint.sh","Args": [...],"State": {"Status": "running"...},"Image": "sha256:c8562eaf9d81c779cbfc318d6e01b8e6f86907f1d41233268a2ed83b2f34e748","ResolvConfPath": "/var/lib/docker/containers/8dc18999533348d6aeaa31b24f3d592f8c2a1738636d3a2eb53bdaf3efbbc4c0/resolv.conf","HostnamePath": "/var/lib/docker/containers/8dc18999533348d6aeaa31b24f3d592f8c2a1738636d3a2eb53bdaf3efbbc4c0/hostname","HostsPath": "/var/lib/docker/containers/8dc18999533348d6aeaa31b24f3d592f8c2a1738636d3a2eb53bdaf3efbbc4c0/hosts","LogPath": "/var/lib/docker/containers/8dc18999533348d6aeaa31b24f3d592f8c2a1738636d3a2eb53bdaf3efbbc4c0/8dc18999533348d6aeaa31b24f3d592f8c2a1738636d3a2eb53bdaf3efbbc4c0-json.log","Name": "/musing_jepsen","RestartCount": 0,"Driver": "overlay2","Platform": "linux","MountLabel": "","ProcessLabel": "","AppArmorProfile": "","ExecIDs": null,"HostConfig": {"Binds": null...},"GraphDriver": {"Name": "overlay2"...},"Mounts": [...],"Config": {"Hostname": "8dc189995333"...},"NetworkSettings": {"Bridge": ""...}
    ]
    
  5. 进入正在运行的容器

    命令 意义
    docker exec -it 容器id bashShell 进入容器并打开一个新终端,启动新线程
    docker attach 容器id 进入容器并打开启动命令的终端,不会启动新进程
  6. 从容器内拷贝文件到主机上: docker cp 容器id:容器内路径 目的主机路径

Docker命令小结

命令 意义 意义
attach Attach to a running container 当前shell下attach连接指定运行镜像
build Build an image from a Dockerfile 通过Dockerfile定制镜像
commit Create a new image from a container changes 提交当前容器为新的镜像
cp Copy files/folders from the containers filesystem to the host path 从容器中拷贝指定文件或者目录到宿主机中
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 an existing container 在已存在的容器上运行命令
export Stream the contents of a container as a tar archive 导出容器的内容流作为一个tar归档文件(对应import
history Show the history of an image 展示一个镜像形成历史
images List images 列出系统当前镜像
import Create a new filesystem image from the contents of a tarball 从 tar包中的内容创建一个新的文件系统映像(对应export)
info Display system-wide information 显示系统相关信息
inspect Return low-level information on a container 查看容器详细信息
kill Kill a running container kill指定Docker容器
load Load an image from a tar archive 从一个tar包中加载一 个镜像(对应save)
login Register or Login to the docker registry server 注册或者登陆一个Docker源服务器
logout Log out from a Docker registry server 从当前Docker registry退出
logs Fetch the logs of a container 输出当前容器日志信息
port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT 查看映射端口对应的容器内部源端口
pause Pause all processes within a container 暂停容器
ps List containers 列出容器列表
pull Pull an image or a repository from the docker registry server 从Docker镜像源服务器拉取指定镜像或者库镜像
push Push an image or a repository to the docker registry server 推送指定镜像或者库镜像至Docker源服务器
restart Restart a running container 重启运行的容器
rm Remove one or more containers 移除一个或者多个容器
rmi Remove one or more images 移除一个或多个镜像(无容器使用该镜像才可删除,否则需删除相关容器才可继续或-f强制删除
run Run a command in a new container 创建一个新的容器并运行一个命令
save Save an image to a tar archive 保存一个镜像为一个tar包(对应load)
search Search for an image on the Docker Hub 在Docker Hub中搜索镜像
start Start a stopped containers 启动容器
stop Stop a running containers 停止容器
tag Tag an image into a repository 给源中镜像打标签
top Lookup the running processes of a container 查看容器中运行的进程信息
unpause Unpause a paused container 取消暂停容器
version Show the docker version information 查看Docker版本号
wait Block until a container stops, then print its exit code 截取容器停止时的退出状态值

练习1: 使用Docker安装Nginx

  1. 搜索镜像: docker search nginx,输出结果如下:

    NAME                               DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
    nginx                              Official build of Nginx.                        14445     [OK]
    jwilder/nginx-proxy                Automated Nginx reverse proxy for docker con…   1965                 [OK]
    richarvey/nginx-php-fpm            Container running Nginx + PHP-FPM capable of…   807                  [OK]
    jc21/nginx-proxy-manager           Docker container for managing Nginx proxy ho…   146
    linuxserver/nginx                  An Nginx container, brought to you by LinuxS…   141
    tiangolo/nginx-rtmp                Docker image with Nginx using the nginx-rtmp…   113                  [OK]
    ...
    
  2. 拉取镜像: docker pull nginx,输出如下:

    Using default tag: latest
    latest: Pulling from library/nginx
    a076a628af6f: Already exists
    0732ab25fa22: Pull complete
    d7f36f6fe38f: Pull complete
    f72584a26f32: Pull complete
    7125e4df9063: Pull complete
    Digest: sha256:10b8cc432d56da8b61b070f4c7d2543a9ed17c2b23010b43af434fd40e2ca4aa
    Status: Downloaded newer image for nginx:latest
    docker.io/library/nginx:latest
    
  3. 启动容器: docker run -d --name mynginx -p 3500:80 nginx,输出如下:

    58d4ab1e9f71cb183cc68e98d5cd2ceb6e856b65f85dd70fb378afb254f6c0d4   # 这是该容器的container ID
    
  4. 测试访问: curl localhost:3500,输出如下:

    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>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>
    

    得到上面结果说明Nginx启动成功.

  5. 查看容器状态: docker ps,输出如下:

    CONTAINER ID   IMAGE   COMMAND                 CREATED             STATUS              PORTS                   NAMES
    58d4ab1e9f71    nginx   "/docker-entrypoint.…"    About a minute ago  Up About a minute   0.0.0.0:3500->80/tcp mynginx
    
  6. 进入容器,查看index.html

    1. 进入容器: docker exec -it mynginx /bin/bash

    2. 查询nginx的路径: whereis nginx,输出如下:

      /usr/sbin/nginx
      /usr/lib/nginx
      /etc/nginx
      /usr/share/nginx
      
    3. 查看index.html: cat /usr/share/nginx/html/index.html,输出如下:

      <!DOCTYPE html>
      <html>
      <head>
      <title>Welcome to nginx!</title>
      <style>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>
      

练习2: 使用Docker安装Tomcat

  1. 下载Tomcat镜像: docker pull tomcat
  2. 启动: docker run -d -p 8080:8080 --name tomcat01 tomcat
  3. 进入Tomcat: docker exec -it tomcat9 /bin/bash
  4. 部署项目

练习3: 使用Docker部署Elasticsearch

使用Docker部署Elasticsearch需要考虑如下几个问题:

  1. 端口暴露问题9200,9300.
  2. 数据卷的挂载问题data,plugins,conf
  3. 内存问题: "ES_JAVA_OPTS=-Xms512m -Xmx512m"

实验步骤如下:

  1. 先启动一个Elasticsearch镜像: docker run -d --name elasticsearch01 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2

  2. 启动成功之后发现服务器很卡,使用docker stats命令查看容器状态:docker stats elasticsearch01,输出如下:

    CONTAINER ID NAME                CPU %       MEM USAGE / LIMIT       MEM %
    249ae46da625    elasticsearch01     0.00%       1.036GiB / 1.716GiB     60.37%
    

    发现是Elasticsearch占用内存太大了.

  3. 关闭这个Elasticsearch镜像: docker stop elasticsearch01

  4. 启动Elasticsearch镜像是增加内存限制: 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

  5. 使用docker stats命令查看容器状态:docker stats elasticsearch02,输出如下:

    CONTAINER ID   NAME                    CPU %       MEM USAGE / LIMIT       MEM %
    bea4a52fb840   elasticsearch02      0.45%       404.4MiB / 1.795GiB     22.00%
    

    发现这次服务就不卡了

  6. 测试访问: curl localhost:9200,输出如下:

    {"name" : "bea4a52fb840","cluster_name" : "docker-cluster","cluster_uuid" : "-adcnQWoS3S0KR4YBsDWBA","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"
    }
    

容器数据卷

随着Docker容器的删除,其中的数据也被删除了,对于数据库等应用来说这样不合适.

可以使用容器数据卷将数据挂在到本地,卷就是目录或者文件,存在于一个或者多个容器中,由Docker挂载到容器,但不属于联合文件系统,因此能够绕过 Union File System,提供一些用于持续存储或共享数据的特性.

卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷.

容器数据卷的特点:

  1. 数据卷可在容器之间共享或重用数据
  2. 卷中的更改可以直接生效
  3. 数据卷中的更改不会包含在镜像的更新中
  4. 数据卷的生命周期一直持续到没有容器使用它为止

卷就是容器的持久化,以及容器间的继承和数据共享.

容器数据卷的挂载

使用docker run命令的-v参数添加数据卷,命令格式如下:

docker run -v 挂载路径映射 镜像名

根据挂载方式不同,挂载路径映射的写法不同.

指定路径挂载

对于指定路径挂载,挂载路径映射的格式是宿主机路径:容器内路径,例如:

docker run --name centos01 -it -v /home/ceshi:/home centos /bin/bash

上述命令将容器内的/home路径挂载到宿主机的/home/ceshi路径上.

使用docker inspect命令可以查看容器数据卷: docker inspect centos01,得到输出如下,可以在Mounts节点下看到挂载的容器数据卷.

[{"Id": "a36ee54bd1f03b30820490171ef6f058dea39b5c4d1350013be462b6baa6ff09",// ..."Mounts": [{"Type": "bind","Source": "/home/ceshi","Destination": "/home","Mode": "","RW": true,"Propagation": "rprivate"}]// ...}
]

不论容器是否运行,在容器外对/home/ceshi的操作和在容器内对/home的操作是一致的.


下面演示使用容器数据卷将MySQL数据库中的数据持久化:

  1. 启动MySQL数据库时除了使用-v参数指定数据卷挂载,-p参数指定端口映射之外,还要使用-e参数指定MySQL的root用户的密码,见Docker Hub上MySQL镜像的页面.

    docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d \-v /home/mysql/data:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD=123456 \--name mysql01 \mysql
    

    上述命令将容器内的MySQL配置文件/etc/mysql/conf.d映射到宿主机的/home/mysql/conf文件上,将容器内MySQL数据文件目录/var/lib/mysql映射到宿主机/home/mysql/data目录上.

  2. 使用docker inspect命令查看数据卷挂载信息: docker inspect mysql01,得到结果如下,可以看到端口映射和数据卷挂载信息:

    [{"Id": "b9b5aa7a5a18790c3b69ee7531c825da8585e3b7c71741cff749ad9841d9db0e","Name": "/mysql01",// ..."Mounts": [     // 数据卷挂载信息{ // MySQL配置文件"etc/mysql/conf.d"映射到宿主机的"/home/mysql/conf"文件上"Type": "bind","Source": "/home/mysql/conf","Destination": "/etc/mysql/conf.d","Mode": "","RW": true,"Propagation": "rprivate"},{   // MySQL数据文件目录"/var/lib/mysql"映射到宿主机"/home/mysql/data"目录上"Type": "bind","Source": "/home/mysql/data","Destination": "/var/lib/mysql","Mode": "","RW": true,"Propagation": "rprivate"}],// ..."NetworkSettings": {// ..."Ports": {     // 容器的3306端口映射到宿主机的3310端口上"3306/tcp": [{"HostIp": "0.0.0.0","HostPort": "3310"}],"33060/tcp": null},// ...}}
    ]
    
  3. 使用数据库客户端工具连接宿主机的3310端口就能对容器中的MySQL数据库进行操作,在数据库中创建数据后查看宿主机的/home/mysql目录,发现存在对应的文件.

  4. 使用docker rm -f mysql01命令删除容器,发现主机的/home/mysql目录下的文件依然存在.

匿名挂载和具名挂载

出于可移植性的考虑,指定目录挂载的数据卷挂载方式不常用,因为宿主机路径是依赖于特定宿主机的,并不能够保证所有宿主机上都存在对应目录.

常见的数据卷挂载方式有两种:

  1. 匿名挂载: 指定数据卷在容器内的路径,挂载路径映射的格式是容器内路径.
  2. 具名挂载: 指定数据卷在容器内的路径并为数据卷命名,挂载路径映射的格式是卷名:容器内路径.

例如:

docker run -d -P --name nginx01 -v /etc/nginx nginx                  # 匿名挂载
docker run -d -P --name nginx02 -v nginx-volume:/etc/nginx nginx    # 具名挂载

为了区分具名挂载和指定路径挂载,指定路径挂载中的宿主机路径必须是绝对路径(以/开头);而具名挂载中的卷名不得以/开头.

使用docker inspect 命令可以查看数据卷挂载信息:

  • 运行命令docker inspect nginx01,输出如下:

    [{"Id": "f483cc589ff041580e114d04b5a03324e62a24c44b68485d9ed4cf2fa75f4c31","Name": "/nginx01",// ..."Mounts": [{ // 匿名挂载,"Name"属性为随机hash"Type": "volume",      "Name": "689f2a4c1b6b95079378d64fe468f256e2639ebd6aaaae2028e3cd7f33f146a0","Source": "/var/lib/docker/volumes/689f2a4c1b6b95079378d64fe468f256e2639ebd6aaaae2028e3cd7f33f146a0/_data","Destination": "/etc/nginx","Driver": "local","Mode": "","RW": true,"Propagation": ""}]// ...}
    ]
    
  • 运行命令docker inspect nginx02,输出如下:

    [{"Id": "f483cc589ff041580e114d04b5a03324e62a24c44b68485d9ed4cf2fa75f4c31","Name": "/nginx02",// ..."Mounts": [{  // 具名挂载,"Name"属性为指定的卷名"Type": "volume","Name": "nginx-volume","Source": "/var/lib/docker/volumes/nginx-volume/_data","Destination": "/etc/nginx","Driver": "local","Mode": "z","RW": true,"Propagation": ""}],// ...}
    ]
    

使用具名挂载和匿名挂载的数据卷在宿主机的/var/lib/docker/volumes目录下.使用docker volume ls命令可以查看所有容器数据卷:

DRIVER    VOLUME NAME
local     f38b9f3afda1f8511ce46668a7edd40b581c001426ca5fc2b96a11ae9038b654
local     nginx-volume

指定读写权限

挂载路径映射后加上:读写权限可以设置容器对该数据卷的读写权限,读写权限有两种:

  1. ro: 只读权限
  2. rw: 读写权限

示例如下:

docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:ro nginx   # 只读
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:rw nginx  # 读写

容器间数据共享

可以通过数据卷实现容器间数据的共享,在创建容器时使用--volumes-from 父容器参数指定从父容器中继承(共享)数据卷,实现父子容器间的数据卷共享.示例如下:

  1. 创建父容器container01,指定两个匿名挂载卷/data_volume1/data_volume1:

    docker run --name container01 -v /data_volume1 -v /data_volume2 -it centos /bin/bash
    
  2. 打开另外两个ssh窗口,分别创建子容器container02, container03,使用--volumes-from container01参数指定从container01中继承数据卷.

    docker run --name container02 --volumes-from container01 -it centos /bin/bash
    docker run --name container03 --volumes-from container01 -it centos /bin/bash
    
  3. 在某个容器中修改贡献路径下的数据,另外两个容器中的数据同步发生变化.

  4. 删除某个容器,另外两个容器中的数据不受影响.

  5. 删除所有容器,宿主机内的数据仍存在.

得出结论: 容器数据卷的生命周期一直持续到没有容器使用它为止,存储在本机的文件则会一直保留.

Docker镜像

Docker镜像原理

Linux操作系统由内核空间和用户空间组成,内核空间是kernel,Linux刚启动时会加载bootfs文件系统,之后bootfs会被卸载掉.

Dcoker镜像通过共享bootfs层模拟出多种操作系统环境

镜像是分层的:

在下载镜像时,可以看到镜像是分层下载的: docker pull redis,输出如下:

Using default tag: latest
latest: Pulling from library/redis
a076a628af6f: Already exists
f40dd07fe7be: Pull complete
ce21c8a3dbee: Pull complete
ee99c35818f8: Pull complete
56b9a72e68ff: Pull complete
3f703e7f380f: Pull complete
Digest: sha256:0f97c1c9daf5b69b93390ccbe8d3e2971617ec4801fd0882c72bf7cad3a13494
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest

使用docker inspect命令也可以查看Docker镜像的层次结构: docker inspect redis,可以在RootFS/Layers节点下看到该镜像的层次结构:

[{"Id": "sha256:621ceef7494adfcbe0e523593639f6625795cc0dc91a750629367a8c7b3ccebb",// ..."RootFS": {"Type": "layers","Layers": [      // 该镜像的6层结构"sha256:cb42413394c4059335228c137fe884ff3ab8946a014014309676c25e3ac86864","sha256:8e14cb7841faede6e42ab797f915c329c22f3b39026f8338c4c75de26e5d4e82","sha256:1450b8f0019c829e638ab5c1f3c2674d117517669e41dd2d0409a668e0807e96","sha256:f927192cc30cb53065dc266f78ff12dc06651d6eb84088e82be2d98ac47d42a0","sha256:a24a292d018421783c491bc72f6601908cb844b17427bac92f0a22f5fd809665","sha256:3480f9cdd491225670e9899786128ffe47054b0a5d54c48f6b10623d2f340632"]},// ...}
]

Docker镜像的创建

创建新镜像有两种方式: 通过docker commit命令commit容器 和 通过docker build命令根据Dockerfile创建镜像.

镜像commit

容器本质上是在镜像最上层上方附加的可写的一层.

可以使用docker commit命令将该层的修改固化下来,生成新的镜像,语法如下:

docker commit -m="提交的描述信息" -a="作者" 容器id 要创建的目标镜像名:[标签名]

下面以Tomcat镜像为例,演示如何基于已有镜像生成新镜像:

  1. 默认下载的Tomcat镜像运行之后访问其8080端口会得到404错误,因为其/usr/local/tomcat/webapps目录为空.

    1. 先使用docker run -d -p 8080:8080 --name tomcat01 tomcat命令启动Tomcat容器

    2. 使用curl localhost:8080访问8080端口,得到结果如下:

      <!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/9.0.41</h3></body></html>
      

      可以看到404错误

    3. 进入docker容器,查看其/usr/local/tomcat/webapps目录,发现其内容为空:

      docker exec -it tomcat01 /bin/bash
      ls -l /usr/local/tomcat/webapps
      

      输出如下:

      total 0
      
    4. 可以看到webapps中的默认内容都在webapps.dist目录下: ls -l /usr/local/tomcat/webapps.dist

      total 20
      drwxr-xr-x  3 root root 4096 Jan 13 08:25 ROOT
      drwxr-xr-x 15 root root 4096 Jan 13 08:25 docs
      drwxr-xr-x  7 root root 4096 Jan 13 08:25 examples
      drwxr-xr-x  6 root root 4096 Jan 13 08:25 host-manager
      drwxr-xr-x  6 root root 4096 Jan 13 08:25 manager
      
  2. 因此我们启动一个新Tomcat容器,将webapps.dist目录下的内容复制到webapps目录下:

    1. 启动Tomcat容器并进入工作目录: docker run -d -p 8080:8080 --name tomcat02 tomcat

    2. 进入容器: docker exec -it tomcat02 /bin/bash

    3. webapps.dist目录下的内容复制到webapps目录下: cp -r webapps.dist/* webapps

    4. 退出容器: Ctrl+P+Q

    5. 访问8080端口: curl localhost:8080,得到输出如下:

      <!DOCTYPE html>
      <html lang="en"><head><meta charset="UTF-8" /><title>Apache Tomcat/9.0.41</title><link href="favicon.ico" rel="icon" type="image/x-icon" /><link href="tomcat.css" rel="stylesheet" type="text/css" /></head><body><div id="wrapper"><div id="navigation" class="curved container"><span id="nav-home"><a href="https://tomcat.apache.org/">Home</a></span><span id="nav-hosts"><a href="/docs/">Documentation</a></span><span id="nav-config"><a href="/docs/config/">Configuration</a></span><span id="nav-examples"><a href="/examples/">Examples</a></span><span id="nav-wiki"><a href="https://wiki.apache.org/tomcat/FrontPage">Wiki</a></span><span id="nav-lists"><a href="https://tomcat.apache.org/lists.html">Mailing Lists</a></span><span id="nav-help"><a href="https://tomcat.apache.org/findhelp.html">Find Help</a></span><br class="separator" /></div></div><!-- ... -->    </body>
      </html>
      
  3. 通过上述步骤,我们已构建了一个可访问的Tomcat容器,之后可以通过docker commit命令将上述容器打包成镜像

    docker commit -a="chenhai" -m="copy webapps.dist/* to webapps" tomcat02 my_tomcat_image
    
  4. 使用docker images命令,可以看到我们打包的my_tomcat_image镜像:

    REPOSITORY        TAG       IMAGE ID       CREATED          SIZE
    my_tomcat_image   latest    919273b2c954   14 seconds ago   654MB
    tomcat            latest    040bdb29ab37   5 weeks ago      649MB
    
  5. 使用docker inspect命令分别查看tomcat镜像和my_tomcat_image镜像的"Layers"属性,可以看出my_tomcat_image是基于tomcat基础上构建的

    • 运行docker inspect tomcat命令,输出如下:

            [{// ..."RootFS": {"Type": "layers","Layers": [     // tomcat镜像有10层"sha256:4762552ad7d851a9901571428078281985074e5ddb806979dd7ad24748db4ca0","sha256:a1f2f42922b1d3aa948f2569adebb37129941e889f13b96823a5e2aa8ecc1a8f","sha256:ef9a7b8862f4797ec08f3733ab9fc2a08c51f44e5561b087eb10a6e442599760","sha256:aa7af8a465c6b600b7151db82799f757d0029c7fb9f170faaffdc40080c525c5","sha256:7496c5e8691b7de622ad5c1e0f9b300df55e923b960fc75e7b7cf1a297a36da8","sha256:7a9b35031285d77ce1d4e73b9eabb0a8f204b0729c3f4c342bca4e57b73fbae1","sha256:500f722b156b012903f8a0af13cfb2a8521be6b2126071f4330714b6fa5bd9d7","sha256:8e2e6f2527c7c2e81725a0d539a04281d8a32b26bf2ca57fe5f5ffe20862625d","sha256:c9132b9a3fc8c30239edb774bdf01b252e1cbe945c3994e4fa12929cc93831d4","sha256:9ddc8cd8299b64510aee4f540827bf2c5cf326aa73fdd47a599a1ee0d9a8c224"]},// ...}
      ]
      
    • 运行docker inspect my_tomcat_image命令,输出如下:

      [{// ..."RootFS": {"Type": "layers","Layers": [     // my_tomcat_image镜像有11层,可以看到前10层与tomcat镜像相同"sha256:4762552ad7d851a9901571428078281985074e5ddb806979dd7ad24748db4ca0","sha256:a1f2f42922b1d3aa948f2569adebb37129941e889f13b96823a5e2aa8ecc1a8f","sha256:ef9a7b8862f4797ec08f3733ab9fc2a08c51f44e5561b087eb10a6e442599760","sha256:aa7af8a465c6b600b7151db82799f757d0029c7fb9f170faaffdc40080c525c5","sha256:7496c5e8691b7de622ad5c1e0f9b300df55e923b960fc75e7b7cf1a297a36da8","sha256:7a9b35031285d77ce1d4e73b9eabb0a8f204b0729c3f4c342bca4e57b73fbae1","sha256:500f722b156b012903f8a0af13cfb2a8521be6b2126071f4330714b6fa5bd9d7","sha256:8e2e6f2527c7c2e81725a0d539a04281d8a32b26bf2ca57fe5f5ffe20862625d","sha256:c9132b9a3fc8c30239edb774bdf01b252e1cbe945c3994e4fa12929cc93831d4","sha256:9ddc8cd8299b64510aee4f540827bf2c5cf326aa73fdd47a599a1ee0d9a8c224","sha256:4bf57ab98abebba174523e47d442ba9dd58213ac1e28b12df21f0f10bb708146"]},// ...}
      ]
      

Dockerfile

从Dockerfile构建Docker镜像的步骤:

  1. 编写Dockerfile文件
  2. docker build 构建镜像
  3. docker run

Dockerfile的常见指令如下:

指令 意义
FROM 基础镜像,指定当前新镜像是基于哪个镜像的
MAINTAINER 镜像维护者的姓名混合邮箱地址
RUN 容器构建时需要运行的命令
EXPOSE 当前容器对外保留出的端口
WORKDIR 指定在创建容器后,终端默认登录的进来工作目录,一个落脚点
ENV 用来在构建镜像过程中设置环境变量
ADD 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
COPY 类似ADD,拷贝文件和目录到镜像中!
VOLUME 容器数据卷,用于数据保存和持久化工作
CMD 指定一个容器启动时要运行的命令,dockerFile中可以有多个CMD指令,但只有最后一个生效
ENTRYPOINT 指定一个容器启动时要运行的命令,和CMD一样
ONBUILD 当构建一个被继承的Dockerfile时运行命令,父镜像在被子镜像继承后,父镜像的ONBUILD被触发

下面以CentOS官方镜像为例,展示一个Dockerfile的内容,见CentOS的Dockerfile:

FROM scratch                 # base镜像,最基础的镜像
ADD centos-8-x86_64.tar.xz /    # 将rootfs添加到根目录并解压
LABEL org.label-schema.schema-version="1.0"     org.label-schema.name="CentOS Base Image"     org.label-schema.vendor="CentOS"     org.label-schema.license="GPLv2"     org.label-schema.build-date="20201204"
CMD ["/bin/bash"]             # 启动命令行

练习1: 构建自定义CentOS镜像

CentOS的官方Docker镜像比较精简,没有很多常用的工具,登陆后的默认路径的是根目录/.下面我们在此基础上进行修改,增加vimnet-tools,并将登陆后的默认路径修改为root用户的家目录.步骤如下:

  1. 编写Dockerfile文件:

    FROM centos                     # 基于centos镜像构建
    MAINTAINER chenh<123@qq.com> # 作者姓名和邮箱
    ENV MYPATH /root                # 设置环境变量
    WORKDIR $MYPATH                 # 设置默认登陆目录
    RUN yum -y install vim          # 安装vim
    RUN yum -y install net-tools    # 安装net-tools
    EXPOSE 80                       # 暴露80端口
    CMD echo $MYPATH                # 输出调试信息
    CMD echo "---end---"          # 输出调试信息
    CMD /bin/bash                   # 进入bash
    
  2. 进入Dockerfile所在目录,执行docker build命令构建镜像:

    docker build语法如下:

    docker build -f dockerfile地址 -t 新镜像名字:TAG .
    

    注意最后有一个.,表示当前目录.

    本实验构建my-centos镜像的命令如下:

    docker build -f Dockerfile -t my-centos .
    

    输出如下

    Step 1/10 : FROM centos---> 300e315adb2fStep 2/10 : MAINTAINER chenh<123@qq.com>---> Running in c44ab3a18589
    Removing intermediate container c44ab3a18589---> 7cd26ffc364dStep 3/10 : ENV MYPATH /root---> Running in 1b0e6f4f4fa2
    Removing intermediate container 1b0e6f4f4fa2---> 741fb6aecb01Step 4/10 : WORKDIR $MYPATH---> Running in a2b56ea26c54
    Removing intermediate container a2b56ea26c54---> 71e9bb4c397fStep 5/10 : RUN yum -y install vim---> Running in a31932ed0c54
    CentOS Linux 8 - AppStream                      1.6 MB/s | 6.3 MB     00:03
    CentOS Linux 8 - BaseOS                         588 kB/s | 2.3 MB     00:03
    CentOS Linux 8 - Extras                         8.8 kB/s | 8.6 kB     00:00
    Dependencies resolved.
    Install  5 Packages
    Complete!
    Removing intermediate container a31932ed0c54---> 5d1a36c2ee7aStep 6/10 : RUN yum -y install net-tools---> Running in 60c7b23e18ec
    Last metadata expiration check: 0:00:14 ago on Thu Feb 18 11:52:47 2021.
    Dependencies resolved.
    Total download size: 322 k
    Installed size: 942 k
    Downloading Packages:
    Complete!
    Removing intermediate container 60c7b23e18ec---> 7c09e53a2051Step 7/10 : EXPOSE 80---> Running in 2f7481e6d0e0
    Removing intermediate container 2f7481e6d0e0---> 3b2bb84afa87Step 8/10 : CMD echo $MYPATH---> Running in 08a3a22956c2
    Removing intermediate container 08a3a22956c2---> 6aef0d4c26dfStep 9/10 : CMD echo "---end---"---> Running in 9a21ec5aa63e
    Removing intermediate container 9a21ec5aa63e---> 494ed5a122adStep 10/10 : CMD /bin/bash---> Running in 3ccac448e32d
    Removing intermediate container 3ccac448e32d---> 7e2c3b0cc70eSuccessfully built 7e2c3b0cc70eSuccessfully tagged my-centos:latest
    

    可以看到Docker逐句解析并执行Dockerfile,每执行一次就生成一个新层.

  3. 运行容器:

    docker run -it my-centos
    

    运行该容器后,发现默认进入到/root目录下,且vimifconfig命令均能正常工作.

  4. 列出镜像变更历史:

    docker history my-centos
    

    可以看到镜像的变更历史如下:每一条变更历史对应一层

    IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
    7e2c3b0cc70e   6 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B
    494ed5a122ad   6 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B
    6aef0d4c26df   6 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B
    3b2bb84afa87   6 minutes ago   /bin/sh -c #(nop)  EXPOSE 80                    0B
    7c09e53a2051   6 minutes ago   /bin/sh -c yum -y install net-tools             23.3MB
    5d1a36c2ee7a   6 minutes ago   /bin/sh -c yum -y install vim                   58.1MB
    71e9bb4c397f   7 minutes ago   /bin/sh -c #(nop) WORKDIR /root                 0B
    741fb6aecb01   7 minutes ago   /bin/sh -c #(nop)  ENV MYPATH=/root             0B
    7cd26ffc364d   7 minutes ago   /bin/sh -c #(nop)  MAINTAINER chenh<123@qq.c…   0B
    300e315adb2f   2 months ago    /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
    <missing>      2 months ago    /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B
    <missing>      2 months ago    /bin/sh -c #(nop) ADD file:bd7a2aed6ede423b7…   209MB
    

练习2:构建自定义Tomcat镜像

  1. 编写Dockerfile如下:

    FROM centos
    MAINTAINER chenh<123@qq.com> #把java与tomcat添加到容器中
    ADD jdk-8u11-linux-x64.tar.gz /usr/local/
    ADD apache-tomcat-9.0.22.tar.gz /usr/local/#安装vim编辑器
    RUN yum -y install vim#设置工作访问时候的WORKDIR路径,登录落脚点
    ENV MYPATH /usr/local
    WORKDIR $MYPATH#配置java与tomcat环境变量
    ENV JAVA_HOME /usr/local/jdk1.8.0_11
    ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
    ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.22
    ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.22
    ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin#容器运行时监听的端口
    EXPOSE 8080#启动时运行tomcat
    CMD /usr/local/apache-tomcat-9.0.22/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.22/bin/logs/catalina.out
    
  2. 构建镜像: docker build -t my-tomcat .

  3. 运行容器:

    docker run -d -p 9090:8080 --name my-tomcat \-v /home/tomcat/test:/usr/local/apache-tomcat9.0.22/webapps/test \-v /home/tomcat/tomcat9logs:/usr/local/apache-tomcat9.0.22/logs \--privileged=true \        my-tomcat
    

    使用--privileged=true是为了避免因为权限报错

  4. 运行curl localhost:9090命令,得到结果如下:

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><title>Apache Tomcat/9.0.41</title><link href="favicon.ico" rel="icon" type="image/x-icon" /><link href="tomcat.css" rel="stylesheet" type="text/css" /></head><body><div id="wrapper"><div id="navigation" class="curved container"><span id="nav-home"><a href="https://tomcat.apache.org/">Home</a></span><span id="nav-hosts"><a href="/docs/">Documentation</a></span><span id="nav-config"><a href="/docs/config/">Configuration</a></span><span id="nav-examples"><a href="/examples/">Examples</a></span><span id="nav-wiki"><a href="https://wiki.apache.org/tomcat/FrontPage">Wiki</a></span><span id="nav-lists"><a href="https://tomcat.apache.org/lists.html">Mailing Lists</a></span><span id="nav-help"><a href="https://tomcat.apache.org/findhelp.html">Find Help</a></span><br class="separator" /></div></div><!-- ... -->    </body>
    </html>
    
  5. 进入/home/tomcat/test目录下,发布一个程序:

    创建web.xml,内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"id="WebApp_ID" version="2.5"><display-name>test</display-name>
    </web-app>
    

    创建a.jsp,内容如下:

    <%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>hello,kuangshen</title>
    </head><body>-----------welcome------------<%=" my docker tomcat,kuangshen666 "%><br><br><% System.out.println("-------my docker tomcat-------");%></body>
    </html>
    
  6. 运行curl localhost:9090/test/a.jsp,得到结果如下:

    <%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>hello,kuangshen</title>
    </head><body>-----------welcome------------my docker tomcat,kuangshen666 <br><br>-------my docker tomcat-------</body>
    </html>
    

发布镜像

本节略

Docker网络

在研究Docker网络之前,先删除所有镜像和容器:

docker rm -f $(docker ps -a -q)  # 删除所有容器
docker rmi -f $(docker images -qa)  # 删除全部镜像

桥接网卡docker0

在宿主机中使用ip addr查看网卡信息如下:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000link/ether 52:54:00:2f:80:19 brd ff:ff:ff:ff:ff:ffinet 172.21.16.4/20 brd 172.21.31.255 scope global eth0valid_lft forever preferred_lft foreverinet6 fe80::5054:ff:fe2f:8019/64 scope linkvalid_lft forever preferred_lft forever3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group defaultlink/ether 02:42:aa:6b:53:81 brd ff:ff:ff:ff:ff:ffinet 172.17.0.1/16 brd 172.17.255.255 scope global docker0valid_lft forever preferred_lft foreverinet6 fe80::42:aaff:fe6b:5381/64 scope linkvalid_lft forever preferred_lft forever

可以看到宿主机有3块网卡,分别是回环网卡lo,物理网卡eth0和Docker桥接网卡docker0

  • 为了验证Docker容器之间是否能够通信,创建一个容器tomcat01并查询其网卡信息:

    docker run -d -P --name tomcat01 tomcat
    docker exec -it tomcat01 ip addr
    

    可以看到tomcat01容器的网卡信息如下:

    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft forever136: eth0@if137: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group defaultlink/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0valid_lft forever preferred_lft forever
    

    在宿主机中尝试ping容器tomcat01: ping 172.17.0.2,发现能够ping通:

    64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.047 ms
    64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.053 ms
    64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.055 ms
    64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.056 ms
    ...
    

    再次在宿主机使用ip addr命令查看网卡信息,发现宿主机多出了一块网卡veth2387536@if136:

    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000# ...2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000# ...3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default# ...137: veth2387536@if136: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group defaultlink/ether 52:05:09:20:5c:f9 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet6 fe80::5005:9ff:fe20:5cf9/64 scope linkvalid_lft forever preferred_lft forever
    

    我们发现宿主机的veth2387536@if136和容器内的eth0@if137组成了一对网卡.

  • 再启动一个容器tomcat02,发现宿主机内又多了一个和容器tomcat02内网卡相对应的网卡.

    docker run -d -P --name tomcat02 tomcat
    docker exec -it tomcat02 ip addr
    

    容器tomcat02内网卡信息如下:

    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft forever138: eth0@if139: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group defaultlink/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0valid_lft forever preferred_lft forever
    

    宿主机内网卡信息如下:

    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000# ...2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000# ...3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default# ...137: veth2387536@if136: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group defaultlink/ether 52:05:09:20:5c:f9 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet6 fe80::5005:9ff:fe20:5cf9/64 scope linkvalid_lft forever preferred_lft forever139: veth2bed2bf@if138: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group defaultlink/ether 96:90:58:5a:80:62 brd ff:ff:ff:ff:ff:ff link-netnsid 1inet6 fe80::9490:58ff:fe5a:8062/64 scope linkvalid_lft forever preferred_lft forever
    
  • 下面测试宿主机与容器之间能否ping通:

    • 在宿主机内通过IP地址ping容器tomcat01,tomcat02,能够ping通.

      ping 172.17.0.2      # 在宿主机内ping容器tomcat01的IP地址,能ping通
      ping 172.17.0.3     # 在宿主机内ping容器tomcat02的IP地址,能ping通
      
    • 在容器tomcat01内通过IP地址ping宿主机和容器tomcat02,能够ping通.

      docker exec -it tomcat01 ping 172.17.0.1 # 在容器tomcat01内ping宿主机的IP地址,能ping通
      docker exec -it tomcat01 ping 172.17.0.3    # 在容器tomcat01内ping容器tomcat02的IP地址,能ping通
      
    • 在容器tomcat02内通过IP地址ping宿主机和容器tomcat01,能够ping通.

      docker exec -it tomcat02 ping 172.17.0.1 # 在容器tomcat02内ping宿主机的IP地址,能ping通
      docker exec -it tomcat02 ping 172.17.0.1    # 在容器tomcat02内ping容器tomcat01的IP地址,能ping通
      

结论: Docker在宿主机内安装的虚拟网卡docker0是一个桥接网卡,使用了veth-pair技术.

--link

使用docker0作为桥接网卡可以实现容器间的通信,但是这种方法存在一个局限: 容器间只能通过IP地址进行通信,不能通过容器名或容器id进行通信.

ping 172.17.0.2      # 在宿主机内ping容器tomcat01的IP地址,能ping通
ping tomcat01       # 在宿主机内ping容器tomcat01的容器名,不能ping通docker exec -it tomcat01 ping 172.17.0.3   # 在容器tomcat01内ping容器tomcat02的IP地址,能ping通
docker exec -it tomcat01 ping tomcat02      # 在容器tomcat01内ping容器tomcat02的容器名,不能ping通

通过在启动容器时添加--link 要连接的容器名或id参数,可以实现通过容器名或id进行通信,示例如下:

docker run -d -P --name tomcat03 --link tomcat02 tomcat

创建容器tomcat03连接到容器tomcat02中,这样就可以在容器tomcat03中t那个锅容器名或容器id来ping容器tomcat02

docker exec -it tomcat03 ping 172.17.0.3 # 在容器tomcat03内ping容器tomcat02的IP地址,能ping通
docker exec -it tomcat03 ping tomcat02      # 在容器tomcat03内ping容器tomcat02的容器名,能ping通
docker exec -it tomcat03 ping 94cd188b01ea  # 在容器tomcat03内ping容器tomcat02的容器id,能ping通

--link机制是通过修改/etc/hosts文件实现的,进入容器tomcat03查看其/etc/hosts文件: 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 94cd188b01ea   # 容器tomcat02的容器名和容器id
172.17.0.4  4ea43009c443            # 容器tomcat03自身的容器id

因为--link是通过修改hosts文件实现连接的,因此不能实现双向连接,不推荐使用.

自定义网络

使用docker network命令可以对Docker网络进行操作.

首先使用docker network ls命令列出所有网络,输出如下:

NETWORK ID     NAME      DRIVER    SCOPE
2c2577c5c04e   bridge    bridge    local
8a11f7f5238a   host      host      local
c77811056092   none      null      local

其中DRIVER属性表示网络模式,具体如下:

网络模式 docker run命令中的参数 意义
bridge --net=bridge,是docker run命令的默认参数 在Docker网桥docker0上为容器创建新的网络栈
none --net=none 不配置网络,用户可以稍后进入容器,自行配置
container --net=container:name/id 和另外一个容器共享Network namespace
host --net=host 容器和宿主机共享Network namespace
用户自定义 --net=自定义网络名 用户自己使用network相关命令定义网络,创建容器的时候可以指定为自己定义的网络

使用docker run命令创建容器时,默认参数是--net=bridge,即通过docker0网桥组网.


使用docker network inspect可以查看网络的详细信息:

docker network inspect bridge

输出如下,可以在Containers节点中看到该网络下有我们之前创建的tomcat01,tomcat02,tomcat033个容器:

[{"Name": "bridge","Id": "2c2577c5c04e67dcff83b9509b44d249f6b8f28391550a9835d840f2f1349a79","Created": "2021-02-17T23:23:27.045956359+08:00","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": null,"Config": [{"Subnet": "172.17.0.0/16","Gateway": "172.17.0.1"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {     // 我们之前创建的3个容器"3c35894e46aedb420bf560a9db4f393012a999ba99dc5679077ee3ac8113b7b4": {"Name": "tomcat01","EndpointID": "739cc96286e2bb55526b68ff0a9eab3aa65a8c09a9e524abb7d8f3630c6f5aec","MacAddress": "02:42:ac:11:00:02","IPv4Address": "172.17.0.2/16","IPv6Address": ""},"4ea43009c443efb3ba5fb0c247d63904c252092e1055e67bb70f140d35a38ee9": {"Name": "tomcat03","EndpointID": "6eaad11d71a7852e99d0ad04c2feda731e69744f273f541c98e176fc512bbdeb","MacAddress": "02:42:ac:11:00:04","IPv4Address": "172.17.0.4/16","IPv6Address": ""},"94cd188b01ea1bb3472a7c192c9edf4e322da03691baa99080ddede880fba7bf": {"Name": "tomcat02","EndpointID": "d9f7a82132ea3d467eba5434a7b5912b667f7670b331dc59f0237c96dd4730bf","MacAddress": "02:42:ac:11:00:03","IPv4Address": "172.17.0.3/16","IPv6Address": ""}},"Options": {"com.docker.network.bridge.default_bridge": "true","com.docker.network.bridge.enable_icc": "true","com.docker.network.bridge.enable_ip_masquerade": "true","com.docker.network.bridge.host_binding_ipv4": "0.0.0.0","com.docker.network.bridge.name": "docker0","com.docker.network.driver.mtu": "1500"},"Labels": {}}
]

可以使用docker network create命令创建自定义网络:

docker network create \--driver bridge \         --subnet 192.168.0.0/16 \--gateway 192.168.0.1 \mynet

在这里创建了自定义网络mynet,网络模式为桥接模式,网段为192.168.0.0/16,网关为192.168.0.0/16

在该网络下创建2个容器tomcat-mynet01tomcat-mynet02:

docker run -d -P --name tomcat-mynet01 --net mynet tomcat
docker run -d -P --name tomcat-mynet02 --net mynet tomcat

在自定义网络内,可以使用容器名或容器id访问网络内的其它容器.

docker exec -it tomcat-mynet01 ping 192.168.0.3      # 在容器tomcat-mynet01内ping容器tomcat-mynet02的IP地址,能ping通
docker exec -it tomcat-mynet01 ping tomcat-mynet02  # 在容器tomcat-mynet01内ping容器tomcat-mynet02的容器名,能ping通
docker exec -it tomcat-mynet01 ping 13251b560879    # 在容器tomcat-mynet01内ping容器tomcat-mynet02的容器id,能ping通docker exec -it tomcat-mynet02 ping 192.168.0.2     # 在容器tomcat-mynet02内ping容器tomcat-mynet01的IP地址,能ping通
docker exec -it tomcat-mynet02 ping tomcat-mynet01  # 在容器tomcat-mynet02内ping容器tomcat-mynet01的容器名,能ping通
docker exec -it tomcat-mynet02 ping da45a19c956e    # 在容器tomcat-mynet02内ping容器tomcat-mynet01的容器id,能ping通

Docker的不同网络之间默认是隔离的,可以使用docker network connect命令将容器和网络连通,格式如下:

docker network connect [OPTIONS] NETWORK CONTAINER
  • 上文创建的mynet网络和默认的docker0网络是隔离的,两个网络之间的容器不能互相访问

    docker exec -it tomcat01 ping 192.168.0.3        # 在容器tomcat01内ping容器tomcat-mynet01的IP地址,不能ping通
    docker exec -it tomcat01 ping tomcat-mynet01    # 在容器tomcat01内ping容器tomcat-mynet01的容器名,不能ping通
    docker exec -it tomcat01 ping da45a19c956e      # 在容器tomcat01内ping容器tomcat-mynet01的容器id,不能ping通
    
  • 使用docker network connect命令将tomcat01连接到mynet网络上

    docker network connect mynet tomcat01
    

    使用docker network inspect mynet命令查看mynet网络的详细信息,可以看到mynet网络下包含了tomcat01容器.

    [{"Name": "mynet","Id": "203a1e68d66172078f437d23f146dd1309592dcd6eab87a7d4461aea119bdb08",// ..."Containers": {    // 可以看到容器中除了原有的tomcat-mynet01和tomcat-mynet02容器之外,又增加了tomcat01容器"da45a19c956e881c4c445e49b301f2bcbdf0e388bc29925da080dfab19560b21": {"Name": "tomcat-mynet01","EndpointID": "da7a5a3a5e424b63359ec13637743a97359bb5ba5461aacab115f14687001bed","MacAddress": "02:42:c0:a8:00:02","IPv4Address": "192.168.0.2/16","IPv6Address": ""},"13251b5608793d7fd4ee16aae520fb9d45846f122da351438eaac0565591c438": {"Name": "tomcat-mynet02","EndpointID": "f78746e31a9d691625b271ee4ebc63774bac1a8c93956e894e494b175cbcf19a","MacAddress": "02:42:c0:a8:00:03","IPv4Address": "192.168.0.3/16","IPv6Address": ""},"3c35894e46aedb420bf560a9db4f393012a999ba99dc5679077ee3ac8113b7b4": {"Name": "tomcat01","EndpointID": "e5d23183e8ad0454c8e8de7434f6480ee304dfeb2556b64bf7b8c7591a7983bb","MacAddress": "02:42:c0:a8:00:04","IPv4Address": "192.168.0.4/16","IPv6Address": ""},},// ...}
    ]

    查看容器tomcat01的IP地址可以看到,容器tomcat01有两个IP地址: docker exec -it tomcat01 ip addr

    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft forever136: eth0@if137: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group defaultlink/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0valid_lft forever preferred_lft forever148: eth1@if149: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group defaultlink/ether 02:42:c0:a8:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 192.168.0.4/16 brd 192.168.255.255 scope global eth1valid_lft forever preferred_lft forever
    
  • 容器tomcat01可以和mynet下的容器进行通信了:

    docker exec -it tomcat01 ping 192.168.0.3      # 在容器tomcat01内ping容器tomcat-mynet01的IP地址,不能ping通
    docker exec -it tomcat01 ping tomcat-mynet01    # 在容器tomcat01内ping容器tomcat-mynet01的容器名,不能ping通
    docker exec -it tomcat01 ping da45a19c956e      # 在容器tomcat01内ping容器tomcat-mynet01的容器id,不能ping通
    

练习1: 部署一个Redis集群

  1. 创建redis网络:

    docker network create redis --subnet 172.38.0.0/16
    
  2. 启动6个Redis容器,这里使用脚本生成命令并运行:

    创建6个Redis节点的配置文件

    # 通过脚本创建六个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
    

    创建6个Redis镜像

    for port in $(seq 1 6); dodocker run \-p 637"${port}":6379 -p 1637"${port}":16379 \--name redis-"${port}" \-v /mydata/redis/node-"${port}"/data:/data \-v /mydata/redis/node-"${port}"/conf/redis.conf:/etc/redis/redis.conf \-d \--net redis --ip 172.38.0.1"${port}" \redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf;
    done
    
  3. 进入其中一个容器,创建集群

    # 进入容器redis-1
    docker exec -it redis-1 /bin/bash# 创建集群
    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
    
  4. 查看集群信息

    # 连接集群
    redis-cli -c# 查看集群信息
    cluster info# 查看节点
    cluster nodes
    

练习2: 将SpringBoot项目打包成Docker镜像

  1. 使用IDEA创建一个SpringBoot项目:

    创建项目后创建helloController.java文件如下:

    @RestController
    public class HelloController {@GetMapping("/hello")public String hello(){return "hello world";}
    }
    

    使用MAVEN将项目打包成jar包app.jar

  2. 在项目下编写Dockerfile如下:

    FROM java:8# 服务器只有dockerfile和jar在同级目录
    COPY *.jar /app.jar
    CMD ["--server.port=8080"]# 指定容器内要暴露的端口
    EXPOSE 8080
    ENTRYPOINT ["java","-jar","/app.jar"]
    
  3. 将Dockerfile和项目的jar包上传到linux服务器上,构建镜像并启动容器:

    # 构建镜像
    docker build -t my-app .# 启动容器
    docker run -d -p 8080:8080 --name my-app my-app
    
  4. 测试访问:

    curl localhost:32779/hello
    

    输出:

    hello world
    

pdf版本笔记的下载地址: Docker学习笔记01(访问密码:3834)

Docker学习笔记总结相关推荐

  1. Docker:学习笔记(1)——基础概念

    Docker:学习笔记(1)--基础概念 Docker是什么 软件开发后,我们需要在测试电脑.客户电脑.服务器安装运行,用户计算机的环境各不相同,所以需要进行各自的环境配置,耗时耗力.为了解决这个问题 ...

  2. Docker学习笔记 之 Docker安装配置使用

    简介 Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的容器.开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机).bare met ...

  3. docker学习笔记(四)使用docker搭建环境

    参考:汤小洋老师的教学视频 docker学习笔记(一)[docker 介绍.卸载.安装.配置加速] docker学习笔记(二)docker常用命令 docker学习笔记(三)镜像 docker学习笔记 ...

  4. docker学习笔记(二)docker常用命令

    参考:汤小洋老师的教学视频 docker学习笔记(一)[docker 介绍.卸载.安装.配置加速] docker学习笔记(三)镜像 docker学习笔记(四)使用docker搭建环境 docker学习 ...

  5. docker学习笔记(三)镜像

    参考:汤小洋老师的教学视频 docker学习笔记(一)[docker 介绍.卸载.安装.配置加速] docker学习笔记(二)docker常用命令 docker学习笔记(四)使用docker搭建环境 ...

  6. docker学习笔记(五)如何创建自己的阿里云镜像仓库(这是2021版的阿里云教程)

    参考:汤小洋老师的教学视频 docker学习笔记(一)[docker 介绍.卸载.安装.配置加速] docker学习笔记(二)docker常用命令 docker学习笔记(三)镜像 docker学习笔记 ...

  7. 【长篇博文】Docker学习笔记与深度学习环境的搭建和部署(二)

    长篇博文记录学习流程不容易,请关注.转发.点赞.评论,谢谢! 上一篇文章:Docker学习笔记与深度学习环境的搭建和部署(一) 文章末尾附加nvidia455.23.cuda11.1.cudnn8.0 ...

  8. 狂神 Docker学习笔记 从基础到进阶 一步到位

    Docker 学习笔记 感谢狂神的分享.附上B站视频链接. https://www.bilibili.com/video/BV1og4y1q7M4?from=search&seid=92256 ...

  9. 开源的容器虚拟化平台Docker学习笔记,个人私藏分享,不谢!

    一.Docker 简介 Docker 两个主要部件: Docker: 开源的容器虚拟化平台 Docker Hub: 用于分享.管理 Docker 容器的 Docker SaaS 平台 -- Docke ...

  10. Docker学习笔记 (4)

    Docker学习笔记 (4) Docker 网络 原理简述 ip addr查看网络地址: 问题:Docker 如何处理容器网络访问的? docker run -d -P --name tomcat01 ...

最新文章

  1. DVWA 1.9 通关秘籍
  2. 这场论文复现的华山论剑,谁能拔得头筹
  3. 15crmo焊接后多长时间探伤_承压设备渗透探伤检测方法简单操作思路
  4. [Node.js] 模块化 -- NodeJS之heroAdmin后台管理系统基础
  5. 面向对象风格的合理架构
  6. 对于response.setContentType(MIME)的解释
  7. JavaScript高级使用(一)--参数Arguments对象
  8. 《zabbix_agent客户端的添加》-5
  9. 如何解决海量数据的处理问题
  10. 全国勘察设计注册暖通空调工程师专业基础考试大纲(送审稿)
  11. 一文带你搞定AOP切面
  12. 解决win10+Ubuntu20.0.4双系统,win10时间错误问题
  13. 2022-2028年中国美容行业发展趋势前瞻与投资战略规划分析报告
  14. 完整电商项目--(八)商品订单模块(1):订单结算与 mysql事务
  15. 淘宝店铺动销率对店铺有什么影响,怎样提高店铺动销率
  16. 相关系数,互相关函数,协方差,卷积
  17. Ask, acquire, and attack: data-free UAP generation using class impressions
  18. Python字面量、注释、变量、数据类型、数据类型的转换、标识符、运算符、字符串扩展、字符串格式化、数据输入(input语句)
  19. bootstra select 下拉框多选,搜索效果
  20. 附PPT下载|网易大数据用户画像实践

热门文章

  1. linux查看日志相关
  2. Eggjs Sequelize 多表关联查询
  3. 语言特征与模式- λ演算
  4. 换钱的最少货币数(NC126/考察次数Top69/难度简单)
  5. 如何将Excel单元格内逗号分隔的内容放到多个列
  6. UVA 10480 Sabotage
  7. eclipse更改web项目的WebContent目录
  8. Android之 Bitmap使用
  9. TI Sitara AM57x 多核SoC核心板(DSP + ARM)-性能及参数资料
  10. android录音权限被占用,请问,app被用户禁止拍照和录音权限之后,拍照和录音事件应该怎么处理?...