GVKun编程网logo

Docker 容器学习与分享 03(docker容器实战)

4

想了解Docker容器学习与分享03的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于docker容器实战的相关问题,此外,我们还将为您介绍关于1.Docker容器学习之新生入门必备基础知识、

想了解Docker 容器学习与分享 03的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于docker容器实战的相关问题,此外,我们还将为您介绍关于1.Docker容器学习之新生入门必备基础知识、167 docker docker构建nginx容器系列问题 docker registry docker run docker toolbo、2.Docker容器学习之新生入门必备基础知识、3.Docker容器学习之新手基础使用的新知识。

本文目录一览:

Docker 容器学习与分享 03(docker容器实战)

Docker 容器学习与分享 03(docker容器实战)

Docker 容器的基本操作

所有的 docker 命令都是以 docker 开头,也就是指调用 docker 程序。我学习的第一个命令就是 docker run,运行一个容器。以 Docker 分享 02 中的容器为例: 这样就成功的运行了一个容器,docker run 后面跟着的 -i -t 表示为这个容器分配一个交互式界面,如果只是运行了 docker run docker.io/centos, 那么 centos 将不会给你返回一个容器的交互式页面: 如果想让容器在后台运行那么可以执行 docker run -d docker.io/centos

docker run 常用的选项有下面几种: -i 让容器的标准输入保持打开。 -t 让 Docker 分配一个伪终端并绑定到容器的标准输入上。 -d 让容器保持在后台运行 --name 为容器自定义名字,形式为 docker run --name centos docker.io/centos.

到这里就知道了如何在 centos 上运行一个容器,接下来学习了如何使一个正在运行的容器停止一个容器,在此之前先来学习一下怎么查看正在运行的容器,查看当前正在运行的容器使用 docker ps 命令: 发现之前使用 docker run docker.io/centos 创建的容器竟然没有在运行,再使用 docker ps -a 查看所有正在运行的容器: 这时发现之前运行的容器是 Exited 状态,那么重新创建一个运行的容器: 这样就创建了一个在后台运行的名为 centos 的容器,来验证一下: 可以看到创建成功了,接下来停止运行这个容器,使用 docker stop centos. 那么怎么再次重新运行这个退出的容器呢? 这样就重新将停止运行的容器重新运行了。 使用 docker attach 命令进入正在后台运行的容器。 这样就成功的进入了在后台运行的容器。

到此,就学会了容器的基本操作,让我来总结一下: docker run 运行一个容器 docker ps 查看当前正在运行的容器 docker stop 停止正在运行的一个容器 docker start 使一个停止运行的容器重启运行 docker attach 进入一个在后台运行的容器

1.Docker容器学习之新生入门必备基础知识

1.Docker容器学习之新生入门必备基础知识

文章目录

        • 0x00 Docker 快速入门
          • 1.基础介绍
          • 2.Docker 架构
          • 3.Docker 资源隔离
          • 4.Docker 容器文件系统
        • 0x01 Docker 安装
          • 1. Linux
          • 2. Windows
          • 3. MAC
          • 4. 加速器配置

0x00 Docker 快速入门

1.基础介绍

描述:Docker [ˈdɑ:kə®] 是一个基于Go语言开发实现的遵循Apache 2.0协议开源项目,目标是实现轻量级的操作系统虚拟化解决方案;
,诞生于2013年初最初发起者是dotCloud公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,后续由于docker的发展后来也改名为Docker Inc,它是仅次于OpenStack最受欢迎的云计算开源项目;Docker 从 17.03版本之后分为 CE(Community Edition) 和 EE(Enterprise Edition)

Docker 的目标是"Build,Ship and Run Any App,Anywhere",通过对应用组件的封装\[Packaging]-> 分发\[Distribution] -> 部署\[Deployment] -> 运行\[Runtime]等生命周期进行管理,达到应用级别"一次封装,到处运行";
例如:它可以独立运行一个Web应用,也可以是一套数据库服务,甚至是一个操作系统或编译器;

Apache 2.0 授权 Github 项目开源 : https://github.com/docker/docker


Dcoker与OpenStack的区别?

  • 部署难度:Docker非常简单;OpenStack组件多部署繁琐
  • 启动速度:秒级;分钟级
  • 执行性能:和物理机几乎是一致;VM会占用一些资源
  • 镜像体积:镜像是MB级别的;虚拟机镜像是GB级别的
  • 管理效率:关键简单;组件相互依赖且管理复杂
  • 隔离性:隔离性高;彻底隔离
  • 可管理性:单进程;完整的系统管理
  • 网络连接:比较弱;借助于Neutron可以灵活组件各类网络架构

完整的Docker由以下几部分构成:

  • (1) 守护进程(Daemon):Docker守护进程(dockerd)侦听Docker API请求并管理Docker对象,可以与客户端在同一个节点或者运行在不同节点上,如图像、容器、网络和卷。守护进程还可以与其他守护进程通信来管理Docker服务。
  • (2) REST API: 主要与Docker Daemon进行交互,比如Docker Cli或者直接调用REST API;
  • (3) 客户端(Docker Client): 它是与Docker交互的主要方式通过命令行接口(CLI)客户端(docker命令),客户机将命令通过REST API发送给守护进程dockerd并执行其命令;(注意:一个客户端可以与多个守护进程通信)
  • (4) Register Repository 镜像仓库: Docker注册表存储Docker镜像,可以采用Docker Hub是公共注册仓库,或者采用企业内部自建的Harbor私有仓库;
  • (5) Image 镜像: 映像是一个只读模板,带有创建Docker容器的指令。映像通常基于另一个映像,还需要进行一些额外的定制,你可以通过Docker Hub公共镜像仓库进行拉取对应的系统或者应用镜像;
  • (6) Container 容器: 容器是映像的可运行实例。您可以使用Docker API或CLI创建、启动、停止、移动或删除容器。您可以将一个容器连接到一个或多个网络,将存储附加到它,甚至根据它的当前状态创建一个新映像。
  • (7) Services : Docker引擎支持集群模式服务允许您跨多个Docker守护进程(一个群的每个成员都是一个Docker守护进程)扩展管理容器,服务允许您定义所需的状态,例如在任何给定时间必须可用的服务副本的数量。默认情况下,服务在所有工作节点之间进行负载平衡。对于使用者来说Docker服务看起来是一个单独的应用程序;

WeiyiGeek.引擎图


Linux容器基础之LXC技术介绍:

描述:Docker引擎的基础是Linux容器(Linux Containers,LXC)技术,容器有效的将各个操作系统管理的资源划分到孤立的组,以便更好的在孤立的组之间平衡有冲突的资源使用需求。
容器可以在核心CPU本地运行指令,并不需要任何专门的解释机制;最早的容器技术可以追溯到1982年Unix系列操作系统上的chroot工具;用户操作容器就像操作一个轻量级虚拟机那样简单,也可以将容器比作为一种沙盒(Sandbox);


Docker 优势:

  • 1.更高效的利用系统资源:Docker容器不需要进行硬件虚拟以及运行完整操作系统等额外开销(资源远远小于虚拟机);
  • 2.更快速的启动时间:直接运行于宿主内核无需启动完整的操作系统,可以做到秒级、甚至毫秒级的启动时间;
  • 3.更快速的交付和部署:实现持续集成(Continuous Integration)、持续交付、自动部署(Continuous Delivery/Deployment),大量节约开发,测试,部署的时间;
  • 4.更高效的资源利用:不需要额外的虚拟化管理程序VMM以及Hypervisor的支持;
  • 5.更容易学习、迁移和扩展:一致的运行环境Docker 可以在很多平台上运行无论是物理机、虚拟机、公有云、私有云
  • 6.更简单的更新管理:使用Dockerfile只需要小小的配置修改,可以快速创建和删除容器,Docker hub 提供镜像平台方便共享镜像;
  • 7.基于 Docker 的 CI 持续集成和 CD 持续支付
  • 8.基于 Kubernetes, Docker Swarm 的集群弹性扩容和缩容

什么是虚拟化技术?
虚拟化技术是一个通用的概念,在不同的领域有不同的理解;在计算机领域一般指的是计算机虚拟化(Computer Virtualization)或者说是服务器虚拟化;虚拟化的核心是对资源进行抽象和管理,目标往往是为了在同一个主机上运行多个系统或者应用,从而提高系统资源的利用率,同时带来降低成本,方便管理和容错和容灾等好处;

  • 硬件虚拟化:真正意义上的基于它的技术不多见,少数网卡中的单根多IO虚拟化等技术;
  • 软件虚拟化(Virtualization)
    • 1.应用虚拟化
    • 2.平台虚拟化:细分
      • 2.1 完全虚拟化
      • 2.2 硬件辅助虚拟化:利用硬件CPU辅助支持虚拟化技术Intel-VT和AND-V处理铭感指令来实现完全虚拟化的功能;
      • 2.3 部分虚拟化:只对部分硬件资源进行虚拟化,客户端系统需要进行修改;
      • 2.4 准虚拟化(Paravirtualization):如xen
      • 2.5 操作系统级虚拟化:内核通过创建多个虚拟化的操作系统实例内核和库来隔离不同的进程,dokcer以及其他容器都在这个范畴之内;

传统虚拟机的比较:

WeiyiGeek.传统对比


传统虚拟化方式与Docker虚拟化方式

  • 传统虚拟化方式是在硬件层面实现虚拟化,需要有额外的虚拟机管理应用和虚拟机操作系统层,然后在该系统上运行业务所需程序;
  • Docker虚拟化方式是在宿主系统层面上实现虚拟化,直接复用本地主机的操作系统与内核,容器内没有自己的内核,所以容器内的应用进程实际运行于宿主机内核,因此更加轻量级;

WeiyiGeek.Docker

  • 虚拟机是为提供系统环境而生,容器是为了提供应用环境而生的;

WeiyiGeek.VM对比


物理机-虚拟机-Docker容器容易理解的对比

  • 一栋楼一户人家,独立地基独立花园(别墅)
  • 一栋楼包含多套房,一套房一户人家,共享地基、共享花园、独立卫生间、厨房和宽度(二室一厅)
  • 一套房隔成多个小隔间,每个小隔间住一位租户(胶囊式公寓)

Docker 应用场景

  • 使用docker容器开发、测试、部署服务:自动化测试和持续集成、发布;
  • 在服务型环境中部署与扩展Webapp以及调整数据库或其他应用;
  • 统一、优化和加速本地开发和构建流程;创建隔离的运行环境,测试环境
  • 构建多用户的平台即服务(PaaS)基础设施
  • 提供软件即服务(SaaS)的应用程序
  • 高性能、超大规模的宿主机部署,web应用的自动化打包和发布

2.Docker 架构

描述:Docker对使用者来讲是一个C/S模式(使用客户机-服务器)的架构而Docker的后端是一个非常松耦合的架构,模块各司其职并有机组合支撑Docker的运行。

具体流程:

  • (1) 用户使用Docker客户机与Docker守护进程通信,后者负责构建、运行和分发Docker容器等繁重的工作。
  • (2) Docker Daemon作为Docker架构中的主体部分,首先提供Server的功能使其可以接受Docker Client的请求;
  • (3) Docker客户端和守护进程可以运行在同一个系统上,或者您可以将一个Docker客户端连接到一个远程Docker守护进程。
  • (4) Docker客户机和守护进程之间通过UNIX套接字或网络接口使用REST API进行通信

WeiyiGeek.架构


Docker 内部具体实现:

  • Engine执行Docker内部的一系列工作,每一项工作都是以一个Job的形式的存在。
  • Job的运行过程中,当需要容器镜像时,则从Docker Registry中下载镜像,并通过镜像管理驱动graphdriver将下载镜像以Graph的形式存储;
  • 当需要为Docker创建网络环境时,通过网络管理驱动networkdriver创建并配置Docker容器网络环境;
  • 当需要限制Docker容器运行资源或执行用户指令等操作时,则通过execdriver来完成。
  • libcontainer是一项独立的容器管理包,networkdriver以及execdriver都是通过libcontainer来实现具体对容器进行的操作。

WeiyiGeek.组件架构图


3.Docker 资源隔离

Docker 本质是宿主机上的一个进程,docker通过namespace实现资源隔离以及轻量级虚拟化容器服务,通过cgroup实现了资源限制,通过写时复制技术(Copy-on-write)实现了高效的文件操作;

Docker通过由内核namespace提供实现的隔离,namespace的API包括clone(),sents()以及unshare()还有在/proc下的部分文件

  • 文件系统隔离:每个容器都有自己的 root 文件系统
  • 进程隔离:每个容器都运行在自己的进程环境中
  • 网络隔离:容器间的虚拟网络接口和 IP 地址都是分开的
  • 资源隔离和分组:使用 cgroups 将 CPU 和内存之类的资源独立分配给每个 Docker 容器

即namespace的六项隔离(内核实现 namespace 资源隔离内容 - 系统调用参数)如下标所示:

名称 宏定义 隔离的内容
IPC CLONE_NEWIPC System V IPC, POSIX message queues (since Linux 2.6.19) 信号量消息队列和共享内存
NETWORK CLONE_NEWNET network device interfaces, IPv4 and IPv6 protocol stacks, IP routing tables, firewall rules, the /proc/net and /sys/class/net directory trees, sockets, etc (since Linux 2.6.24) 网络设备,网络栈,端口等
MOUNT CLONE_NEWNS Mount points (since Linux 2.4.19) 挂载点(文件系统)
PID CLONE_NEWPID Process IDs (since Linux 2.6.24) 进程编号
User CLONE_NEWUSER User and group IDs (started in Linux 2.6.23 and completed in Linux 3.8) 用户和用户组(3.8后内核支持)
UTS CLONE_NEWUTS Hostname and NIS domain name (since Linux 2.6.19) 主机名与域名(自Linux 2.6.19)
Cgroup CLONE_NEWCGROUP Cgroup root directory (since Linux 4.6) Cgroup根目录(自Linux 4.6)

cgroup的特点与功能:

  • cgroup的API以一个伪文件系统来实现的,用户态的程序通过文件操作实现cgroup的组织管理;
  • cgroup的组织管理操作单元可以细粒度级别,另外用户可以创建和销毁cgroup,从而实现资源再分配和利用;
  • 所有资源管理的功能都以子吸引的方式实现接口统一,子任务创建之初与其父任务处于同一cgroup的控制组;
  • cgroup四大功能:资源限制(资源总额进行限制),优先级分配(分配CPU时间片数量以及磁盘IO带宽大小),资源统计(CPU时长/内存用量),任务控制(执行挂起/恢复等操作);

4.Docker 容器文件系统

描述:从下面的图片可以看见出以下几点:

  • Docker 镜像代表了容器的文件系统里的内容,是容器的基础,镜像一般是通过 Dockerfile 生成的;
  • Docker 的镜像是分层的,所有的镜像(除了基础镜像)都是在之前镜像的基础上加上自己这层的内容生成的;
  • Docker 中每一层镜像的元数据都是存在 json 文件中的,除了静态的文件系统之外,还会包含动态的数据;
  • Docker 镜像生产容器后会在此基础之上加入挂载点到安装Docker宿主机文件系统之中,并提供一个读写层(Read-Write Layer),所以容器进程的所有操作都在读写层进行;

WeiyiGeek.容器文件系统

总结:

  • Docker通过为Linux容器技术提供更简洁的使用和管理方案、更高效的版本控制,Docker 让容器技术一下子变得灵活易用,随着云计算(Cloud Computing)的发展,它在Virtualization中的地位越来越重要.
  • 四大核心概念:镜像 [image] / 容器 [Container] / 仓库 [Repository] / Dockerfile

参考书籍:Docker技术入门与实战


0x01 Docker 安装

1. Linux

系统环境:docker最低支持centos7且在64位平台上,内核版本在3.10以上
官方安装文档:https://docs.docker.com/install/linux/docker-ce/centos/#
镜像开源安装站点:https://mirrors.tuna.tsinghua.edu.cn/help/docker-ce/

  • Docker Engine改为Docker CE(社区版): 它包含了CLI客户端、后台进程/服务以及API。用户像以前以同样的方式获取。
  • Docker Data Center改为Docker EE(企业版): 在Docker三个定价层增加了额外的支付产品和支持。

官方一键安装脚本
补充时间:[2020年4月22日 11:00:59]

一键安装Docker-ce以及Docker-compose:

##[docker]
#国外
curl -fsSL https://get.docker.com | bash -s docker
#国内
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
curl -fsSL https://get.docker.com -o get-docker.sh && chmod +x get-docker.sh && ./get-docker.sh
#测试安装结果
docker-info

##[docker-compose]
sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose
#测试安装结果
docker-compose version

Yum安装Docker / Docker-compose

#删除历史docker版本
yum remove -y  docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

#下载docker repo包
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
#或者手动设置官方源
sudo tee /etc/yum.repos.d/docker.repo <<-''EOF''
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/centos/$releasever/
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg
EOF

#下载安装docker-ce社区版本
#Docker Community Edition (CE)对于希望开始使用Docker并尝试基于容器的应用程序的开发人员和小型团队来说非常理想。
#Docker CE有三种更新通道:稳定通道、测试通道和夜间通道:
sudo yum install -y docker-ce docker-compose  #手动官方源执行 docker-ce-cli containerd.io

# 更新docker-ce
yum -y upgrade docker-ce

#按照版本号从高到低排序
[root@zabbix log]$ yum list docker-ce --showduplicates | sort -r
docker-ce.x86_64            3:18.09.5-3.el7                    docker-ce-stable
docker-ce.x86_64            3:18.09.5-3.el7                    @docker-ce-stable  #当前使用版本

# Docker 是一个 C/S 架构的服务,安装好 docker 之后需要启动 docker 软件后才能使用 docker 命令;
systemctl start/status docker  # 启动docker-ce

# 查看docker启动状态
docker version
Client:
 Version:           18.09.5
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        e8ff056
 Built:             Thu Apr 11 04:43:34 2019
 OS/Arch:           linux/amd64

# 移出docker-ce
$ sudo yum remove docker-ce
#主机上的映像、容器、卷或自定义配置文件不会自动删除。删除所有图像、容器和卷:
$ sudo rm -rf /var/lib/docker

#测试 docker 下载 hello-world 或者 alpine
docker pull hello-world
docker images
docker run hello-world

WeiyiGeek.DockerCentosOK

docker-compose的安装补充时间:[2020年1月22日 10:54:55]

  • 方式1:安装 docker-compose: [需要安装大于或者等于1.6版本的 Docker ]
    https://docs.docker.com/compose/ -> 选择InstallCompose

WeiyiGeek.

#安装docker-compose
#切换为root权限下载并安装docker-compose ( current stable release (v1.25.0) )
$ curl -L "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" > /usr/local/bin/docker-compose  
$ chmod +x /usr/local/bin/docker-compose    #添加执行权限
  • 方式2:安装Docker-Compose
#在centos7中使用python-pip安装docker-compose
$yum install -y python3
$pip3 install pip --upgrade
[root@vm-1575613390 ~]# pip --version
pip 19.3.1 from /usr/local/lib/python3.6/site-packages/pip (python 3.6)

$pip3 install docker-compose

补充说明:[2020年4月22日 10:58:21]

  • 目前最新版本的 docker 默认优先采用 overlay2 的存储驱动,对于已支持该驱动的 Linux 发行版,不需要任何进行任何额外的配置

其它操作系统参考:
Ubuntu的安装:https://docs.docker.com/install/linux/docker-ce/ubuntu/


2. Windows

Windows 下安装 Docker:https://www.docker.com/products/docker-desktop
使用CPU虚拟化检测工具(LeoMoon CPU-V)检测环境:
WeiyiGeek.cpu-v


window 7
Step 1.下载 docker Tool box 进行全安装FULL Installation

Step 2.安装成功后会在桌面出现virtual VM,docker,Kitematic(Alpha)等等

  • Kitematic(Alpha):是一个Docker GUi工具.用户可能运行命令(docker run hello-world)在Docker客户端启动一个容器,在Kitematic中能观察结果. 用GitHub账号登陆.就可以看到自己创建的镜像,或是在GitHub上down下来的镜像.
    Oracle VM VirtualBox:虚拟机管理器,可以创建虚拟机;也可对当前正在运行的虚拟机进行管理.

Step 3.点击 Docker Quickstart Terminal进行下载boot2docker.iso 运气好不报错的话可以说明安装完成

Step 4.而我win7启动 Docker Quickstart Terminal报错,解决方法也是很简单

WeiyiGeek.报错

下载后放在C:\Users\WeiyiGeek.docker\machine\cache\boot2docker.iso即可

WeiyiGeek.下载boot2docker

解决上述问题后,验证安装:

docker pull hello-world
docker images
docker run hello-world

WeiyiGeek.安装成功


Step 5.安装后的docker是可以通过ssh连接的,boot2docker用户和密码 ```bash docker tcuser ssh root command:sudo -i (docker用户下执行) ``` ![WeiyiGeek.dockerssh](https://img-blog.csdnimg.cn/20201009171605351.png)

window 10
描述: 现在在Windows 10 Pro, Enterprise, and Education等系统版本中可以进行下载安装Docker Desktop for Windows下载地址-当前版本2.3.0.3,它可以进行使用的界面来操作查看docker中的容器,以此来简化了学习成本;
Step 1.设置docker进行安装,加入到PATH之中
Step 2.安装成功,关闭窗口
Step 3.安装后利用powershell进行查看docker版本

> docker version
> docker run hello-world

Step 4.查看docker pull下来得镜像,并且运行

> docker images  #查看镜像
> docker run -it hello-world

WeiyiGeek.desktop for windows


3. MAC

WeiyiGeek.mac


4. 加速器配置

方式1:使用DaoCloud加速器
简介:DaoCloud 加速器 是广受欢迎的 Docker 工具,解决了国内用户访问 Docker Hub 缓慢的问题。DaoCloud 加速器结合国内的 CDN 服务与协议层优化,成倍的提升了下载速度。
DaoCloud官网:
https://www.daocloud.io/mirror#accelerator-doc


方式2:使用阿里云容器镜像服务加速器
推荐安装1.10.0以上版本的Docker客户端,您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器:

#方法1.常规加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-''EOF''
{
   
  "registry-mirrors": ["https://xlx9erfu.mirror.aliyuncs.com"]
}
EOF

#方法2:对于 1.12 以前的版本, dockerd 换成 docker daemon 
#注:编辑docker.service文件
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --registry-mirrors=https://xlx9erfu.mirror.aliyuncs.com

#方法3:Docker-CE17.12版本以及之后(CentOS7.0)
vi /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --registry-mirror=https://xlx9erfu.mirror.aliyuncs.com

#通用启动
sudo systemctl daemon-reload   #重载守护
sudo systemctl restart docker

#检查加速器是否生效
sudo ps -ef | grep dockerd
root 5346 1 0 19:03 ? 00:00:00 /usr/bin/dockerd --registry-mirror=https://jxus37ad.mirror.aliyuncs.com

WeiyiGeek.

补充一键配置:

# Docker中国 mirror
# export REGISTRY_MIRROR="https://registry.docker-cn.com"
# 腾讯云 docker hub mirror
# export REGISTRY_MIRROR="https://mirror.ccs.tencentyun.com"
# 华为云镜像
# export REGISTRY_MIRROR="https://05f073ad3c0010ea0f4bc00b7105ec20.mirror.swr.myhuaweicloud.com"
# DaoCloud 镜像
# export REGISTRY_MIRROR="http://f1361db2.m.daocloud.io"
# 阿里云 docker hub mirror
# export REGISTRY_MIRROR=https://registry.cn-hangzhou.aliyuncs.com
export REGISTRY_MIRROR=https://xlx9erfu.mirror.aliyuncs.com
curl -sSL https://kuboard.cn/install-script/set_mirror.sh | sh -s ${REGISTRY_MIRROR}

WeiyiGeek Blog - 为了能到远方,脚下的每一步都不能少。

博主 Blog 镜像站点(友链交换请邮我哟):

  • https://weiyigeek.top # 国内访问较慢
  • https://blog.weiyigeek.top # 更新频繁
  • https://weiyigeek.gitee.io # 国内访问快可能会有更新不及时得情况

更多原创学习笔记文章请关注 WeiyiGeek 公众账号

【点击我关注】

WeiyiGeek-公众账号

167 docker docker构建nginx容器系列问题 docker registry docker run docker toolbo

167 docker docker构建nginx容器系列问题 docker registry docker run docker toolbo

docker构建nginx容器系列问题


background : 最近为小伙伴们筹划docker系列的技术分享,研究了一会docker相关技术, 在此记录一下构建nginx容器时候的坑

1.nginx服务器根目录问题

docker 官方镜像提供的nginx基于debian/jessie平台,其文件结构和ubuntu中的nginx中并不相同

eg:

run一个niginx容器

<span>//80端口被占用,so...</span>
$ sudo docker run <span>-it</span><span>-p</span><span>800</span>:<span>800</span> nginx
$ sudo docker ps 

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                   NAMES
<span>1801</span>a32aab54        nginx               <span>"nginx -g ''daemon off"</span><span>2</span> minutes ago       Up <span>2</span> minutes        <span>80</span>/tcp, <span>443</span>/tcp, <span>0.0</span><span>.0</span><span>.0</span>:<span>800</span><span>-&gt;</span><span>800</span>/tcp   berserk_kare
登录后复制

进入容器内部

<span>$ </span>sudo docker exec -it <span>1801</span>a32aab54 /bin/bash
root<span>@1801a32aab54</span><span>:/</span><span># </span>
登录后复制

查看nginx目录

<span># cd /etc/nginx/</span>
conf<span>.d</span>/         koi-utf         mime<span>.types</span>      nginx<span>.conf</span>      uwsgi_params    
fastcgi_params  koi-win         modules/        scgi_params     win-utf  
登录后复制

可以看到不仅没有熟悉的 /sites-available,也没有 /sites-enabled

继续查看nginx配置

<span># cat /conf.d/default.conf</span><span>server</span> {
    listen       <span>80</span>;
    server_name  localhost;

    <span>#charset koi8-r;</span><span>#access_log  /var/log/nginx/log/host.access.log  main;</span>    location / {
        root   /usr/share/nginx/html;
        <span>index</span><span>index</span>.html <span>index</span>.htm;
    }

    <span>#error_page  404              /404.html;</span><span># redirect server error pages to the static page /50x.html</span><span>#</span>
    error_page   <span>500</span><span>502</span><span>503</span><span>504</span>  /<span>50</span>x.html;
    location = /<span>50</span>x.html {
        root   /usr/share/nginx/html;
    }
    <span>#...省略php-fpm配置,好长..</span>
}
登录后复制

根目录配置: root /usr/share/nginx/html;

测试

<span># cd /usr/share/nginx/html</span><span># touch index.html</span><span># echo "test nginx in docker" &gt;index.html</span>
登录后复制

php-fpm配置相关

'').addClass(''pre-numbering'').hide(); $(this).addClass(''has-numbering'').parent().append($numbering); for (i = 1; i '').text(i)); }; $numbering.fadeIn(1700); }); });

以上就介绍了167 docker docker构建nginx容器系列问题,包括了docker,nginx方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

2.Docker容器学习之新生入门必备基础知识

2.Docker容器学习之新生入门必备基础知识

文章目录

        • 0x02 Docker 核心概念
          • 1.镜像 [image]
          • 2.容器 [Container]
          • 3.仓库 [Repository]
        • 0x03 Docker 数据管理
          • 1.数据卷
          • 2.数据卷容器
        • 0x04 Docker 网络管理

0x02 Docker 核心概念

描述:Docker的三大核心概念镜像/容器和仓库, 通过三大对象核心概念所构建的高效工作流程;

1.镜像 [image]

描述:images 类似于虚拟机镜像,借鉴了Git利用分成分层优点,通过文件系统分层的概念实现了分层复用,极大的节约了磁盘空间;简单的您可以将它理解成为一个面向Docker引擎的只读模板包含文件系统;

  • 镜像是创建Docker容器的基础,然后通过版本管理和增量的文件系统;
  • 用户基于镜像来运行自己的容器,镜像是基于 Union 文件系统的层式结构;

Docker运行容器前本地必须存在对应的镜像,如果不指定镜像名将会默认自动采用Docker Hub公共注册服务器仓库中该名称的镜像;
Docker 镜像使用帮助:https://lug.ustc.edu.cn/wiki/mirrors/help/docker

基础知识:

  • 1.镜像名称格式:Image hub address/Namespace/Repository:taghub.weiyigeek.top/Test//alpine-apps:1.0
  • 2.典型Linux启动需要运行两个FS即:Kernel > Bootfs > Rootfs
  • 3.镜像的分层结构: 新镜像是从Base镜像一层一层叠加的,每安装一个软件就在现有镜像基础上增加一层;

镜像操作关键点:

docker search [镜像名称] #搜索关于Archlinux镜像
#支持的参数:
--automated=false #仅仅显示自动创建的镜像(官方)
--no-trunc=false  #输出信息不截断显示
-s,--stars=0    #指定仅显示评价为指定星级以上的镜像

#仓库名(Repository) 或者 标签名[不指定着默认latest,即最新]
docker pull name/[repository[:tag]] #获取Hub镜像如果不指定TAG将默认选择仓库中最新颁布的镜像
docker push DockerHubUser用户/test:latest  #上传到docker仓库

docker images   #列出本机已有镜像

docker tag 原仓库[:标签] 新仓库名[:标签]  #为本地镜像添加一个新标签 [注意仓库名称必须小写]
docker tag <image id> username/name:devel #修改镜像的标签

docker inspect [image id]  #获取镜像的详细信息
docker inspect -f {
   {
   ".Architecture"}} 550(images Id 前面3位)  #-f 获取单个属性 返回JSON
  
docker rmi [<image id>|<repository> ]   #删除镜像 镜像id|仓库名称
docker rmi -f <images id>   #不建议强行删除正在容器中运行的镜像文件

docker save -o 保存文件名.tar  [repository[:tag]]  #将镜像文件打包存出到磁盘
docker save [repository[:tag]] > 保存文件名 #将镜像文件打包存出到磁盘

docker load --input 保存文件名.tar   #将打包的镜像文件进行载人
docker load < 保存文件名.tar

运行案例:

$ sudo docker pull ubuntu:16.04                #下载14.04 tag的镜像
Using default tag: latest
latest: Pulling from library/ubuntu
#从下面可以看出镜像文件一般是由若干组成,行首f476d66f5408代表了各层的ID,下载过程中会获取并输出镜像各层信息
#层(Layer)其实是AUFS(Advanced Union File System联合文件系统)重要概率是实现增量保存于更新的基础
f476d66f5408: Pulling fs layer
8882c27f669e: Pulling fs layer
d9af21273955: Pulling fs layer
f5029279ec12: Waiting

$ sudo docker pull registry.hub.docker.com:5000/ubuntu   #从指定长仓库进行下载

$ sudo docker run -t -i Ubuntu /bin/bash        #利用dockerubuntu镜像创建一个容器 仓库后面是接的命令
root@634e7ed26d76:/# w
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
 03:34:47 up  1:59,  0 users,  load average: 0.00, 0.05, 0.06
root@634e7ed26d76:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.2 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.2 LTS"


$ sudo docker images   #列出镜像
#其中Image id的信息十分重要,它唯一标示了镜像,Tag信息来区分发行版本(如14.04,16.04) 
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              d131e0fa2585        9 days ago          102MB
centos              latest              9f38484d220f        7 weeks ago         202MB
#REPOSITORY (来自哪个仓库) TAG (镜像的标签信息) IMAGE ID (镜像的ID号,唯一) CREATED [Created:建立时间] VIRTUAL SIZE (镜像大小)


$ sudo docker tag ubuntu:latest ubuntu18.04:latest #修改镜像名称使用该方式进行添加新标签原来的不会被删除
$ sudo docker tag d131e0fa2585 ubuntutls:latest
$ sudo docker images
#更改后镜像的ID是完全一致的,其实都指向了同一个镜像文件相当于别名而已;
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntutls           latest              d131e0fa2585        9 days ago          102MB
ubuntu18.04         latest              d131e0fa2585        9 days ago          102MB 

$ sudo docker inspect d131e0fa2585 #获取该镜像的详细信息
$ sudo docker inspect -f {
   {
   ".Architecture"}} d131  #获取系统架构 通常使用镜像ID的前三位
amd64

WeiyiGeek.inspect

当该镜像在容器运行存在的时候,镜像文件默认是无法被删除的;必须停止/删除容器ID才能删除镜像文件;

#当同一个镜像有多个标签的时候rmi命令只是删错了该进行的标签而且,并不影响镜像文件
#但当只剩下一个标签的时候就要小心了,如果在停止的状态下再次使用rmi命令则会删除该镜像
$ sudo docker rmi ubuntu18.04
Untagged: ubuntu18.04:latest
$ sudo docker rmi ubuntu ubuntutls
Untagged: ubuntu:latest 
Untagged:  #删除了这个镜像文件的所有AUFS层
ubuntu@sha256:d26d529daa4d8567167181d9d569f2a85da3c5ecaf539cace2c6223355d69981

$ sudo docker rmi -f ubuntutls  #强制删除
Untagged: ubuntutls:latest
Deleted: sha256:d131e0fa2585a7efbfb187f70d648aa50e251d9d3b7031edf4730ca6154e221e

创建镜像有三种办法:

  • 1.从已有镜像的容器创建
  • 2.基于本地模板导入:使用操作系统模板导入一个镜像文件;这里推荐使用OpenVZ提供的模板来常见
  • 3.基于Dockerfile导入

######### 从已有镜像创建 ############
$sudo docker commit [option-选项] ContainerId [Repository[:Tag]]
$sudo docker commit -m "xx" -a "oo" ContainerID(被修改过的ID) [Repository[:Tag]] 
# -a,--author="作者"
# -m,--message="更改信息"
# -p,--pause=ture 提交时暂停容器Container运行

$sudo docker run -it centos:latest /bin/bash
[root@32a481e170c6 ~]$ touch {
   1..10}.txt  #上面这个容器ID非常重要在进行修改之后

$sudo docker container ls -a   #查看容器记录
#创建一个新的镜像
$sudo docker commit -m "Zabbix base in Centos7" -a "Weiyigeek" 32a481e170c6 centoszabbix:latest
sha256:680ddb57c4b80c625ef68e113f553ee932a06f25d4685d25a0b6464cf5d60982  #成功会给出一个镜像ID

######### 从本地模板导入 ############
$sudo cat ubuntu-14.04.tar.gz | docker import - ubuntu:14.04  #本地导入镜像命令

存出和载人镜像并上传镜像到DockerHub中实例:

$docker save -o zabbixcentos.tar centoszabbix:latest
ls -alh zabbixcentos.tar
-rw------- 1 root root 200M 5月   6 13:16 zabbixcentos.tar
$docker load --input zabbixcentos.tar
Loaded image: centoszabbix:latest

$docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centoszabbix (上面从已有镜像文件中创建)       latest              622b7661c06b        13 minutes ago      202MB

#用户需要在DockerHub网站注册后才能进行上传镜像
$docker login  #在及其上进行登录
# Login with your Docker ID to push and pull images from Docker Hub. If you don have a Docker ID, head over to https://hub.docker.com to create one.
# Username: weiyigeek
# Password: 输入hub密码
# WARNING! 账号密码base64编码存放于 /root/.docker/config.json 文件中
# echo "d2VpeW********VrO***ldlaXllMjAxOQ==" | base64 -d
# weiyigeek:Docker
# https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded  #表示登录成功

$docker push weiyigeek/czabbix:latest
The push refers to repository [docker.io/weiyigeek/czabbix]
484404f26982: Pushed
d69483a6face: Mounted from library/centos
latest: digest: sha256:c1d891c2d56a0677ff28639189fa7252790d3b8ef417816570fb3a7654bc4e05 size: 736  #表示上传成功返回的票据

WeiyiGeek.hub镜像上传成功


镜像的F&Q相关问题

Q:Docker 镜像是怎么实现增量的修改和维护的?
答:每个镜像都由很多层次构成,Docker 使用 Union FS 将这些不同的层结合到一个镜像中去。
通常 Union FS 有两个用途:(Docker 在 AUFS 上构建的容器也是利用了类似的原理)

  • 一方面可以实现不借助 LVM、RAID 将多个 disk 挂到同一个目录下
  • 就是将一个只读的分支和一个可写的分支联合在一起,Live CD 正是基于此方法可以允许在镜像不变的基础上允许用户在其上进行一些写操作

Q:什么是镜像写时复制?
答: 比如典型的Linux启动首先会将rootfs置为readonly再进行一系列检查后将其切换为readwrite供用户使用,当在Docker中起初也是将rootfs置为readonly,然后利用union mount将一个readwrite文件系统挂载只读的rootfs之上,并且运行再次将下层的文件系统设置为readonly并且向上叠加,我们把这样一组readonly和一个writeable的结构构成一个容器的运行目录,每一个被称为一个Layer;

Writable : Container  (可以向上叠加同时它变成一层Image)
add Apache : Image (Reference parent-引用父)
add Emacs : Image  (Reference parent-引用父)
Debian : Base Image
> Bootfs
lxc,aufs,brtfs : Kernel

Q:Docker 中 save 和 export 命令的区别?
答: 我们先简单的说一下其区别,在随后的的例子中使您更快的理解;

  • 1.save 与 load 命令对应即导出与导入镜像,而export与import命令对应即导出导入容器;
  • 2.save 保存后 load 加载的镜像没有丢失历史和层(Layer),而容器export导出然后import导入时所有的提交历史将会丢失,这意味着您无法回滚到之前的层;
  • 3.补充:通过import导入的方式镜像只有一层,而通过commit的方式生成的镜像实际是在原有的Base Image(即复写层)上又生成了一层;
# 1.在一个正在运行的容器上创建一个目录然后commit
docker exec -it test1 mkdir /tmp/demo
docker commit -a "WeiyiGeek" -m "create /tmp/demo directory" test1 test:1.2 #加上tag镜像名称:版本防止玄虚镜像
sha256:30a048249000dd36561bffaa9fecc7690a45ef12096849c77afd4543b0d2d9b0

# 2.采用save命令进行导出提交的镜像
docker save -o save.tar 30a048

# 3.采用export进行导出正则运行的容器
docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
25d2d645bfc9        test1               "top -b -d 2"       2 weeks ago         Up 3 days                               test1
docker export test1 > export.tar # 或者 docker export 25d > export.tar


# 4.在另外一台机器上进行分别导入 save.tar 与 export.tar
docker load -i save.tar #此时默认导入会导致虚悬镜像
Loaded image ID: sha256:30a048249000dd36561bffaa9fecc7690a45ef12096849c77afd4543b0d2d9b0
cat export.tar | docker import - test1:1.0
sha256:cdd65e7054be9e1928fe8133380817e81ff12b8493b40e2f9106efedac5ee572

# 5.查看导入情况
docker images
REPOSITORY                            TAG                 IMAGE ID            CREATED             SIZE
<none>                                <none>              30a048249000        2 minutes ago       7.37MB
test1                                 1.0                 cdd65e7054be        3 minutes ago       7.35MB

# 6.查看异同
[root@master-01 ~]$ docker history 30a # save 方式 存在历史层信息
# IMAGE CREATED CREATED BY SIZE COMMENT
# 30a048249000 22 minutes ago -d 2 193B create /tmp/demo directory
# <missing> 2 weeks ago /bin/sh -c #(nop) CMD ["-d" "2"] 0B
# <missing> 2 weeks ago /bin/sh -c #(nop) ENTRYPOINT ["top" "-b"] 0B
# <missing> 2 weeks ago /bin/sh -c echo "http://mirrors.huaweicloud".… 1.8MB
# <missing> 2 weeks ago /bin/sh -c #(nop) MAINTAINER WeiyiGeek mast… 0B
# <missing> 2 weeks ago /bin/sh -c #(nop) LABEL Author=WeiyiGeek De… 0B
# <missing> 5 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
# <missing> 5 weeks ago /bin/sh -c #(nop) ADD file:c92c248239f8c7b9b… 5.57MB
[root@master-01 ~]$ docker history cdd # export 方式无历史层信息且只有一层
# IMAGE CREATED CREATED BY SIZE COMMENT
# cdd65e7054be 23 minutes ago 7.35MB Imported from -

2.容器 [Container]

描述:Docker容器Container类似于一个轻量级的沙箱,也可以看做一个简易版的Linux系统环境;因为容器是运行应用程序的,所以必须得先有一个操作系统为基础

Docker利用容器来运行和隔离应用;

  • 容器是从镜像创建的应用独立运行的实例;
  • 可以进行启动/开始/停止/删除容器,而这些容器都是相互隔离,互不可见的;
  • 镜像自身只读的,容器从镜像启动的时候会在镜像的最上层创建一个可写层,镜像本身将保持不变;
  • 创建容器、启动容器、终止容器、进入容器、删除容器、导入导出容器实现容器迁移;

当创建并运行容器时候Docker在后台运行的标准操作包括:

  • 检查本地是否存在指定镜像,不存在就从公有仓库下载
  • 利用镜像创建并启动一个容器
  • 分配一个文件系统,并在只读的镜像层外面挂载一个可读写层
  • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
  • 从地址池配置一个IP地址给容器
  • 执行用户指定的应用程序
  • 执行完毕后容器被终止

启动容器有两种方式:

  • 一种是基于镜像新建一个容器并启动
  • 另外一个是将在终止状态(stopped)的容器重新启动。

关键命令:

docker create -it repository[:tag] #创建容器但处于停止状态

docker start -a -i <container id>   #启动创建的容器
# -a 参数 连接容器并打印输出或错误 -
# -i 参数 启动容器并进入交互模式

docker run -t -i repository[:tag]  /bin/bash #创建并启动容器 等同于上面两条命令
# -t:让Docker分配一个伪终端(pseudo-tty)并绑定在容器的标准输入上.
# -i:则让容器的标准输入保持打开.
# CTRL+Z 和 Exit 则退出容器Container
docker run -d repository[:tag] /bin/sh -C "echo hello word" #守护态运行
# -d 参数即可后台运行,用户无法看到容器中的信息
# -c 执行的Command
# --rm 添加这个标记,容器会在停止后立即删除自身 (注意:与-d不能同时使用)
# --name 使用--name web 标记可以为容器重新命名

docker logs <Container-id>      #获取容器的输出信息

docker attach [names]  #采用ps -a NAMES 进入容器

docker exec -it <Container-id>  /bin/bash  #docker exec 至1.3版本起可以在容器中运行命令

docker ps -aq   #显示本机上的所有容器ID运行的容器ID信息

docker restart <container id>  #重启容器

docker stop <container id>  #停止容器
docker kill <cantainer id>  #强行终止容器 可以直接发送SIGKILL信号来终止容器

docker rm <container id>    #删除容器删除依赖该镜像的容器ID,前3位即可
# -f,--force=false 强制终止并删除一个运行中的容器[默认会发生SIGKILL信号]
# -l,--link=false 删除容器连接但保留容器
# -v,--volumes=false 删除容器挂载的数据卷

docker export <container id> >导出文件.tar  #导出容器

docker import - repository[:tag] #导入容器

WeiyiGeek.run与start的区别

实例命令:

#创建容器
$sudo docker create -it weiyigeek/czabbix  
2b72a3410be576aeb9023ef2c41488e7b2630cf2282b8a0b1dddce771f22231f

#启动容器ID执行交换登录,start可以进入到任何在容器中运行
$sudo docker start -i 2b7  
# [root@2b72a3410be5 /]# whoami
# root
# [root@2b72a3410be5 /]# exit
#对于创建后的容器采用exit命令退出后该容器自动处于终止状态;
#提示:正常退出不关闭容器请按Ctrl+P+Q进行退出容器

$sudo docker ps -a  #显示本机上存在的所有容器
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 634e7ed26d76 d131e0fa2585 "/bin/bash" About an hour ago Exited (130) About an hour ago recursing_goodall
# b72a3410be5 weiyigeek/czabbix "/bin/bash" 41 seconds ago Up 21 seconds priceless_chaplygin

$docker run -t -i centos /bin/bash  #创建容器并且运行
# [root@0b9aef4876d3 /]# hostname
# 0b9aef4876d3

$ddocker run -d centoszabbix /bin/sh -c "echo Hello World,Docker Container"
4e62768b1d9196fc79fd740c103df79c8e3bb09d9c6810aa43976abeda036a26

$ddocker logs 4e62  #获取容器输出的信息
Hello World,Docker Container

$docker attach priceless_chaplygin  #通过上面的ps -a 中names进入想对应的容器
#当多个窗口同时 attach 到同一个容器的时候 所有窗口都会同步显示 。当某个窗口因命令阻塞时,其他窗口也无法执行操作了
# [root@b72a3410be5 /]$ hostname
# b72a3410be5

$docker exec -ti b72 /bin/echo "whoami"   #可以通过exec直接执行命令和进入shell
# whoami


#停止容器
#当需要删除一个在容器中运行的镜像的时候,会导致不能删除镜像[Image]这时候必须先停止再删除容器[container]:
$sudo docker stop 634e7ed26d76  

#镜像的容器ID,前3位即可,然后在删除镜像
$sudo docker rm 634      #此时再用镜像ID来删除进行,成功则会打印出删除各层信息
$sudo docker rmi -f d131e0fa2585     #镜像的容器ID,前3位即可,然后在删除镜像

#导出镜像
$sudo docker export 092 > czabbix.tar

#导入镜像
$cat czabbix.tar | docker import - test:latest
sha256:bbb9dbcaa5fff9c5b1b99c978df4dcaeeca3d2200d82fc466f5064931bd3bba2
[root@zabbix ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test                latest              bbb9dbcaa5ff        14 seconds ago      202MB

补充:使用nsenter工具进入Docker容器

#获取容器的PID
$PID=$(docker inspect --format "{ { .State.Pid}}" <container id>)
#通过得到的这个PID,就可以连接到这个容器:
$nsenter --target $PID --mount --uts --ipc --net --pid

#手动获取docker container 运行的PID
[root@zabbix ~]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED
092d1b82c6a0        weiyigeek/czabbix   "/bin/bash"         17 minutes ago      ck
[root@zabbix ~]$ docker inspect --format "{
   { .State.Pid}}" 092
9030
[root@zabbix ~]$ nsenter --target 9030 --mount --uts --ipc --net --pid
[root@092d1b82c6a0 /]$ cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)
#成功进入该容器,9030就是容器092d1b82c6a0的进程PID

Docker load 与 Docker import 的比较
描述:导入容器和导入镜像是差不多的但是实际上又是有所区别的

  • load:导入镜像存储文件到本地镜像库 而 import:导入一个容器快照到本地镜像库
  • 容器快照:文件将丢失所有的历史记录和元数据信息(即保留容器当时的快照状态),导入的时候还需要重新制定标签等元数据信息;
  • 镜像存储:文件将保存完整的记录,并且体积也要大;

总结:

  • 容器的名称是唯一性的如果不指定名称,将会自动生成一个容器名称;
  • 容器是直接提供应用服务的组件,也是Docker实现快速启停和高效服务器性能的基础
  • 在生产环境中因为容器自身的轻量性,建议在容器前段引入HA(高可靠性)机制,当出现错误的时候能快速切换到其他容器之中,还能自动重启故障容器;

3.仓库 [Repository]

描述:Docker 仓库(Repository)类似于代码仓库,是Docker集中存放镜像文件的场所;该概念的引入为Docker镜像文件的分发和管理提供了便捷的途径。
仓库注册地址:https://hub.docker.com/
安装帮助文档:http://www.widuu.com/docker/installation/ubuntu.html

注册服务器是存放仓库的地方,其上往往存放着多个仓库,每个仓库集中存放某一类镜像,往往包括多个镜像文件,通过不同的标签[TAG]来进行区分;

  • 目前最大的公开仓库是 Docker Hub 存放了数量庞大的镜像提供用户下载
  • 国内的公开仓库包括Docker Pool等等可以提供稳定的国内访问。

例如:对于仓库地址dl.dockerpool.com/ubuntu来说,dl.dockerpool.com是注册服务器,ubuntu是仓库名;
WeiyiGeek.仓库注册服务器

Docker 仓库分类:

  • 公开仓库(Public)
  • 私有仓库(Private)

官方与用户提供的镜像比较:

  • 官方:centos 由Docker维护的基础或根镜像;
  • 个人:user/centos 表示由user用户维护的centos基础镜像;

关键点:

docker login   #连接并初始化hub仓库 需要输入用户名和密码认证,然后存放于/root/.docker/config.json 文件中
docker pull [repository]  #下载指定仓库到本地
docker push [imges]

#实例
$docker pull dl.dockerpool.com:5000/ubuntu:12.04 #连接其他的注册服务器
$docker images
$docker tag dl.dockerpool.com:5000/ubuntu:12.04 ubuntu:12.04   #更新标签与官方标签保持一致
$docker push dl.dockerpool.com:5000/ubuntu:12.04  #上传到私有镜像

(1)创建和使用私有仓库:
最快捷还是搭建本地的仓库服务器(注意:配置不当会导致漏洞)

$ docker run -d -p 5000:5000 registry
#默认情况下仓库创建在容器的/tmp/register目录下,-v 通过镜像文件存放在宿主机本地的指定路径/opt/data/registry上;
$ docker run -d -p 5000:5000 -v /opt/data/registry:/tmp/registry registry 
# -d:容器启动后会进入后台,用户无法看到容器中的信息.
# -p:指定仓库镜像的端口.
# -v:将镜像的存放位置放在本地指定的路径上.

此时会在本地启动一个私有仓库服务,监听端口为5000; 更新标签本地仓库地址并上传到私有仓库之中:

$docker tag ubuntu:14.04 10.0.2.2:5000/test  #更改镜像的标签
$docker pull 10.0.2.2:5000/test              #下载镜像

#可以以这个来测试是不是存在docker 5000未授权访问漏洞
$ curl http://10.0.2.2:5000/v1/search  #上传成功后可以查看到返回的json字符串

(2)自动创建[Automated Builds]
该功能是对于需要经常升级镜像内程序来说十分的方便,用户创建镜像发生更改的时候进行手动更新镜像,并能通过自动创建功能跟踪目标网络,一旦项目发现新的提交则自动执行创建;配置自动创建步骤如下:

  • 创建登录Docker Hub 绑定Github;
  • 在Docker Hub中配置一个自动创建
  • 选取一个目标网站中的项目(需要Dockerfile和分支)
  • 指定Dockerfile的位置并提交创建,可以在"自动创建页面"跟踪每次创建的状态;

总结:

  • 仓库管理镜像的设计理论与Git差不多,工作流程为文件分发和合作带来的众多优势。

0x03 Docker 数据管理

Data Management,在使用Docker时候必然会在容器内产生数据,或者需要将容器内的数据进行备份,甚至多个容器之间进行数据共享,这时数据管理变得尤为重要;

WeiyiGeek.数据管理


容器中管理数据的主要有两种方式:

  • 数据卷:Data Volumns
  • 数据卷容器:Data Volume Dontainers

数据管理共享的方式:

  • 使用数据卷容器在容器和主机
  • 容器和容器之间共享数据
1.数据卷

描述:是一个可供容器使用的数据目录,并且让文件系统提供很多有用的特性,数据卷的使用类似于Linux对目录或者文件进行mount操作;

特性:

  • 数据库可以在容器之间共享和重用
  • 数据卷修改后会立马生效
  • 对数据卷的更新不会影响镜像
  • 卷会一直存在,即使容器被删除

Q:如何在容器内创建一个数据卷?

#### 创建一个web容器并创建一个数据卷挂载到容器的/webapp目录下(默认将宿主机/根映射到容器中webapp目录中)
$ sudo docker run -d -P 5000 --name web(新建容器) -v /webapp(容器目录) training/webapp(镜像) python app.py
# --name 指定容器的名称
# -v:将镜像的存放位置放在本地指定的路径上.
# -P:是允许外部访问容器需要暴露的port
# -d:是容器的后台运行守护

#cp 把容器文件copy到宿主机,或者把宿主机的文件copy到容器
$docker cp 容器id或者name:/home/wwwroot/1.php /home/Lcy/ #把容器的1.php拷贝到宿主机家目录
$docker cp config.php 容器id或者name:/home/wwwroot/    #把宿主机的config.php拷贝到容器

挂载主机目录/文件作为数据卷:

#挂载一个主机目录作为数据卷 /src/webapp[主机目录]:/opt/webapp[容器目录]:rw (权限)
$ sudo docker run -d -P --name web -v  /src/webapp:/opt/webapp:rw training/webapp python app.py
# Docker挂载数据卷的默认权限 rw,ro[只读] //加入ro后数据卷的数据就无法修改了

#挂载一个本地文件作为数据卷(注意再挂载文件得时候尽量设置ro自读,防止inode不一致报错)
$ sudo docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash
# --rm :当它退出自动移除容器 即docker ps -aq 不能查询到
2.数据卷容器

描述:IF用户需要在容器之间共享一些持续的数据,最简单的方式就是使用数据卷容器(实际上就是一个普通容器);
使用数据卷容器可以让用户在容器之间自由地升级和移动数据卷;

首先创建一个数据卷容器dbdata并在其中创建一个数据卷挂载到/dbdata上;

$ sudo docker run -it -v /dbdate --name dbdate ubuntu

#然后在容器中进行使用 创建两个容器db1 / db2
$ sudo docker run -it --volumes-from dbdate --name db1 ubuntu
$ sudo docker run -it --volumes-from dbdate --name db2 ubuntu
#使用--volumes-from参数所挂载数据卷的容器自身并不需要保持运行状态


#修改目录中其中任何一个文件,其他容器的该目录都会改变
$ sudo docker run -d --name db2 --volumes-from db1 tarining/postgresql      #可以从已有挂载了容器卷的容器来挂载数据卷
#删除挂载的容器(dbdata 、 db1 、db2)数据卷饼不会被自动的删除,必须在删除最后一个挂载着它容器时显示使用Docker rm -v 命令来指定同时删除关联的容器;

(1) 数据卷容器迁移数据
可以利用数据卷容器对其中的数据卷进行备份、恢复以实现数据的迁移;

#备份: 创建一个worker容器 ,将本地当前目录挂载到容器中backup目录,进行选择数据目录备份压缩
$ sudo docker run --volumes-from dbdata -v $(pwd):/backup --name worker ubuntu tar cvf /backup/backup.tar /dbdate

#恢复: 首先创建一个带有数据卷的容器dbdata2
$ sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
#解压备份文件到挂载的数据卷中
$ sudo docker run --volumes-from dbdata2 $(pwd):/backup busybox tar xvf /backup/backup.tar

实例演示:

#挂载
$docker run --name web --rm -dit -v /opt:/opt/ centos /bin/bash
5b3d35fe3305fb458e8b33f39d5fedfbd7d9cb1f6742bcf725cfbf2ecd0245fc
#进入容器
$docker start -i 5b3
#建立一个文件
[root@5b3d35fe3305 opt]$ vi containerDokcer.txt
#宿主机器目录查看
[root@zabbix opt]$ cat containerDokcer.txt
#!/bin/bash
docker

#挂载单个文件
$docker run --rm -it -v ~/.bash_history:/root/.bash_history centos /bin/bash
$docker rm -vf web  #删除容器和数据卷
$docker ps -a  #由于使用--rm参数则会在容器退出时候删除容器

补充说明::Z与:z的区别

#配置selinux标签如果使用selinux,可以添加z或z选项来修改挂载到容器中的主机文件或目录的selinux标签
#:z选项指示绑定挂载内容在多个容器之间共享。
#:Z选项表示绑定挂载内容是私有和非共享的。
#重要:当使用绑定与服务挂载时,selinux标签(:z和:Z)以及:ro将被忽略,设置了z选项以指定多个容器可以共享绑定挂载的内容,此时不能使用——mount标记修改selinux标签
docker run -d --restart=always --name zhcx-v /disk/webapp/war/:/usr/local/tomcat/webapps:z -p 4081:8080 -e JAVA_OPTS=-Dsome.property=value -e Xmx=1536m tomcat-base:6.0.85-jre8

总结:

  • 推荐直接挂载文件目录到容器中,如果直接挂载一个文件到容器中在使用文本编辑工具时候可能会报错;
  • 可以多次使用–volumes-from参数从来多个容器挂载多个数据卷;锁挂载的容器自身并不需要保持在运行状态
  • 推荐使用数据卷和数据容器之外的物理备份存储系统,如RAID或者分布式系统如Ceph,GPFS,HDFS等

0x04 Docker 网络管理

大量互联网服务包括多个服务组件往往需要多个容器之间进行网络通信相互配合,Docker目前提供了映射容器端口与宿主主机和容器互联机制来为容器提网络服务;并且采用Linux系统知道的网络系统来实现对网络服务的支持使之能提供稳定支持以及快速的高性能转发;

当在一台未经过特殊网络配置的centos 或 ubuntu机器上安装完docker之后,在宿主机上通过ifconfig命令可以看到多了一块名为docker0的网卡;不难想到docker0就不只是一个简单的网卡设备了而是一个网桥。

$ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255
$route -n
172.18.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0

#下图即为Docker默认网络模式(bridge模式)下的网络环境拓扑图,创建了docker0网桥,并以eth pair连接各容器的网络,容器中的数据通过docker0网桥转发到eth0网卡上。
#网桥(等同于交换机)

#在Linux中,可以使用brctl命令查看和管理网桥(需要安装bridge-utils软件包),比如查看本机上的Linux网桥以及其上的端口:
$yum install bridge-utils
$brctl show
bridge name     bridge id               STP enabled     interfaces
br-63791a62ad5a   8000.024258a66d6e       no        veth4ce6e0e
                                                    vethe5abf0f
br-6cde78afe495   8000.02420a2496c6       no      veth93e8dc0
                                                  vethfda7b14
docker0   8000.024216e63d3c       no

#docker0网桥是在Docker daemon启动时自动创建的,其IP默认为172.18.0.1/16,之后创建的Docker容器都会在docker0子网的范围内选取一个未占用的IP使用,并连接到docker0网桥上。

#除了使用docker0网桥外,还可以使用自己创建的网桥,比如创建一个名为br0的网桥,配置IP:
brctl  addbr br0
ifconfig  br0 18.18.0.1

#在Docker容器和外界通信的过程中,还涉及了数据包在多个网卡间的转发(如从docker0网卡转发到宿主机ens160网卡)
#需要内核将ip-forward功能打开即将ip_forward系统参数设1
echo 1 > /proc/sys/net/ipv4/ip_forward

WeiyiGeek.bridge模式图


在Docker在1.9版本中network子命令和跨主机网络支持,为了标准化网络的驱动开发步骤和支持多种网络驱动,Docker公司在libnetwork中使用了CNM(Container Network Model)定义了构建容器虚拟化网络的模型。
libnetwork和Docker daemon及各个网络驱动的关系图:
Docker daemon通过调用libnetwork对外提供的API完成网络的创建和管理等功能,libnetwrok中则使用了CNM来完成网络功能的提供;
WeiyiGeek.

CNM中主要有沙盒(sandbox)、端点(endpoint)、网络(network)3种组件:

  • (1)Sandbox:包含了一个容器网络栈的信息,实现对容器的接口、路由和DNS设置等进行管理;
  • (2)Endpoint:它可以加入一个沙盒和一个网络,且一个端点只可以属于一个网络并且只属于一个沙盒;
  • (3)Network:可以直接互相联通的端点(包含多个端点),网络的实现可以是Linux bridge、VLAN等

libnetwork共有5种内置驱动:bridge驱动、host驱动、overlay驱动、remote驱动、null驱动。

  • (1)bridge驱动: Docker默认设置驱动,它可以将创建出来的Docker容器连接到Docker网桥常规方法能满足容器基础需求,然后在复杂场景下使用又诸多限制(使用NAT转发)
  • (2)host驱动:它将不为Docker容器创建网络协议栈(不会创建独立的network namespace),即容器于宿主机共用一个network namespace并使用宿主机的网卡/IP端口等等信息,该驱动适用于对于容器集群规模不大的场景;
  • (3)overlay驱动: 采用IETE标准的VXLAN方式,并且是VXLAN中被普遍认为最适合大规模的云计算虚拟化环境的SDN controller模式,使用时候需要额外的配置存储服务(例如Consul、etcd和zookeeper)
  • (4)remote驱动: 该驱动并未做真正的网络服务实现而是调用了用户自行实现的网络驱动插件,使libnetwork实现了驱动的可插件化,更好地满足了用户的多种需求
  • (5)null驱动: 容器拥有自己的网络命名空间,但并不为Docker容器进行任何网络配置;容器除了network namespace自带的loopback网卡名,没有其他任何网卡、IP、路由等信息(需要用户对齐配置)

libnetwork官方示例:
WeiyiGeek.libnetwork


(1)端口映射实现访问容器
通过-P或者-p来指定端口,

  • 使用-P时候:会进行选择 49000 ~ 49900 端口随机分配映射;
  • 使用-p时候:会让你您设置固定与容器映射的端口;

支持的格式:

  • hostPort:containerPort < 映射到本地指定端口以及容器端口
  • ip:hostPort:containerPort < 映射到本地指定地址以及本地指定端口和容器端口
  • ip::containerPort < 映射本地指定IP的任意端口和容器端口 (注意此处是:
#随机开启端口
$sudo docker run -d -P centos python app.py 

#查看转发的端口
$docker ps -l   

#查看详细的日志信息
$sudo docker logs -f [NAMES] 

#1.映射所有接口地址 [将本地的5000端口映射到容器的5000端口]
$sudo docker run -d -p 5000:5000 centos python app.py 
#2.映射指定地址指定端口
$sudo docker run -d -p 127.0.0.1:5000:5000 centos python app.py 
#3.映射指定地址到的任意端口 还能使用tcp标记来指定udp端口
$sudo docker run -d -p 127.0.0.1::5000/tcp centos python app.py 

#查看端口映射配置
$sudo docker port [NAMES] 5000 #容器Port

(2)实现容器间通信
容器的链接(Linking)系统是除了端口映射外的另一种可以与容器中应用进行交换的方式;它会在源和接收容器之间创建一个隧道,接收容器可以看到源容器指定的信息;

Docker两种方式为容器公开连接信息:

  • 1.环境变量
  • 2.更新/etc/hosts
#首先创建一个新的数据库容器,启动db容器的时候并没有使用-p与-P标记,避免了暴露数据库端口到外部网络上
$sudo docker run -d --name db tranining/postgres

#使db容器与web容器建立互联关系;
#--link name:alias 其中namd是链接的容器的名称,alias是这个链接的别名.
$ sudo docker run -d -P --name web --link db:db training/webapp python app.py

#使用 docker ps 来查看容器的连接
$ docker ps 
CONTAINER ID IMAGE COMMAND CREATED STAT
US PORTS NAMES
349169744e49 training/postgres:latest su postgres -c ''/usr About a minute ago Up About a minute 5432/tcp db, web/db''
#web/db这表示web 容器链接到 db 容器,web 容器将被允许访问 db 容器的信息。


#使用env命令来查看web容器的环境变量
$sudo docker run --rm --name web1 --link db:db training/webapp env
#起点汇总DB_开头的环境变量是提供web容器连接到db使用,前缀采用大写的链接别名
DB_NAME=/web2/db
DB_PORT=tcp://172.17.0.5:5432
DB_PORT_5000_TCP=tcp://172.17.0.5:5432
DB_PORT_5000_TCP_PROTO=tcp
DB_PORT_5000_TCP_PORT=5432
DB_PORT_5000_TCP_ADDR=172.17.0.5


#同时Docker还添加host信息到父容器的/etc/hosts文件
$sudo docker run -it --rm --link db:db training/webapp /bin/bash
cat /etc/hosts

实例:

$docker pull nginx
$docker run -d -p 80:80 --name web nginx
$docker container ls -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
16207d8f2291        nginx               "nginx -g ''daemon of…"   19 seconds ago      Up 18 seconds       0.0.0.0:80->80/tcp   web
#容器有自己的内部网络和IP地址,使用docker inspect + 容器ID 可以获取所有的变量值;
$docker inspect web
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.2",
"MacAddress": "02:42:ac:12:00:02",

#然后打开80端口进行访问采用logs打印访问
$docker logs -f web
218.x.x.xx - - [08/May/2019:15:00:11 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0" "-"

#进行link关联容器使之能进行正常通信
[root@izwz9biz2m4sd3bb3k38pgz ~]$docker run -d --name web1 --link web:nginx_web alpine cat /etc/hosts
ebe1df8c1fb00462b127d36201d558a9f62507c81faea1ce6c4bf4b5ea6075e3

[root@izwz9biz2m4sd3bb3k38pgz ~]$docker run -d --name web2 --link web:nginx_web alpine env
baa9dfe5f64519eb5ccbd122fc191e0f40118a4ee28385a818f7ffe6e2e03639

[root@izwz9biz2m4sd3bb3k38pgz ~]$docker start -i web1
172.18.0.2      nginx_web 16207d8f2291 web  #成功添加web
172.18.0.3      ebe1df8c1fb0

[root@izwz9biz2m4sd3bb3k38pgz ~]$docker start -i web2
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=baa9dfe5f645
NGINX_WEB_PORT=tcp://172.18.0.2:80  #web2也成功添加web
NGINX_WEB_PORT_80_TCP=tcp://172.18.0.2:80
NGINX_WEB_PORT_80_TCP_ADDR=172.18.0.2
NGINX_WEB_PORT_80_TCP_PORT=80
NGINX_WEB_PORT_80_TCP_PROTO=tcp
NGINX_WEB_NAME=/web2/nginx_web
NGINX_WEB_ENV_NGINX_VERSION=1.15.12-1~stretch
NGINX_WEB_ENV_NJS_VERSION=1.15.12.0.3.1-1~stretch

WeiyiGeek.访问容器映射出网站


(3)libnetwork库官方示例
执行流程:

#docker内置的默认默认网卡是是无法使用docker network rm进行删除;
$docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f26c3ed5f7b0        bridge              bridge              local
fd3572aceb38        host                host                local
01da6464c812        none                null                local

#Step 1.创建名为backend、frontend两个网络
$docker network create backend
6cde78afe495a310bb27c5e1a50074b20e204bfa72e71bcaf6a4c37feb300b93
$docker network create frontend
63791a62ad5a5fe4aeb5926616b2ea1d65b490bb9fb718824b7cb1c408ae50c1
$docker network create -d bridge test-net
#-d:参数指定 Docker 网络类型,有 bridge、overlay/none。

#Step 2. 将c1与c2的容器加入到backend网络中,将c3容器加入到frontend网络中
$docker run -itd --name c1 --net backend alpine
729f2abef71ceaf831999d66264d05f78674d9cd2c235f84481a14b366698adb
$docker run -itd --name c2 --net backend alpine
26d47af2d39a1b00f767c60a68cd5f61f1cf5f48652cdcbcb0216968a3185f5e
$docker run -itd --name c3 --net frontend alpine
9cb94f7c66955ba5a95c90d08ce314da0e477f6eddbcea0329309ec36ca5a711


#Step 3. 分别进入c1和c3容器使用ping命令测试其与c2的连通性,因为c1和c2都在backend网络中,所以两者可以连通。但是因为c3和c2不在一个网络中,所以两个容器之间不能连通:
# 使用docker inspect c3 查看IP信息:
C1: 172.19.0.2
C2: 172.19.0.3
C3: "IPAddress": "172.20.0.2",

# 进入c1容器ping c2通、ping c3不通。其它两个容器就不进入演示了,大家自己可以试一下:
# docker exec -it c1 sh
# ip addr
18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:13:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.2/16 brd 172.19.255.255 scope global eth0
# ping c2
PING c2 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.065 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.050 ms
/ # ping 172.20.0.2
PING 172.20.0.2 (172.20.0.2): 56 data bytes


# Step 4. 将c2连接加入到front网络中,使用exec进入c2中查看网卡信息,测试c2与c3的连通性后,可以发现两者已经连通
$docker network connect frontend c2
$docker exec -it c2 sh
/ $ ip addr
20: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:13:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.3/16 brd 172.19.255.255 scope global eth0
24: eth1@if25: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:14:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.3/16 brd 172.20.255.255 scope global eth1

/ $ ping c3
PING c3 (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.100 ms

(4) 跨主机实现互通
通过添加路由路由的方式route

比如:

Docker1: 172.18.0.1/24 --Gateways-- 192.168.1.99

总结:

  • 用户可以链接多个子容器到父容器中比如连接多个web到db容器上;
  • 学习额外的机制比如SDN(软件定义网络)或者NFV(网络功能虚拟化)的相关技术

WeiyiGeek Blog - 为了能到远方,脚下的每一步都不能少。

博主 Blog 镜像站点(友链交换请邮我哟):

  • https://weiyigeek.top # 国内访问较慢
  • https://blog.weiyigeek.top # 更新频繁
  • https://weiyigeek.gitee.io # 国内访问快可能会有更新不及时得情况

更多原创学习笔记文章请关注 WeiyiGeek 公众账号

【点击我关注】

WeiyiGeek-公众账号

3.Docker容器学习之新手基础使用

3.Docker容器学习之新手基础使用

文章目录

        • 0x00 Docker进阶补充
          • 0.镜像与容器
          • 1.数据管理
          • 2.高级网络配置
        • 0x01 搭建私有仓库
        • 0x02 Dockerfile基础学习
        • 0x03 Docker-Compose编排
          • 1. 安装与配置
          • 2. 命令一览
          • 3. 模板文件
          • 4. 使用案例

学习参考:https://yeasy.gitbooks.io/docker_practice/repository/registry.html

0x00 Docker进阶补充

0.镜像与容器

什么是虚悬镜像?
答: 虚悬镜像(dangling image),在使用docker images 查看镜像既没有仓库名,也没有标签均为
产生原因:由于新旧镜像同名,旧镜像名称被取消,从而出现仓库名、标签均为 的镜像。

#查看与删除虚悬镜像
$ docker images -f dangling=true
$ docker rmi $(docker images -q -f dangling=true)

1.数据管理

(1)数据卷的使用
启动一个挂载数据卷的容器,进行容器之间的资源共享;

$docker volume create myvol
$docker volume ls
local               myvol

#下面创建一个名为 web 的容器,并加载一个 数据卷 到容器的 /webapp 目录。
$ docker run -d -P \
    --name web \
    # -v my-vol:/wepapp \
    #挂载一个数据卷到容器之中
    --mount source=my-vol,target=/webapp \
    #挂载一个本地主机文件作为数据卷
    --mount type=bind,source=$HOME/.bash_history,target=/root/.bash_history,readonly \
    training/webapp \
    sh

#进入webapp修改目录进行修改东文件,在其他容器中验证是否可以进行数据共享交互
docker run -it --name web2 -v myvol:/webapp centos sh  #-v 与 --mount产生的效果差不多

sh-4.2# cat test.txt #实现了资源共享
asdasdasdasda:


#查看数据卷的具体信息
"Mounts": [
            {
   
                "Type": "volume",
                "Name": "myvol",
                "Source": "/var/lib/docker/volumes/myvol/_data",
                "Destination": "/webapp",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": ""
            }
        ],

#删除数据卷(注意正在使用的不能删除)
docker volume rm `docker volume ls -q`

(2)利用数据卷容器来备份、恢复、迁移数据卷
可以利用数据卷对其中的数据进行进行备份、恢复和迁移

#备份
#首先使用 --volumes-from 标记来创建一个加载 dbdata 容器卷的容器,并从主机挂载当前目录到容器的 /backup 目录
#容器启动后,使用了 tar 命令来将 dbdata 卷备份为容器中 /backup/backup.tar 文件,也就是主机当前目录下的名为 backup.tar 的文件。
$ sudo docker run --volumes-from dbdata -v $(pwd):/backup ubuntu -C "tar cvf /backup/backup.tar /dbdata"
/ # ls
backup  dbdata  

#恢复
#首先创建一个带有空数据卷的容器 dbdata2
sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
#然后创建另一个容器,挂载 dbdata2 容器卷中的数据卷,并使用 untar 解压备份文件到挂载的容器卷中。
$ sudo docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
-rw-r--r-- 1 root  root  5120 5月  24 15:02 dbdata.tar

#为了查看/验证恢复的数据,可以再启动一个容器挂载同样的容器卷来查看
$ sudo docker run --volumes-from dbdata2 busybox /bin/ls /dbdata

2.高级网络配置

容器互联:随着 Docker 网络的完善,强烈建议大家将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 --link 参数

如何自定义配置容器的主机名和 DNS 呢?
答:Docker 会默认用主机上的 /etc/resolv.conf 来配置容器, 所以可以直接在宿主机上的resolv.conf文件中进行更改,也可以在/etc/docker/daemon.json 文件中增加DNS键值对是一个数组;

#新建网络
docker network create -d bridge my-net
#分别启动两个容器(然后进入互ping查看)
$docker run -it --rm --name busybox1 --network my-net busybox sh
$docker run -it --rm --name busybox1 --network my-net busybox sh


#秘诀就是 Docker 利用虚拟文件来挂载容器的 3 个相关配置文件,在容器中使用 mount 命令可以看到挂载信息
#可以让宿主主机 DNS 信息发生更新后,所有 Docker 容器的 DNS 配置通过 /etc/resolv.conf 文件立刻得到更新。
/dev/mapper/cl-root on /etc/resolv.conf type xfs (rw,relatime,attr2,inode64,noquota)
/dev/mapper/cl-root on /etc/hostname type xfs (rw,relatime,attr2,inode64,noquota)
/dev/mapper/cl-root on /etc/hosts type xfs (rw,relatime,attr2,inode64,noquota)
#Docker 1.2.0 开始支持在运行中的容器里编辑 /etc/hosts, /etc/hostname 和 /etc/resolv.conf 文件。
#但是这些修改是临时的,只在运行的容器中保留,容器终止或重启后并不会被保存下来,也不会被 docker commit 提交。

#宿主机更改后立即生效(容器重新进入的时候)
$docker start -i 81fa
sh-4.2# cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 192.168.10.254
nameserver 61.128.128.68
nameserver 114.114.114.114

Docker 网络原理
当 Docker 启动时,会自动在主机上创建一个 docker0 虚拟网桥,实际上是 Linux 的一个 bridge,可以理解为一个软件交换机,它会在挂载到它的网口之间进行转发。
同时,Docker 随机分配一个本地未占用的私有网段(在 RFC1918 中定义)中的一个地址给 docker0 接口

  • 比如典型的 172.17.42.1,掩码为 255.255.0.0

Docker 就创建了在主机和所有容器之间一个虚拟共享网络
当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包), 这对接口

  • 一端在容器内即 eth0;
  • 另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头(例如 vethAQI2QT)

通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。
WeiyiGeek.Docker网络


容器访问控制
容器的访问控制,主要通过 Linux 上的 iptables 防火墙来进行管理和实现.
容器访问外部网络,需要本地系统的转发支持。在Linux 系统中,检查转发是否打开。

$sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

#如果在启动 Docker 服务的时候设定 --ip-forward=true, Docker 就会自动设定系统的 ip_forward 参数为 1。
$sysctl -w net.ipv4.ip_forward=1

容器之间访问需要两方面的支持:

  • 容器的网络拓扑是否已经互联。默认情况下,所有容器都会被连接到 docker0 网桥上。
  • 本地系统的防火墙软件 – iptables 是否允许通过。
    动容器(docker run)时使用 --link=CONTAINER_NAME:ALIAS 选项,就会在宿主机上添加了 iptables 规则。
$ sudo iptables -nL
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
ACCEPT     tcp  --  172.17.0.2           172.17.0.3           tcp spt:80
ACCEPT     tcp  --  172.17.0.3           172.17.0.2           tcp dpt:80
DROP       all  --  0.0.0.0/0            0.0.0.0/0

默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。

  • 容器访问外部实现:容器所有到外部网络的连接,源地址都会被 NAT 成本地系统的 IP 地址
  • 外部访问容器实现:可以在 docker run 时候通过 -p 或 -P 参数来启用。

不管用那种办法,其实也是在本地的 iptable 的 nat 表中添加相应的规则

$sudo iptables -t nat -nL
#其中,上述规则将所有源地址在 172.17.0.0/16 网段,目标地址为其他网段(外部网络)的流量动态伪装为从系统网卡发出。
#MASQUERADE 跟传统 SNAT 的好处是它能动态从网卡获取地址。
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16       !172.17.0.0/16


#使用端口映射的时候
chain DOCKER (2 references)
target     prot opt source               destination
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80

docker 网桥
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。
Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信,它还给出了 MTU(接口允许接收的最大传输单元),通常是 1500 Bytes,或宿主主机网络路由上支持的默认值,值都可以在服务启动的时候进行配置。

#由于目前 Docker 网桥是 Linux 网桥,用户可以使用 brctl show 来查看网桥和端口连接信息。
$brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0242f0960e9f       no              veth4fe5b74

#每次创建一个新容器的时候,Docker 从可用的地址段中选择一个空闲的 IP 地址分配给容器的 eth0 端口。使用本地主机上 docker0 接口的 IP 作为所有容器的默认网关。
$ sudo docker run -i -t --rm base /bin/bash
$ip addr show eth0
$ip route
default via 172.17.42.1 dev eth0
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.3

#自定义网桥:
#用户也可以指定网桥来连接各个容器,在启动 Docker 服务的时候,使用 -b BRIDGE或--bridge=BRIDGE 来指定使用的网桥。
1. 如果服务已经运行,那需要先停止服务,并删除旧的网桥。
$ sudo systemctl stop docker
$ sudo ip link set dev docker0 down #将网卡处于非工作状态
$ sudo brctl delbr docker0   #删除默认网桥
$ sudo brctl addbr bridge0   #然后创建一个网桥 bridge0。
$ sudo ip addr add 192.168.5.1/24 dev bridge0
$ sudo ip link set dev bridge0 up  #查看确认网桥创建并启动。

*注:brctl 命令在 Debian、Ubuntu /Centsos采用相同的包中可以使用 sudo apt-get install bridge-utils 来安装。

示例:创建一个点到点连接,点到点链路不需要子网和子网掩码。
默认情况下,Docker 会将所有容器连接到由 docker0 提供的虚拟子网中,用户有时候需要两个容器之间可以直连通信,而不用通过主机网桥进行桥接。
解决办法很简单:创建一对 peer 接口,分别放到两个容器中,配置成点到点链路类型即可

$docker run -it --rm --net=none --name demo1 alpine sh
39ca23ce4417

$docker run -it --rm --net=none --name demo2 alpine sh
d4b1311349c1

#找到进程号,然后创建网络命名空间的跟踪文件。
$docker inspect -f ''{
   {.State.Pid}}'' d4b
6742
$docker inspect -f ''{
   {.State.Pid}}'' 39c
6807

sudo mkdir -p /var/run/netns
sudo ln -s /proc/6742/ns/net /var/run/netns/6742
sudo ln -s /proc/6807/ns/net /var/run/netns/6807

#创建一对A B peer 接口,然后配置路由
$ sudo ip link add A type veth peer name B

$ sudo ip link set A netns 6742
$ sudo ip netns exec 6742 ip addr add 10.1.1.1/32 dev A
$ sudo ip netns exec 6742 ip link set A up
$ sudo ip netns exec 6742 ip route add 10.1.1.2/32 dev A

$ sudo ip link set B netns 6807
$ sudo ip netns exec 6807 ip addr add 10.1.1.2/32 dev B
$ sudo ip netns exec 6807 ip link set B up
$ sudo ip netns exec 6807 ip route add 10.1.1.1/32 dev B

#现在这 2 个容器就可以相互 ping 通,并成功建立连接。点到点链路不需要子网和子网掩码。
容器$ ip addr

WeiyiGeek.点到点通信


0x01 搭建私有仓库

描述: 镜像仓库主要是用来存储和分发镜像的,并对外提供一套 HTTP API V2。镜像仓库中的所有镜像,都是以数据块 (Blob) 的方式存储在文件系统中。 支持多种文件系统,主要包括filesystem,S3,Swift,OSS等。

产生原因:
Docker hub是公开的其他人也是可以下载并不安全因此还可以使用docker registry官方提供的私有仓库;但是我们默认在机器上搭建的registry私有仓库是不需要验证的,因此我们需要进行安全配置仓库并加入认证;

Docker Registry由三个部分组成:

  • index: 负责登录、负责认证、负责存储镜像信息和负责对外显示的外部实现
  • registry: 负责存储镜像的内部实现
  • registry client: 则是docker 客户端

registry认证:https://yeasy.gitbooks.io/docker_practice/repository/registry_auth.html

#1.下载registry仓库并设置数据存放的目录(并生成认证账号密码)
docker pull registry

mkdir -vp /opt/data/auth   #宿主机认证目录
mkdir -vp /opt/data/registry  #宿主机仓库目录

#采用--entrypoint进行执行
docker run --entrypoint htpasswd registry -Bbn testuser testpassword > auth/htpasswd

#2.运行下载的仓库镜像(我们常常指定一个本地数据卷给容器)
docker run -d -p 5000:5000 -v /opt/data/registry:/var/lib/registry registry  #未认证
##加入认证
docker run -d -p 5000:5000 --restart=always --name docker-hub \
  -v /opt/data/registry:/var/lib/registry \
  -v /opt/data/auth:/auth \
  -e "REGISTRY_AUTH=htpasswd" \
  -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
  registry


#Docker 默认不允许非 HTTPS 方式推送镜像。我们可以通过 Docker 的配置选项来取消这个限制
# 3.修改docker的配置文件,让他支持http方式,上传私有镜像 (本地)

tee /etc/docker/daemon.json <<EOF # 写入如下内容 { "registry-mirror": [ "https://registry.docker-cn.com" ], "insecure-registries": [ "192.168.11.37:5000" ] } EOF

# 4.修改docker的服务配置文件
vim /lib/systemd/system/docker.service
# 找到[service]这一代码区域块,写入如下参数
[Service]
EnvironmentFile=-/etc/docker/daemon.json

# 5.重新加载docker服务
systemctl daemon-reload

# 6.重启docker服务
systemctl restart docker
# 注意:重启docker服务,所有的容器都会挂掉
docker run -d -p 5000:5000 --name dockerregistry -v /opt/data/registry:/var/lib/registry  registry

# 7.修改本地镜像的tag标记,往自己的私有仓库推送
#docker tag weiyigeek/hello-world-docker 192.168.11.37:5000/weiyigeek #对于修改名称的
$docker commit -m "alpine-sh" -a "weiyigeek" a63 10.10.107.221:5000/alpine-sh
sha256:b75ef26a9e1d92924914edcb841de8b7bdc0b336cea2c6cfbaaf6175e24472c6

$docker login 10.10.107.221:5000
Username: testuser
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

#上传我们的镜像文件
$docker push 10.10.107.221:5000/alpine-sh
The push refers to repository [10.10.107.221:5000/alpine-sh]
2a499f806f16: Pushed
f1b5933fe4b5: Pushed
latest: digest: sha256:6d13420cb9ce74095e2a71f565fc8c15ba17b40933e14534fc65775025eedd18 size: 735

# 8.下载私有仓库的镜像(查看)
docker pull 192.168.11.37:5000/weiyige
# http://192.168.119.10:5000/v2/_catalog #查看仓库 需要进行认证
# http://192.168.119.10:5000/v2/[image_name]/tags/list #查看镜像版本列表
curl -XGET  http://10.10.107.221:5000/v2/_catalog -u testuser:testpassword
{
   "repositories":["alpine-sh"]}

WeiyiGeek.docker仓库

设置账号密码认证后访问将受到限制:
WeiyiGeek.regsitryLogin


补充说明:

  • (1) 通过 Registry API 获得的两个镜像仓库中相同镜像的 manifest 信息的存储路径和内容完全相同。并且两个镜像仓库中相同镜像的 blob 信息的存储路径和内容完全相同
#(1)Registry API

#(2)Harbor 本地目录中
/var/lib/kubelet/cargo/release/data/harbor/registry/docker/registry/v2

# 查看镜像 Manifest 对应的blob id
$cat repositories/release/cyclone-server/_manifests/tags/v0.5.0-beta.1/current/link
sha256:6d47a9873783f7bf23773f0cf60c67cef295d451f56b8b79fe3a1ea217a4bf98
# 查看镜像 Manifest 
$cat blobs/sha256/6d/6d47a9873783f7bf23773f0cf60c67cef295d451f56b8b79fe3a1ea217a4bf98/data

# Blob 数据的存储
# 查看镜像 blob 的位置和大小
$du -s blobs/sha256/71/7118e0a5b59500ceeb4c9686c952cae5e8bfe3e64e5afaf956c7098854a2390e/data
7560 blobs/sha256/71/7118e0a5b59500ceeb4c9686c952cae5e8bfe3e64e5afaf956c7098854a2390e/data

0x02 Dockerfile基础学习

我们需要保证了稳定的变化的命令至于上层保证了每层打包出来的 Layer 能够尽可能的复用,而不会徒增镜像的大小;
*注意:*一个镜像构建时不能超过 127 层

案例:将我的hexo搭建的博客进行dockerfile部署

#基础镜像
FROM mhart/alpine-node:latest
#作者描述
LABEL maintainer="weiyigeek <weiygeek@qq.com>"
LABEL description="weiyigeek blog"

#建立项目目录以及切换工作目录
RUN mkdir -vp /opt/web/
WORKDIR /opt/web/


#更新alpine软件源和下载git
RUN apk update && apk add git && echo $?
RUN git clone https://gitee.com/WeiyiGeek/blog.git
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

#相对重要:不能采用cd进行切换
WORKDIR /opt/web/blog/

#下载博客hexo框架与依赖
RUN npm install -g hexo-cli --save
RUN npm install --production --registry=https://registry.npm.taobao.org --save

#对外暴露的端口
EXPOSE 4000

#容器建立好运行的命令
ENTRYPOINT ["hexo", "server"]

WeiyiGeek.hexoblog-dockerfile

执行完成后将会在docker iamges 中显示我们设置仓库名称:

$docker run -d -p 80:4000 --name blog weiyigeek/blog
c6059fc19891792ce03304bcf943dccd708e5b8c7565fe86159d3407e23e7530

$docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES
c6059fc19891        weiyigeek/blog      "hexo server"       7 seconds ago       Up 5 seconds        0.0.0.0:80->4000/tcp   blog

1.Dockerfile多阶段构建
构建docker容器的多种方式
方式1:将所有的构建过程编包含在一个 Dockerfile 中,包括项目及其依赖库的编译、测试、打包等流程
问题:

  • 镜像层次多,镜像体积较大,部署时间变长
  • 源代码存在泄露的风险

优点:

  • 管理方便简单

方式2:将项目及其依赖库编译测试打包好后,再将编译好的可执行文件拷贝到运行环境中
问题:

  • 部署过程较复杂

优点:

  • 生成的镜像大小相比较于方式1较小

比如:(参照下面的多阶段构建)

#!/bin/sh
#该方式构建需要shell文件来进行打包融合
echo Building gcc/helloworld:build

#进行编译环境搭建并编译环境
docker build -t gcc/helloworld:build . -f Dockerfile.build

#创建编译的容器
docker create --name extract go/helloworld:builder
docker cp extract:/gcc/demo/test ./test
docker rm -f extract

echo Building gcc/helloworld:runner
#构建运行时环境
docker build --no-cache -t gcc/helloworld:2 . -f Dockerfile.copy

rm ./test

方式3:Docker v17.05 开始支持多阶段构建 (multistage builds),此种方法综合和方式1和2并且解决了他们响应的问题;


案例比如: 我们要编译.c文件分为两步进行,编译c再运行
test.c 文件如下:

#include <stdio.h>

int main(void)
{
   
	printf("Hello World! Dockerfile!\n");
	return 0;
}

使用多阶段构建

#编译阶段
#Dockerfile.build
FROM alpine as builder
MAINTAINER weiyigeek <weiyigeek@q.com>
RUN apk update && apk --no-cache add gcc g++
WORKDIR /gcc/demo/
COPY test.c .
RUN gcc test.c -o test

#运行阶段
#Dockerfile.run
FROM alpine-c as runer
WORKDIR /gcc/demo/
COPY --from=0 /gcc/demo/test . #复制 builder 阶段成果二进制文件test到 当前镜像之中
CMD ["./test"]

构建镜像

#项目结构
$ls
mutilDockerfile  test.c

#构建镜像
$docker build -t weiyigeek/hello:1  -f mutilDockerfile .  #注意上下文
Sending build context to Docker daemon  3.072kB
Step 1/10 : FROM alpine as builder
 ---> 055936d39205
Step 2/10 : MAINTAINER weiyigeek <weiyigeek@q.com>
 ---> Running in 59097e3a8120
Removing intermediate container 59097e3a8120
 ---> 8e796c96a921
Step 3/10 : RUN apk update && apk --no-cache add gcc g++
 ---> Running in 89fca19b761d

#运行构建的镜像
$docker run --name hello weiyigeek/hello:1
Hello World! Dockerfile!

0x03 Docker-Compose编排

描述:Docker Compose 是使用 Python 开发的一款基于 Docker 容器进行编排的工具,定义和运行多容器的应用可以一条命令启动多个容器, 从提到的Docker-Machine种可以将用户在其他平台快速安装Docker,而Swarm可以让Docker容器在集群种高效运转,而Compose则可以让用户在集群中部署分布式应用。

从功能上看跟 OpenStack 中的 Heat 十分类似,Compose 定位是 「定义和运行多个 Docker 容器的应用(Defining and running multi-container Docker applications)」,其前身是开源项目 Fig。
简单的说: Docker Compose 属于一个应用层的服务,用户可以定义哪一个容器组运行那些应用,它支持动态改变应用并在需要时扩展;

产生原因:由于单纯的使用Dockerfile只能设置一个Docker镜像且采用多阶段构建的时候entrypoint指令只能存在一个,为了解决这个问题引入了Docker Compose机制;它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project),免去我们需要多次执行docker run命令的烦恼;

其代码目前在:https://github.com/docker/compose

Docker Compose 优点:

  • 安装与使用非常简单的
  • 能够帮我们处理容器的依赖关系,在每个容器中会将容器的 IP 和服务的名称使用 hosts 的方式绑定,这样我们就能在容器中直接使用服务名称来接入对应的容器了
  • 使用 docker-compose.yaml 配置的形式将你需要启动的容器管理起来。

使用Compose 基本上分为三步:

  • Dockerfile 定义应用的运行环境
  • docker-compose.yml 定义组成应用的各服务
  • docker-compose up 启动整个应用

Compose 中有两个重要的概念:

  • 服务 (service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。
  • 项目 (project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。

应用场景:最常见的项目是 web 网站,该项目应该包含 web 应用和缓存。

一个简单的docker-compose.yml配置文件:

version: "2"
services:
    nginx:
        depends_on:
          - "php"
        image: "nginx:latest"
        volumes:
          - "$PWD/src/docker/conf:/etc/nginx/conf.d"
          - "$PWD:/home/q/system/m_look_360_cn"
        ports:
          - "8082:80"
        container_name: "m.look.360.cn-nginx"
    php:
        image: "lizheming/php-fpm-yaf"
        volumes:
            - "$PWD:/home/q/system/m_look_360_cn"
        container_name: "m.look.360.cn-php"

#例如下面这个 Nginx 配置中的php:9000就是利用了这个原理。
server {
   
  listen 80;
  server_name dev.m.look.360.cn;
  charset utf-8;
  root /home/q/system/m_look_360_cn/public;
  index index.html index.htm index.php;
  error_page 500 502 503 504 /50x.html;
  location = /50x.html {
   
    root html;
  }
  # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
  location ~ .php$ {
   
    ##在每个容器中会将容器的 IP 和服务的名称使用 hosts 的方式绑定
    fastcgi_pass php:9000;
    #fastcgi_pass unix:/tmp/fcgi.sock;
    fastcgi_index index.php;
  }
}

1. 安装与配置

Compose 支持 Linux、macOS、Windows 10 三大平台。

安装方法与流程:

#pip方式安装
$sudo pip install -U docker-compose
#采用yum方式安装
$yum install -y docker-compose
#二进制包 在 Linux 上的也安装十分简单,从 官方 GitHub Release 处直接下载编译好的二进制文件即可。
$sudo curl -L https://github.com/docker/compose/releases/download/1.17.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
$sudo chmod +x /usr/local/bin/docker-compose

#卸载
sudo rm /usr/local/bin/docker-compose  #如果是二进制包方式安装的,删除二进制文件即可。
sudo pip uninstall docker-compose    #如果是通过 pip 安装的,则执行如下命令即可删除。

#安装成功测试
$docker-compose --version
docker-compose version 1.18.0, build 8dd22a9

容器中执行:Compose 既然是一个 Python 应用,自然也可以直接用容器来执行它。

$ curl -L https://github.com/docker/compose/releases/download/1.8.0/run.sh > /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose

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

#其他安装方式
[root@localhost ~]# pip3 -V
pip 9.0.3 from /usr/lib/python3.6/site-packages (python 3.6)
[root@localhost ~]# pip3 install docker-compose
[root@localhost ~]# docker-compose version
docker-compose version 1.25.3, build unknown
docker-py version: 4.1.0
CPython version: 3.6.8
OpenSSL version: OpenSSL 1.1.1c FIPS  28 May 2019

2. 命令一览

Compose 来说,大部分命令的对象既可以是项目本身,也可以指定为项目中的服务或者容器

#docker命令的基本的使用格式是
docker-compose [options] [COMMAND] [ARGS...]

#查看帮助
docker-compose [COMMAND] --help 或者 docker-compose help [COMMAND]

命令选项:

  • -f, --file FILE 指定使用的 Compose 模板文件,默认为 docker-compose.yml可以多次指定。
  • -p, --project-name NAME 指定项目名称,默认将使用所在目录名称作为项目名。
  • –x-networking 使用 Docker 的可拔插网络后端特性
  • –x-network-driver DRIVER 指定网络后端的驱动,默认为 bridge
  • –verbose 输出更多调试信息。
  • -v, --version 打印版本并退出。

命令使用说明:

build  #构建(重新构建)项目中的服务容器,可以随时在项目目录下运行 docker-compose build 来重新构建服务。
config #验证 Compose 文件格式是否正确,若正确则显示配置,若格式错误显示错误原因。
up / down  #此命令将会启动/停止 up命令所启动的容器(up是非常重要的),并创建/移除网络
exec  #进入指定的容器。
help
images  #列出 Compose 文件中包含的镜像。
kill  #通过发送 SIGKILL 信号来强制停止服务容器,支持通过 -s 参数来指定发送的信号,例如通过如下指令发送 SIGINT 信号。
logs  #查看服务容器的输出以不同颜色来区分,可以通过 --no-color 来关闭颜色。
port  #打印某个容器端口所映射的公共端口。
ps   #列出项目中目前的所有容器。
pull  #拉取服务依赖的镜像。
push  #推送服务依赖的镜像到 Docker 镜像仓库。
run   #在指定服务上执行一个命令(重点)
scale  #设置指定服务运行的容器个数。
start  #启动已经存在的服务容器。
pause  #暂停一个服务容器。
unpause #恢复处于暂停状态中的服务。
restart #重启项目中的服务。
stop  #停止已经处于运行状态的容器,但不删除它。(可通过start启动)
rm  #删除所有(停止状态的)服务容器,推荐先执行stop
top  #查看各个服务容器内运行的进程。
version

常用命令详解:

#build格式 docker-compose build [options] [SERVICE...]
选项包括:
  --force-rm 删除构建过程中的临时容器。
  --no-cache 构建镜像过程中不使用 cache(这将加长构建过程)。
  --pull 始终尝试通过 pull 来获取更新版本的镜像。


#run格式为 docker-compose run [options] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...]。
选项:
  -d 后台运行容器。
  --name NAME 为容器指定一个名字。
  --entrypoint CMD 覆盖默认的容器启动指令。
  -e KEY=VAL 设置环境变量值,可多次使用选项来设置多个环境变量。
  -u, --user="" 指定运行容器的用户名或者 uid。
  --no-deps 不自动启动关联的服务容器。
  --rm 运行命令后自动删除容器,d 模式下将忽略该选项。
  -p, --publish=[] 映射容器端口到本地主机。
  --service-ports 配置服务端口并映射到本地主机。
  -T 不分配伪 tty,意味着依赖 tty 的指令将无法运行。

例如:
$docker-compose run ubuntu ping docker.com  #将会启动一个 ubuntu 服务容器,并执行 ping docker.com 命令。


#up格式 docker-compose up [options] [SERVICE...] 
#该up十分强大:它将尝试自动完成包括构建镜像build的工作,(重新)创建服务,启动服务run的工作,并关联服务相关容器的一系列操作。
docker-compose up  #前台启动,控制台将会同时打印所有容器的输出信息,可以很方便进行调试。
docker-compose up -d   #后台启动,查看信息需要使用logs命令,般推荐生产环境下使用该选项。
选项:
  -d 在后台运行服务容器。
  --no-color 不使用颜色来区分不同的服务的控制台输出。
  --no-deps 不启动服务所链接的容器。
  --force-recreate 强制重新创建容器,不能与 --no-recreate 同时使用。
  --no-recreate 如果容器已经存在了,则不重新创建,不能与 --force-recreate 同时使用。
  --no-build 不自动构建缺失的服务镜像。
  -t, --timeout TIMEOUT 停止容器时候的超时(默认为 10 秒)。


#rm格式为 docker-compose rm [options] [SERVICE...]。
选项:
  -f, --force 强制直接删除,包括非停止状态的容器。一般尽量不要使用该选项(使用前建议先stop)
  -v 删除容器所挂载的数据卷。


#scale格式为 docker-compose scale [options] [SERVICE=NUM...]
#通过 service=num 的参数来设置数量。例如:
$docker-compose scale web=3 db=2 #将启动 3 个容器运行 web 服务,2 个容器运行 db 服务。

注意:

  • 默认情况,如果服务容器已经存在,docker-compose up 将会尝试停止容器,然后重新创建(保持使用 volumes-from 挂载的卷),以保证新启动的服务匹配 docker-compose.yml 文件的最新内容。
  • 如果用户不希望容器被停止并重新创建,可以使用 docker-compose up --no-recreate。这样将只会启动处于停止状态的容器,而忽略已经运行的服务。
  • 如果用户只想重新部署某个服务,可以使用 docker-compose up --no-deps -d <SERVICE_NAME> 来重新创建服务并后台停止旧服务,启动新服务,并不会影响到其所依赖的服务。
  • 使用 docker-compose scale一般的当指定数目多于该服务当前实际运行容器,将新创建并启动容器;反之将停止容器。

实际案例:
建议在空目录中建立Dockerfile与docker-compose.yml,并运行docker-compose运行的时候建议在Dockerfile与docker-compose.yml 当前目录下运行

$docker-compose config   #验证Dockerfile脚本-正确返回配置
services:
  redis:
    image: redis:alpine
  web:
    build:
      context: /opt/app
    ports:
    - 80:8080/tcp
version: ''3.0''


$docker-compose -p FlaskApp build  #构建容器
Building web
Step 1/5 : FROM python:3.6-alpine

$docker-compose up -d  #后台启动容灾
Creating network "app_default" with the default driver
Building web
Step 1/5 : FROM python:3.6-alpine
 ---> 35bb01a3d284
Step 2/5 : ADD . /code


$docker-compose images   #显示构建运行后的容器
 Container    Repository    Tag       Image Id      Size
----------------------------------------------------------
app_redis_1   redis        alpine   72e76053ebb7   48.5 MB
app_web_1     app_web      latest   e5024b7bdce1   86.1 MB

$docker-compose ps   #项目中目前的容器状态
   Name                  Command               State          Ports
---------------------------------------------------------------------------
app_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp
app_web_1     python app.py                    Up      0.0.0.0:80->8080/tcp


$docker-compose logs   #后台运行的容器信息
Attaching to app_redis_1, app_web_1
web_1    |  * Debug mode: on
web_1    |  * Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)
web_1    |  * Restarting with stat
web_1    |  * Debugger is active!
web_1    |  * Debugger PIN: 324-716-279


$docker-compose exec web /bin/sh  #进入web服务的容器中(前提是必须运行,退出不影响后台运行的容器)
/code # ls
Dockerfile          app.py              docker-compose.yml
/code # whoami
root
/code # hostname
2e10bc9c7618
/code #

$docker-compose stop    #停止容器
Stopping app_redis_1 ... done
Stopping app_web_1   ... done


$docker-compose rm -v  #删除构建的容器
Going to remove app_redis_1, app_web_1
Are you sure? [yN] y
Removing app_redis_1 ... done
Removing app_web_1   ... done


$docker-compose kill -s SIGINT  #通过发送 SIGKILL 信号来强制停止服务容器。

3. 模板文件

标准配置的docker-compose.yaml文件应该包含 version、services、networks 三大部分其中最关键的就是 services 和 networks 两个部分还有就是配置文件的格式

模板文件是使用 Compose 的核心,涉及到的指令关键字也比较多,以下面的案例为例:

#docker-composer版本注意冒号后有个空格
version: ''3''
services:

#用户自定义服务名称
  web:

    #指定服务的镜像名称或镜像ID(先从本地拉取,如果没有找到则从从Docker Hub获取镜像)
    image: ubuntu/ubuntu:18.04

    #服务除了可以基于指定的镜像,还可以基于一份 Dockerfile,在使用 up 启动之时执行构建任务,这个构建标签就是 build,它可以指定 Dockerfile 所在文件夹的路径
    build:/path/to/build/dir  #方式1:存放dockerfile的可以是绝对路径也可以是相对路径
    #方式2:设定上下文根目录,然后以该目录为准指定 Dockerfile。
    build:  
      context: ../
      dockerfile: path/of/Dockerfile  
      #在 Dockerfile 中设置的选项(例如:CMD, EXPOSE, VOLUME, ENV 等) 将会自动被获取,无需在 docker-compose.yml 中再次设置。
      args:  #使用 arg 指令指定构建镜像时的变量。
        buildno: 1
      cache_from:  #使用 cache_from 指定构建镜像的缓存
        - alpine:latest
        - corp/web_app:3.14

    #自定义容器命名格式是:<项目名称><服务名称><序号>
    container_name: app

    #lables指令 向容器添加元数据,和Dockerfile的LABEL指令一个意思,格式如下:
    labels:
      - "com.example.author=weiyigeek"
      - "com.example.description=Accounting webapp"
      - "com.example.department=Finance"
      - "com.example.lrelease=rc3 for v1.0"

    #一般项目容器启动的顺序是有要求的, depends_on标签解决了容器的依赖、启动先后的问题。、
    #例如下面容器会先启动 redis 和 db 两个服务,最后才启动 web 服务:
    depends_on:  #定义了依赖关系
      - db
      - redis
    redis:
      image: redis
    db:
      image: postgres
    #注意:web 服务不会等待 redis db 「完全启动」之后才启动。

    #配置日志选项。
    logging:
      driver: syslog #目前支持三种日志驱动类型,"none" / "json-file"
      options: #配置日志驱动的相关参数。
        syslog-address: "tcp://192.168.0.42:123"
        max-size: "200k"
        max-file: "10"

    #ports标签指定映射端口,使用HOST:CONTAINER格式或者只是指定容器的端口,宿主机会随机映射端口。
    ports:
      - 8080   #注意格式
      - "49100:22"
      - "127.0.0.1:8001:8001"

    #管理全部服务的标签,比如设置全部服务的user标签值为USER,默认属性(用户、角色、类型、级别等)
    security_opt:
      - label:user:USER
      - label:role:ROLE

    #设置另一个信号来停止容器,默认情况下是使用SIGTERM停止容器
    stop_signal: SIGUSR1

    #配置容器连接的网络
    networks:
      - front-tier
      - back-tier
    
    #设置网络模式使用和 docker run 的 --network 参数一样的值。
    network_mode: "bridge" # "host" "none" "service:[service name]" "container:[container name/id]"

    #和 --dns 参数一样用途,格式如下:
    dns: 
      - 8.8.8.8
      - 9.9.9.9
    #此外 dns_search 的配置也类似
    dns_search:
      - dc1.example.com
      - dc2.example.com


  redis:
    image: redis

    #tmpfs标签 挂载临时目录到容器内部(挂载一个 tmpfs 文件系统到容器),与 run 的参数一样效果:
    tmpfs: /run  #两种形式 单个和多个
    tmpfs:
      - /run
      - /tmp

    #env_file 标签指定.env 文件来存放设置的 Compose 的变量
    #如果通过 docker-compose -f FILE 指定了配置文件,则 env_file 中路径会使用配置文件路径。
    env_file:
      - ./common.env
      - ./apps/web.env
      - /opt/secrets.env


    #environment标签设置镜像变量,而且它可以保存变量到镜像/容器里面(类似 docker run -e 的效果)
    #如果有变量名称与 environment 指令冲突,则按照惯例,以后者为准。
    environment:
      - RACK_ENV=development
      - SHOW=true
      - SESSION_SECRET
      - MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password

    #存储敏感数据,例如 mysql 服务密码,需要后面的配置
    secrets:
      - db_root_password
      - my_other_secret

    #与Dockerfile中的EXPOSE指令一样,用于指定暴露的端口(只是作为参考实际上常用ports指令)
    expose:
      - "6379"
 
    #links标签解决的是容器连接问题,与Docker client的--link一样效果,会连接到其它服务中的容器。
    #使用的别名将会自动在服务容器中的/etc/hosts里创建
    links:
      - web

    #使用 command 可以覆盖容器启动后默认执行的命令。
    command: bundle exec thin -p 3000
    #command: [bundle, exec, thin, -p, 3000] #写成类似 Dockerfile 中的格式

    #使用entrypoint标签 可以定义接入点
    entrypoint: /code/entrypoint.sh
    entrypoint:
      - php
      - -d
      - zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so
      - -d
      - memory_limit=-1
      - vendor/bin/phpunit

  lb:
    image: dockercloud/haproxy
    ports:
      - 80:80

    #extra_hosts 添加主机名的标签,就是往/etc/hosts文件中添加下面的一些记录,与Docker client的--add-host类似:
    extra_hosts:
      - "somehost:162.242.195.82"
      - "otherhost:50.31.209.229"
    
    #让Compose项目里面的容器连接到那些项目配置外部的容器(前提是外部容器中必须至少有一个容器是连接到与项目内的服务的同一个网络里面)。
    #链接到 docker-compose.yml 外部的容器,甚至并非 Compose 管理的外部容器。
    external_links:
      - redis_1
      - project_db_1:mysql
      - project_db_1:postgresql

    links:
      - web

    #指定父 cgroup 组,意味着将继承该组的资源限制。
    cgroup_parent: cgroups_1  #指定父 cgroup 组,意味着将继承该组的资源限制

    #加入指定网络,相同的服务可以在不同的网络有不同的别名。
    networks:
      - front-tier
      - back-tier

    #挂载一个目录或者一个已存在的数据卷容器格式[HOSTPATH:CONTAINERPATH:ro] #定路径可以是相对路径,使用 . 或者 .. 来指定相对目录。
    #可以宿主机的 $PWD 常量
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock    #使用绝对路径挂载数据卷
      - ~/configs:/etc/configs/:ro  # 使用用户的相对路径(~/ 表示的目录是 /home/<用户目录>/ 或者 /root/)。
      - datavolume:/var/lib/mysql   #已经存在的命名的数据卷。

    #从其它容器或者服务挂载数据卷可选的参数是 :ro或者 :rw(默认)
    volumes_from:
      - service_name
      - service_name:ro
      - container:container_name
      - container:container_name:rw

    #添加或删除容器的内核功能
    cap_add:  #指定容器的内核能力(capacity)分配。
      - ALL
    cap_drop:  #去掉 NET_ADMIN 能力可以指定为:
      - NET_ADMIN
      - SYS_ADMIN

    #设备映射列表
    devices:
      - "/dev/ttyUSB0:/dev/ttyUSB0"

    #通过命令检查容器是否健康运行
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 1m30s
      timeout: 10s
      retries: 3

    #跟主机系统共享进程命名空间。
    #打开该选项的容器之间,以及容器和宿主机系统之间可以通过进程 ID 来相互访问和操作。
    pid: "host"

    #配置容器内核参数
    sysctls:
      - net.core.somaxconn=1024
      - net.ipv4.tcp_syncookies=0
      - net.ipv4.ip_forward=1

    #指定容器的 ulimits 限制值
    #例如,指定最大进程数为 65535,指定文件句柄数为 20000(软限制,应用可以随时修改,不能超过硬限制) 和 40000(系统硬限制,只能 root 用户提高)。
    ulimits:
      nproc: 65535
      nofile:
        soft: 20000
        hard: 40000

networks:
  front-tier:
    driver: bridge
    
    #子标签aliases,这是一个用来设置服务别名的标签
      aliases:
         - alias1
  back-tier:
    driver: bridge

#放在最后
secrets:
  my_secret:
    file: ./my_secret.txt
  my_other_secret:
    external: true

Compose 模板文件支持动态读取主机的系统环境变量和当前目录下的 .env 文件中的变量。
环境变量文件中每一行必须符合格式,支持 # 开头的注释行。

# common.env: Set development environment
PROG_ENV=development
MONGO_VERSION=3.6

#例如,下面的 Compose 文件将从运行它的环境中读取变量 ${MONGO_VERSION} 的值,并写入执行的指令中。
version: "3"
services:

db:
  image: "mongo:${MONGO_VERSION}"

4. 使用案例

使用案例1:docker-compose 配合Dockerfile构建容器,采用python的flask框架与redis

#项目结构
├── app.py
├── docker-compose.yml
└── Dockerfile

###############app.py###############
#!/usr/bin/env python
#每次刷新页面,计数就会加 1。
from flask import Flask
from redis import Redis

app = Flask(__name__)
redis = Redis(host=''redis'', port=6379)

@app.route(''/'')
def hello():
    count = redis.incr(''hits'')
    return ''Hello World! 该页面已被访问 {} 次。\n''.format(count)

if __name__ == "__main__":
    app.run(host="0.0.0.0",port=8080,debug=True)


########## Docker-compose.yml ########## 
version: ''3''
services:
  web:
    #存放了dockerfile目录
    build: .
    ports:
     - "80:8080"
  #会进行自连接与网络通信关联-docker-compose的一大特色
  redis:
    image: "redis:alpine"


########## Dockerfile ########## 
FROM python:3.6-alpine
ADD . /code
WORKDIR /code
RUN pip install redis flask
RUN chown -R $USER:$USER .
CMD ["python", "app.py"]

WeiyiGeek.
访问我们构建的服务显示:
WeiyiGeek.


使用案例2:采用docker-compose构建博客镜像

#宿主机直接git clone我的blog项目
git clone https://github.com/WeiyiGeek/blog.git

#建立入口执行shell文件
$nano init.sh
#!/bin/bash
npm config set unsafe-perm true
npm config set registry https://registry.npm.taobao.org
npm install -g hexo-cli --save
npm install --save
hexo server

#建立docker-compose.yml文件、
version: "3.0"
services:
  blog:
    image: "mhart/alpine-node:latest"
    container_name: blog
    labels:
      - "com.example.author=weiyigeek"
      - "com.example.description=my blog"
      - "com.example.department=IT"
      - "com.example.lrelease=v1.0"
    ports: 
      - "80:4000"
    volumes:
      - "$PWD:/opt/blog/"
    working_dir: /opt/blog/
    entrypoint: /opt/blog/init.sh   #设置的环境变量也由此初始化到脚本之中

注意事项

  1. 如果你同时指定了 image 和 build 两个标签,那么 Compose 会构建镜像并且把镜像命名为 image 后面的那个名字。
build: ./dir
image: webapp:tag

#Dockerfile 中的 ARG 指令它可以在构建过程中指定环境变量,但是在构建成功后取消,在 docker-compose.yml 文件中也支持这样的写法:
build:
  context: .
  #与 ENV 不同的是,ARG 是允许空值的。例如:
  args:
    - buildno=1
    - password=secret
    - version
  1. YAML 的布尔值(true, false, yes, no, on, off)必须要使用引号引起来(单引号、双引号均可),否则会当成字符串解析。

  2. 如果env_file指定.env文件有变量名称 与 environment 指令冲突则以后者为准。

  3. 注意env_file标签的使用,是这里所说的环境变量是对宿主机的 Compose 而言的:

  • 如果在配置文件中有 build 操作这些变量并不会进入构建过程中,
  • 如果要在构建中使用变量还是首选前面刚讲的 arg 标签。
  1. 补充标签与docker run参数一致
configs #仅用于 Swarm mode
deploy #仅用于 Swarm mode
cpu_shares: 73
cpu_quota: 50000
cpuset: 0,1

#指定容器中运行应用的用户名
user: postgresql

#指定容器中工作目录
working_dir: /code

#指定容器中搜索域名、主机名、mac 地址等。
domainname: foo.com
hostname: foo
ipc: host
mac_address: 02:42:ac:11:65:43

#允许容器中运行一些特权命令。
privileged: true


#指定容器退出后的重启策略为始终重启。该命令对保持服务始终运行十分有效,在生产环境中推荐配置为 always 或者 unless-stopped。
restart: always

#以只读模式挂载容器的 root 文件系统,意味着不能对容器内容进行修改。
read_only: true


shm_size: 64M
#打开标准输入,可以接受外部输入。
stdin_open: true
#模拟一个伪终端。
tty: true

mem_limit: 1000000000
memswap_limit: 2000000000

使用案例3:采用docker-compose构建 MySQL / Redis / Adminer;

version: ''3.1''
services:
  db8:
    image: mysql
    container_name: mysql8.x
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: www.weiyigeek.top
      MYSQL_DATABASE: test
      MYSQL_USER: test8
      MYSQL_PASSWORD: weiyigeek.top
    volumes:
      - "/app/mysql8:/var/lib/mysql"
    ports:
      - 3306:3306
    networks:
      - database-net
  db5:
    image: mysql:5.7.29
    container_name: mysql5.x
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: www.weiyigeek.top
      MYSQL_DATABASE: test
      MYSQL_USER: test5
      MYSQL_PASSWORD: weiyigeek.top
    volumes:
      - "/app/mysql5:/var/lib/mysql"
    ports:
      - 3305:3306
    networks:
      - database-net
  redis:
    image: redis
    container_name: redis
    restart: always
    command: redis-server --requirepass weiyigeek.top
    volumes:
      - "/app/redis:/data"
    ports:
      - 6379:6379
  adminer:
    image: adminer
    container_name: MySQLManager
    restart: always
    ports:
      - 8888:8080
    networks:
      - database-net
    links:
      - db8:mysql8.x
      - db5:mysql5.7
    depends_on:
      - db8
      - db5

#新建(注意不在services中)
networks:
  database-net:
    driver: bridge

# 指定已存在的网络
# networks:
# mysql_database-net:
# external: true

注意事项:此时若还要docker容器间进行相互通讯需要进行配置防火墙信任 docker 的 ip 地址,比如:firewall-cmd --zone=trusted --add-source=172.17.0.1/16 --permanent,如果部署iptable报错请重启docker;


WeiyiGeek Blog - 为了能到远方,脚下的每一步都不能少。

本文章来源 Blog 站点(友链交换请邮我哟):

  • https://weiyigeek.top # 国内访问较慢
  • https://blog.weiyigeek.top # 更新频繁
  • https://weiyigeek.gitee.io # 国内访问快可能会有更新不及时得情况

更多学习笔记文章请关注 `WeiyiGeek` 公众账号

【点击我关注】

WeiyiGeek-公众账号

今天的关于Docker 容器学习与分享 03docker容器实战的分享已经结束,谢谢您的关注,如果想了解更多关于1.Docker容器学习之新生入门必备基础知识、167 docker docker构建nginx容器系列问题 docker registry docker run docker toolbo、2.Docker容器学习之新生入门必备基础知识、3.Docker容器学习之新手基础使用的相关知识,请在本站进行查询。

本文标签: