# Introduction

> 小虾米（QQ:509129）


# Docker 简介

## 什么是虚拟化

在计算机中，虚拟化（英语：Virtualization）是一种资源管理技术，是将计算机的各种实体资源，如服务器、网 络、内存及存储等，予以抽象、转换后呈现出来，打破实体结构间的不可切割的障碍，使用户可以比原本的组态更 好的方式来应用这些资源。这些资源的新虚拟部份是不受现有资源的架设方式，地域或物理组态所限制。一般所指 的虚拟化资源包括计算能力和资料存储。&#x20;

在实际的生产环境中，虚拟化技术主要用来解决高性能的物理硬件产能过剩和老的旧的硬件产能过低的重组重用， 透明化底层物理硬件，从而最大化的利用物理硬件 对资源充分利用&#x20;

虚拟化技术种类很多，例如：软件虚拟化、硬件虚拟化、内存虚拟化、网络虚拟化(vip)、桌面虚拟化、服务虚拟 化、虚拟机等等。

## 什么是Docker？

Docker 是一个开源项目，诞生于 2013 年初，最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推 出的 Go 语言实现。 项目后来加入了 Linux 基金会，遵从了 Apache 2.0 协议，项目代码在 GitHub 上进行维护。

![](/files/-MC_M62HEoVAFtQYYK24)

Docker 自开源后受到广泛的关注和讨论，以至于 dotCloud 公司后来都改名为 Docker Inc。Redhat 已经在其 RHEL6.5 中集中支持 Docker；Google 也在其 PaaS 产品中广泛应用。

Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器（LXC）等技术。

在 LXC 的基础上 Docker 进行了进一步的封装，让用户不需要去关心容器的管理，使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。

为什么选择Docker?&#x20;

（1）上手快。

&#x20;用户只需要几分钟，就可以把自己的程序“Docker化”。Docker依赖于“写时复制”（copy-on-write）模型，使修改 应用程序也非常迅速，可以说达到“随心所致，代码即改”的境界。&#x20;

随后，就可以创建容器来运行应用程序了。大多数Docker容器只需要不到1秒中即可启动。由于去除了管理程 序的开销，Docker容器拥有很高的性能，同时同一台宿主机中也可以运行更多的容器，使用户尽可能的充分利用 系统资源。&#x20;

（2）职责的逻辑分类&#x20;

使用Docker，开发人员只需要关心容器中运行的应用程序，而运维人员只需要关心如何管理容器。Docker设计的 目的就是要加强开发人员写代码的开发环境与应用程序要部署的生产环境一致性。从而降低那种“开发时一切正 常，肯定是运维的问题（测试环境都是正常的，上线后出了问题就归结为肯定是运维的问题）”&#x20;

（3）快速高效的开发生命周期&#x20;

Docker的目标之一就是缩短代码从开发、测试到部署、上线运行的周期，让你的应用程序具备可移植性，易于构 建，并易于协作。（通俗一点说，Docker就像一个盒子，里面可以装很多物件，如果需要这些物件的可以直接将 该大盒子拿走，而不需要从该盒子中一件件的取。）&#x20;

（4）鼓励使用面向服务的架构&#x20;

Docker还鼓励面向服务的体系结构和微服务架构。Docker推荐单个容器只运行一个应用程序或进程，这样就形成 了一个分布式的应用程序模型，在这种模型下，应用程序或者服务都可以表示为一系列内部互联的容器，从而使分 布式部署应用程序，扩展或调试应用程序都变得非常简单，同时也提高了程序的内省性。（当然，可以在一个容器 中运行多个应用程序）

## 容器与虚拟机比较

下面的图片比较了 Docker 和传统虚拟化方式的不同之处，可见容器是在操作系统层面上实现虚拟化，直接复用本 地主机的操作系统，而传统方式则是在硬件层面实现。

![](/files/-MC_M_8gQYL3ceULGWSb)

与传统的虚拟机相比，Docker优势体现为启动速度快、占用体积小。

参考：

[Docker和虚拟机的区别](https://blog.csdn.net/xiangwanpeng/article/details/78685175)

[什么是 Docker？Docker与传统的虚拟机有什么区别？](http://m.elecfans.com/article/648468.html)

## Docker 组件

### Docker服务器与客户端&#x20;

Docker是一个客户端-服务器（C/S）架构程序。Docker客户端只需要向Docker服务器或者守护进程发出请求，服 务器或者守护进程将完成所有工作并返回结果。Docker提供了一个命令行工具Docker以及一整套RESTful API。你 可以在同一台宿主机上运行Docker守护进程和客户端，也可以从本地的Docker客户端连接到运行在另一台宿主机 上的远程Docker守护进程。

![](/files/-MC_MgGfwjrSkguaDaE4)

### Docker镜像与容器

&#x20;镜像是构建Docker的基石。用户基于镜像来运行自己的容器。镜像也是Docker生命周期中的“构建”部分。镜像是基 于联合文件系统的一种层式结构，由一系列指令一步一步构建出来。例如：

&#x20;添加一个文件；&#x20;

执行一个命令；&#x20;

打开一个窗口。&#x20;

也可以将镜像当作容器的“源代码”。镜像体积很小，非常“便携”，易于分享、存储和更新。&#x20;

Docker可以帮助你构建和部署容器，你只需要把自己的应用程序或者服务打包放进容器即可。容器是基于镜像启 动起来的，容器中可以运行一个或多个进程。我们可以认为，镜像是Docker生命周期中的构建或者打包阶段，而 容器则是启动或者执行阶段。 容器基于镜像启动，一旦容器启动完成后，我们就可以登录到容器中安装自己需要 的软件或者服务。

&#x20;所以Docker容器就是：&#x20;

一个镜像格式；&#x20;

一些列标准操作；

&#x20;一个执行环境。&#x20;

Docker借鉴了标准集装箱的概念。标准集装箱将货物运往世界各地，Docker将这个模型运用到自己的设计中，唯 一不同的是：集装箱运输货物，而Docker运输软件。

&#x20;和集装箱一样，Docker在执行上述操作时，并不关心容器中到底装了什么，它不管是web服务器，还是数据 库，或者是应用程序服务器什么的。所有的容器都按照相同的方式将内容“装载”进去。

Docker也不关心你要把容器运到何方：我们可以在自己的笔记本中构建容器，上传到Registry，然后下载到 一个物理的或者虚拟的服务器来测试，在把容器部署到具体的主机中。像标准集装箱一样，Docker容器方便替 换，可以叠加，易于分发，并且尽量通用。

### Registry（注册中心）

&#x20;Docker用Registry来保存用户构建的镜像。Registry分为公共和私有两种。Docker公司运营公共的Registry叫做 Docker Hub。用户可以在Docker Hub注册账号，分享并保存自己的镜像（说明：在Docker Hub下载镜像巨慢， 可以自己构建私有的Registry）。 <https://hub.docker.com/>


# Docker 安装与启动

## Docker安装与启动

### 安装Docker Docker

官方建议在Ubuntu中安装，因为Docker是基于Ubuntu发布的，而且一般Docker出现的问题Ubuntu是最 先更新或者打补丁的。在很多版本的CentOS中是不支持更新最新的一些补丁包的。

&#x20;由于我们学习的环境都使用的是CentOS，因此这里我们将Docker安装到CentOS上。注意：这里建议安装在 CentOS7.x以上的版本，在CentOS6.x的版本中，安装前需要安装其他很多的环境而且Docker很多补丁不支持更 新。

&#x20;请直接挂载课程配套的Centos7.x镜像&#x20;

（1）yum 包更新到最新

```javascript
sudo yum update
```

（2）安装需要的软件包， yum-util 提供yum-config-manager功能，另外两个是devicemapper驱动依赖的

```
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
```

（3）设置yum源为阿里云

```
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-
ce/linux/centos/docker-ce.repo
```

（4）安装docker

```
sudo yum install docker-ce
```

（5）安装后查看docker版本

```
docker -v
```

### 设置ustc的镜像

ustc是老牌的linux镜像服务提供者了，还在遥远的ubuntu 5.04版本的时候就在用。ustc的docker镜像加速器速度 很快。ustc docker mirror的优势之一就是不需要注册，是真正的公共服务。

&#x20;<https://lug.ustc.edu.cn/wiki/mirrors/help/docker>

编辑该文件：

```
vi /etc/docker/daemon.json
```

在该文件中输入如下内容：

```javascript
{
"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"]
}
```

### Docker的启动与停止

systemctl 命令是系统服务管理器指令&#x20;

启动docker：

```
systemctl start docker
```

停止docker：

```
systemctl stop docker
```

重启docker：

```
systemctl restart docker
```

查看docker状态：

```
systemctl status docker
```

开机启动：

```
systemctl enable docker
```

查看docker概要信息

```
docker info
```

查看docker帮助文档

```
docker --help
```

## 参考：Docker 安装与镜像

[官方文档](https://docs.docker.com/)

### 安装

<https://docs.docker.com/install/linux/docker-ce/ubuntu/>

[Ubuntu18.04下Docker CE安装](https://www.jianshu.com/p/07e405c01880)

**常见错误**

IPv4forwarding is disabled.Networkingwill not work.

解决办法：

`sudo vi/etc/sysctl.conf`(Linux内核参数配置文件，可在运行时修改某些内核参数，使之永久生效)

加入`net.ipv4.ip_forward=1`

保存并退出后 执行`systemctl restart network`

#### 资料

安装也可以参考[阿里云的文档Docker CE 镜像源站](https://yq.aliyun.com/articles/110806?spm=a2c1q.8351553.0.0.11b720beQRyGTx)

[ubuntu安装docker官方文档](https://docs.docker.com/install/linux/docker-ce/ubuntu/)

#### centos 安装docker

[centos安装docker官方文档](https://docs.docker.com/install/linux/docker-ce/centos/)

## 镜像

地址：<https://hub.docker.com/>

使用阿里云的镜像加速器

1.登录注册

2.选择 容器镜像服务 =》镜像加速器 进行配置

![](/files/-LfnTK9GFgIwVZ6V629k)

想使用阿里云拉取镜像，则在镜像搜索地方搜索,复制镜像相应的公网地址，使用如下命令：

```
docker pull registry.cn-hangzhou.aliyuncs.com/lxepoo/apache-php5
```

## 资料

[Windows10下安装Docker的步骤](https://www.cnblogs.com/wyt007/p/10656813.html)

```
{
  "registry-mirrors": [
    "https://pypoas5n.mirror.aliyuncs.com"
  ],
  "experimental": true
}
```

[windows10家庭版安装docker踩坑](https://blog.csdn.net/harry5508/article/details/105132207?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.compare\&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.compare)

[Windows10 Docker 下载安装及使用 修改默认存放位置C盘 其它盘符](https://blog.csdn.net/qq_37131345/article/details/106215562)

[windows10 docker 从C盘迁移到其他盘](https://www.cnblogs.com/justblue/p/13202529.html)

```
计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
Professional
```

采用软连的方式更好&#x20;

```
cmd /c mklink /D "C:\ProgramData\Docker" "D:\developer_soft\Docker\ProgramData\Docker"
cmd /c mklink /D "C:\Program Files\Docker" "D:\developer_soft\Docker\Program Files\Docker"
cmd /c mklink /D "C:\ProgramData\DockerDesktop" "D:\developer_soft\Docker\ProgramData\DockerDesktop"
```

重装清除

[在window10上彻底卸载docker](https://www.pythonsky.cn/technical-talk/477.html)

[docker 重装提示 Exising installation is up to date 解决方法](https://blog.csdn.net/qq_35445306/article/details/106242761)

```
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Docker Desktop
```


# Docker 的运行机制

Docker是如何运行的。接下来，将从Docker的引擎与架构两个方面对Docker内部的运行与管理机制进行讲解。

* Docker的引擎
* Docker的架构

## Docker的引擎

Docker Engine（Docker引擎）是Docker的核心部分，使用的是客户端-服务器（C/S）架构模式，其主要组成部分如图所示：

![](/files/-LfnTKgkMXDmaJVtw73U)

可以看出，Docker Engine 中包含了三个核心组件（docker CLI，REST API和docker deemon），具体说明如下 ：

* **Docker CLI(command line interface）：**&#x8868;示Docker命令行接口 ，开发者可以在命令行中使用Docker相关执行与Docker守护进程进行交互，从而管理诸如image（镜像）、container（容器）、network（网络）和data volumes（数据卷）等实体。
* **REST API：**&#x8868;示应用程序API接口，开发者通过该API接口可以与Docker的守护进程进行交互，从而指示后台进行相关操作。
* **docker daemon：**&#x8868;示Docker的服务端组件，它是Docker架构中运行在后台的一个守护进程，可以接受并处理来自命令行接口（Docker CLI）及API接口（REST API）的指令，然后进行相应的后台操作。

对于开发者而言，既可以使用编写好的脚本文件通过REST API来实现与Docker进行交互，也可以直接使用Docker相关指令，通过命令行接口与Docker进行交互，而其他一些Docker应用则是通过底层API和CLI进行交互。

## Docker的架构

Docker使用C/S架构，通过Docker的具体架构，了解Docker的整个运行流程。接下来通过官方的架构图对Docker架构进行详细说明。

> Client 通过接口与Server进程通信实现容器的构建，运行和发布。client和server可以运行在同一台集群，也可以通过跨主机实现远程通信。

![](/files/-LfnTKgmKhK87Xw92fT4)

从图上可以看出，Docker架构主要包括Client、DOCKER\_HOST和Register三部分，这三部分的具体说明如下：

### **1.Client（客户端）**

Client即Docker客户端，也就是**Docker CLI（**&#x44;ocker命令行接&#x53E3;**）。**&#x5F00;发者通过和客户端使用Docker的相关指令与 Docker守护进程进行交互，从而进行Docker镜像的创建、拉取和运行等操作。

### **2.DOCKER\_HOST(Docker主机)**

DOCKER\_HOST即Docker内部引擎运行的主机，主要指Docker daemon(Docker守护进程)。可以通过守护进程与客户端还有Docker的镜像仓库（Registry）进行交互，从而管理Images（镜像）和Containers(容器)等。

### **3.Registry（注册中心）**

Registry即Docker注册中心，实质就是Docker的**镜像仓库，**&#x9ED8;认使用的是Docker官方远程注册中心Docker Hub，也可以使用开发者搭建的本地仓库。Registory中包含了大量的镜像，这些镜像可以是官方基础镜像，也可以是其他开发者上传的镜像 。

### **其他**

我们在实际使用Docker时，除了会涉及以上3个主要部分外，还会涉及很多Docker Objects（Docker 对象），例如：Image(镜像)、Containers（容器）、Networks（网络）、Volumes（数据卷）、Plugin（插件）等。其中常见的两个对象Image(镜像)和Containers（容器）。

**Image(镜像)**

Docker镜像就是一个只读模板，包括了一些创建Docker容器的操作指令。通常情况下，一个Docker镜像是基于另一个基础镜像创建的，并且新创建 镜像会额外包含一些功能配置。例如：开发者可以依赖一个Ubuntu的基础镜像创建一个新镜像，并可以在新镜像中安装Apache等软件或其他应用程序。

**Containers（容器）**

Docker容器属于镜像的一个可运行实例（镜像与容器的关系其实与 编程语言中的类与对象相似），开发者可以通过 API接口或者CLI命令接口来 创建、运行、停止、移动、删除一个容器，也可以将一个容器连接到一个或多个网络中，将数据存储与容器进行关联。

参考资料：

[几张图帮你理解 docker 基本原理及快速入门](https://www.cnblogs.com/SzeCheng/p/6822905.html)


# Docker 的底层技术

> 简单说明。

Docker使用了一系列的底层技术来充分发挥其技术特色，这些底层技术包括Namespaces、Control groups、Union file systems 和 Container format等，其具体含义如下：

### 1.Namespaces （名称空间）

Docker使用名称空间来为容器提供隔离的工作空间。当一个容器运行时，Docker就会为该容器创建一系列的名称空间，并且名称空间提供一层隔离。当一个容器都运行在相对隔离的环境下，对其他名称空间是相对受限的。

### 2.Control groups（控制组）

基于Linux系统的Docker引擎也依赖另一项叫Control groups（cgroups，控制组）的技术。控制组可以对程序进行资源限定，并允许Docker引擎在容器间进行硬件资源共享以及随时进行限制和约束，例如：开发者可以限制某种特定容器 可用内存。

### 3.Union file systems （联合文件系统）

联合文件系统（UnionFS）是一种分层、轻量级并且高性能的文件系统，它支持将文件系统的修改作为一次提交来一层层地叠加，同时可以将不同的目录挂载到同一个虚拟文件系统下。不同Docker容器可以共享一些基础的文件系统层，与自己独有的改动层一起使用，可以大大提高存储效率。Docker目前支持的联合文件系统包括AUFS、btrfs、vfs和DeviceMapper。

### 4.Container format （容器格式）

Docker引擎将命名空间、控制组和联合文件系统组合成一个叫容器格式的整体。当前默认的容器格式是libcontainer，未来Docker可能ui通过与其他技术（如BSD Jails 或者 Solaris Zones）的集成使用来开发其他的容器格式。

## 参考资料

[Docker 介绍以及其相关术语、底层原理和技术](https://blog.csdn.net/zxygww/article/details/53709106)

[Docker 核心技术与实现原理](http://dockone.io/article/2941)


# Portainer详解(Web端管理平台)

[官方网站](https://portainer.io/)

[官方安装教程](https://portainer.io/install.html)

创建一下数据卷,启动即可

```
$ docker volume create portainer_data
$ docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
```

**开放Docker网络管理端口**

```
$ vi /etc/sysconfig/docker
```

在配置文件结尾添加开放Docker开发2375端口的参数

```
OPTIONS='-Htcp://0.0.0.0:2375 -H unix://var/run/docker'
```

资料

[官方文档地址](https://portainer.readthedocs.io/en/latest/deployment.html)

## window安装

参考：

<https://www.portainer.io/installation/>

```
$ docker volume create portainer_data
$ docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart always -v \\.\pipe\docker_engine:\\.\pipe\docker_engine -v portainer_data:C:\data portainer/portainer
```


# 资料

[Docker(七)----搭建Portainer可视化界面](https://blog.csdn.net/u011781521/article/details/80469804)

[Portainer实战原](https://my.oschina.net/guol/blog/2209685)

[Portainer documentation](https://portainer.readthedocs.io/en/stable/)

[\[容器管理\]使用Portainer管理Docker容器](https://www.jianshu.com/p/aff1512746b4)


# Docker 的使用


# Docker 客户端指令

[docker命令官方文档](https://docs.docker.com/engine/reference/commandline/cli/)


# Docker 操作指令

下面表中列出了Docker操作镜像与容器的一些常用指令。

|     **指令**     |  **说明** |
| :------------: | :-----: |
|  docker images |   列出镜像  |
|  docker search |   搜索镜像  |
|   docker pull  |   拉取镜像  |
|  docker build  |   构造镜像  |
|   docker rmi   |   删除镜像  |
|   docker run   | 创建并启动容器 |
|    docker ps   |   列出容器  |
|   docker exec  |   执行容器  |
|   docker stop  |   停止容器  |
|  docker start  |   启动容器  |
|  docker pause  |   暂停容器  |
| docker unpause |   恢复容器  |
|    docker rm   |   删除容器  |

## 1.列出镜像

通过docker images指令可以查看本地镜像列表中已经有的镜像，使用方法如下：

```
$ docker images
```

![](/files/-LfnTK3B6XO9B07FXmHr)

从图中可以看出，系统终端将本地镜像列出来，分5列进行展示，每一列的具体含义如下：

* REPOSITORY：镜像名称
* TAG：镜像参数，类似于版本号，默认为latest
* IMAGE ID：镜像ID，是唯一值。此处看到的是一个长度为12的字符串，实际上它是64位完整镜像ID的缩写形式。
* CREATED：距今创建镜像的时间。
* SIZE：镜像大小。

## 2.搜索镜像

想知道在Docker Hub中包含了哪些镜像，除了可以登录Docker Hub（<https://hub.docker.com/explore/>），在官网中心进行查看，还可以直接在Docker客户端进行查询。例如想要查询Ubuntu镜像，可以使用如下指令：

```
$ docker search ubuntu
```

执行上述命令后，系统终端就会将搜索有关Ubuntu的镜像展示出来.

![](/files/-LfnTK3Dkzt1TwGQB0QN)

系统终端分5列将搜索到的Ubuntu相关的镜像列举出来:

* Name：表示进项的名称，这里有两种格式的名称，其中不带"/"的表示官方镜像，而带有"/"的表示其他用户的公开镜像。公开镜像"/"前面hi用户在Docker Hub上的用户名（唯一），后面是对应的镜像名，除了从镜像名称上可以区分官方镜像与用户镜像，还可以通过第四列OFFICIAL声明中看出（改列内容为OK表示官方镜像）。
* DESCRIPTION：表示镜像的描述，这里只显示了一小部分。
* STARS：表示镜像 收藏数，用户可以在Docker Hub上对镜像进行收藏，一般可以通过该数字反映出该镜像的受欢迎程度。
* OFFICIAL：表示是否为官方镜像。
* AUTOMATED：表示是否自动构建镜像.例如：用户可以将自己Docker Hub绑定到如Github上，当代码提交更新后，自动构建镜像。

## 3.拉取镜像

通过`docker pull`可以拉取仓库镜像到本地（默认都是拉取Docker Hub仓库镜像，也可以指定"IP+端口"拉取某个Docker机器上的私有仓库镜像），具体使用是如下：

```
$ docker pull ubuntu
```

执行上述指令后，Docker会自动从Docker Hub上下载最新版本的Ubuntu到本地，当然也可以使用以下指令拉取指定版本的镜像到本地，具体执行如下：

```
$ docker pull ubuntu:14.04
```

## 4.构建镜像

除了可以通过`docker pull`指令从仓库拉取镜像外，还可以通过`docker build`指令构建Docker镜像，通常情况都是通过Dockerfile文件来构建镜像的。

（1）.在Dockerfile文件所在目录后，可以使用docker build指令进行镜像构建，具体指令如下：

```
$ cd workspace/dockerspace/
$ docker build -t hellodocker .
```

进入Dockerfile所在目录，通过点"."读取当前应用上下文中的Dockerfile进行构建。

（2）.在其他目录构建镜像

除了可以在Dockerfile文件所在目录构建镜像外，还可以在指定目录下进行镜像构建，如在home目录下读取Dockerfile文件所在目录的指令如下：

```
$ docker build -t hellodocker /home/revin/workspace/dockerspace/.
```

构建完成后就可以通过`docker images`指令查看镜像是否创建成功。

## 5.删除镜像

当本地存放过多不需要的镜像时，可以通过`docker rmi`指令将其删除。在删除镜像时,需要指定镜像名称或镜像ID。删除镜像的使用方式如下：

```
$ docker rmi -f hellodocker1 hellodocker2
```

上述指令中，`docker rmi` 表示删除镜像，-f 表示进行强制删除，而hellodocker1和hellodocker2分别表示乣删除的镜像名称，这里同时删除两个镜像。除了根据名称删除镜像外，还可以根据镜像ID来删除。

> 注意：在进行镜像删除操作时，如果通过镜像ID进行镜像删除，那么由该镜像创建的容器必须提前删除或停止。另外，在通过镜像名称操作镜像时,如果操作的不是默认的lastest镜像，必须爱镜像名称后面指定镜像标签tag参数来确保唯一性。

## 6.创建并启动容器

Docker镜像主要用于创建容器，可以使用`Docker run`指令创建并启动容器，具体使用方式如下：

```
$ docker run -d -p 5000:80 --name test hellodocker
```

* `docker run`: 表示创建并启动一个容器，而后面的hellodocker就表示要启动运行的镜像名称。
* `-d`：表示容器启动时在后台运行。
* `-p 5000::80`：表示将容器内暴露的80端口映射到宿主机指定的5000端口，也可以将`-p 5000::80`更改为`-P`来映射主机的随机端口（注意p字母 大小写）。
* `--name test`：表示为创建后的容器指定名称为test，如果有该参数配置，则生成的容器会设置一个随机名称。

> docker run 命令是Docker操作红较为复杂的一个，它可以携带多个参数，我们可以通过docker run --help指令进行查看，其中有些参数如-e、-v和-w等都可以在Dockerfile文件中预先声明。
>
> 注意：由于容器的名称具有唯一性，因此创建容器时若指定了容器名称，则后续创建的容器名称不得与此容器名称相同，否则需要重新命名或者将之前的容器删除。
>
> 参数补充说明([Docker run 命令](http://www.runoob.com/docker/docker-run-command.html))：
>
> * **-a stdin:**&#x6307;定标准输入输出内容类型，可选 STDIN/STDOUT/STDERR 三项；
> * **-d:**&#x540E;台运行容器，并返回容器ID；
> * **-i:**&#x4EE5;交互模式运行容器，通常与 -t 同时使用；
> * **-p:**&#x7AEF;口映射，格式为：主机(宿主)端口:容器端口
> * **-t:**&#x4E3A;容器重新分配一个伪输入终端，通常与 -i 同时使用；
> * **--name="nginx-lb":**&#x4E3A;容器指定一个名称；
> * **--dns 8.8.8.8:**&#x6307;定容器使用的DNS服务器，默认和宿主一致；
> * **--dns-search example.com:**&#x6307;定容器DNS搜索域名，默认和宿主一致；
> * **-h "mars":**&#x6307;定容器的hostname；
> * **-e username="ritchie":**&#x8BBE;置环境变量；
> * **--env-file=\[]:**&#x4ECE;指定文件读入环境变量；
> * **--cpuset="0-2" or --cpuset="0,1,2":**&#x7ED1;定容器到指定CPU运行；
> * **-m :**&#x8BBE;置容器使用内存最大值；
> * **--net="bridge":**&#x6307;定容器的网络连接类型，支持 bridge/host/none/container:四种类型；
> * **--link=\[]:**&#x6DFB;加链接到另一个容器；
> * **--expose=\[]:**&#x5F00;放一个端口或一组端口；
>
> 示例
>
> 使用镜像 nginx:latest，以后台模式启动一个容器,将容器的 80 端口映射到主机的 80 端口,主机的目录 /data 映射到容器的 /data。
>
> ```
> docker run -p 80:80 -v /data:/data -d nginx:latest
> ```

## 7.列出容器

生成容器后，可以通过`docker ps`指令查看当前运行的所有容器，具体使用方法如下：

```
$ docker ps
```

系统终端通过7列对当前的正在运行的一个容器进行了展示，具体含义如下：

* CONTAINER ID：表示生成的容器ID。
* IMAGE：表示生成该容器的镜像名称。
* COMMAND：表示启动容器时运行的命令，Docker要求在启动容器时必须运行一个命令。
* CREATED：表示容器创建的时间。
* STATUS：表示容器运行状态，例如Up表示运行中，Exited表示已停止。
* PORTS：表示容器内部暴露的端口映射到主机的端口
* NAMES：表示生成容器的名称，由Docker引擎自动生成，可以像上述示例中`--name`参数指定生成容器名称。

> 可以通过docker ps --help指令对ps指令详细的信息参数进行查看。

## 8.执行命令

当生成容器后，客户端可以通过`docker exec`指令与运行的容器进行通信，在通信时需要指定容器ID或名称，具体方式如下：

```
$ docker exec f0c9a8b1e2c4 ls -l
```

执行上述指令后，就会将该容器中的所有文件都展示出来。

## 9.停止容器

当不需要容器运行时，可以使用docker stop指令停止指定的容器，在停止容器时，需要指定容器ID名称，具体使用方式如下：

```
$ docker stop f0c9a8b1e2c4
```

使用上述指令停止容器时,会有所略微延迟，成功后会返回该容器ID，如果想要查看该容器，则可以通过上面学习的`docker ps -a` 进行查看。

也可以过`docker kill`指令立即杀死运行的容器进程，使用该指令也需要指定容器ID或名称，具体使用方式如下：

```
$ docker kill f0c9a8b1e2c4
```

使用上述命令杀死运行的容器时，几乎是瞬间完成，执行后便会返回该容器的ID。

## 10.启动容器

容器停止后，如果需要重新访问该容器中的程序，则需要重新启动该容器。启动容器可以通过`docker start`指令来完成，具体使用方式如下：

```
$ docker start f0c9a8b1e2c4
```

还可以使用`docker restart` 指令重启容器。

> 注意：`docker restart`指令即可以重新启动已经停止的容器，也可以重启当前正在运行的容器，具体使用方式如下：

```
$ docker restart f0c9a8b1e2c4
```

## 11.暂停容器

```
docker pause [OPTIONS] CONTAINER [CONTAINER...]
```

暂停容器中所有的进程。

## 12.恢复容器

```
docker unpause [OPTIONS] CONTAINER [CONTAINER...]
```

恢复容器中所有的进程。

> [Docker pause/unpause 命令](http://www.runoob.com/docker/docker-pause-unpause-command.html)

## 13.删除容器

当不需要使用容器时，则可以使用`docker rm`指令删除已停止的容器，具体使用方式如下：

```
$ docker rm f0c9a8b1e2c4
```

> 注意：上面的指令只能删除已经停止运行的容器，而不能删除正在运行的容器。如果想要删除正在运行容器，则需要添加`-f`参数强制删除，具体使用方式如下：

```
$ docker rm -f f0c9a8b1e2c4
```

当需要删除的容器过多时，如果还一个个删除太麻烦，可以使用如下指令将全部容器删除：

```
$ docker rm -f $(docker ps -aq)
```

上述指令中，首先会通过`$(docker ps -aq)`获取所有容器的ID，然后通过`docker rm -f`强制删除。

如果开发者有自己特殊的删除需求，可以根据前面`docker ps`指令进行组装来获取需要删除的容器ID。


# Docker 管理指令

|     **管理指令**     |     **说明**     |
| :--------------: | :------------: |
| docker container |     用于管理容器     |
|   docker image   |     用于管理镜像     |
|  docker network  |  用于管理Docker网络  |
|    docker node   |  用于管理Swarm集群节点 |
|   docker plugin  |     用于管理插件     |
|   docker secret  |  用于管理Docker机密  |
|  docker service  | 用于管理Docker一些服务 |
|   docker stack   |  用于管理Docker堆栈  |
|   docker swarm   |    用于管理Swarm   |
|   docker system  |   用于管理Docker   |
|   docker volume  |     用于管理数据卷    |


# 常用命令

## 镜像相关命令

### 查看镜像&#x20;

```
docker images
```

REPOSITORY：镜像名称&#x20;

TAG：镜像标签

&#x20;IMAGE ID：镜像ID&#x20;

CREATED：镜像的创建日期（不是获取该镜像的日期）&#x20;

SIZE：镜像大小 这些镜像都是存储在Docker宿主机的`/var/lib/docker`目录下

### 搜索镜像&#x20;

如果你需要从网络中查找需要的镜像，可以通过以下命令搜索

```
docker search 镜像名称
```

NAME：仓库名称&#x20;

DESCRIPTION：镜像描述&#x20;

STARS：用户评价，反应一个镜像的受欢迎程度&#x20;

OFFICIAL：是否官方&#x20;

AUTOMATED：自动构建，表示该镜像由Docker Hub自动构建流程创建的

### 拉取镜像&#x20;

拉取镜像就是从中央仓库中下载镜像到本地

```
docker pull 镜像名称
```

例如，我要下载centos7镜像

```
docker pull centos:7
```

### 删除镜像&#x20;

按镜像ID删除镜像

```
docker rmi 镜像ID
```

删除所有镜像

```
docker rmi `docker images -q`
```

## 容器相关命令

### 查看容器&#x20;

查看正在运行的容器

```
docker ps
```

查看所有容器

```
docker ps –a
```

查看最后一次运行的容器

```
docker ps –l
```

查看停止的容器

```
docker ps -f status=exited
```

### 创建与启动容器&#x20;

创建容器常用的参数说明：&#x20;

创建容器命令：`docker run` &#x20;

-i：表示运行容器

&#x20;-t：表示容器启动后会进入其命令行。加入这两个参数后，容器创建就能登录进去。即分配一个伪终端。 --name :为创建的容器命名。

&#x20;-v：表示目录映射关系（前者是宿主机目录，后者是映射到宿主机上的目录），可以使用多个－v做多个目录或文 件映射。注意：最好做目录映射，在宿主机上做修改，然后共享到容器上。&#x20;

-d：在run后面加上-d参数,则会创建一个守护式容器在后台运行（这样创建容器后不会自动登录容器，如果只加-i -t 两个参数，创建后就会自动进去容器）。&#x20;

-p：表示端口映射，前者是宿主机端口，后者是容器内的映射端口。可以使用多个-p做多个端口映射&#x20;

（1）交互式方式创建容器

```
docker run -it --name=容器名称 镜像名称:标签 /bin/bash
```

这时我们通过ps命令查看，发现可以看到启动的容器，状态为启动状态

退出当前容器

```
exit
```

（2）守护式方式创建容器：

```
docker run -di --name=容器名称 镜像名称:标签
```

登录守护式容器方式：

```
docker exec -it 容器名称 (或者容器ID) /bin/bash
```

### 停止与启动容器

停止容器：

```
docker stop 容器名称（或者容器ID）
```

启动容器：

```
docker start 容器名称（或者容器ID）
```

### 文件拷贝&#x20;

如果我们需要将文件拷贝到容器内可以使用cp命令

```
docker cp 需要拷贝的文件或目录 容器名称:容器目录
```

也可以将文件从容器内拷贝出来

```
docker cp 容器名称:容器目录 需要拷贝的文件或目录
```

### 目录挂载

我们可以在创建容器的时候，将宿主机的目录与容器内的目录进行映射，这样我们就可以通过修改宿主机某个目录 的文件从而去影响容器。 创建容器 添加-v参数 后边为 宿主机目录:容器目录，例如：

```
docker run -di -v /usr/local/myhtml:/usr/local/myhtml --name=mycentos3 centos:7
```

如果你共享的是多级的目录，可能会出现权限不足的提示。&#x20;

这是因为CentOS7中的安全模块selinux把权限禁掉了，我们需要添加参数 --privileged=true 来解决挂载的目录没 有权限的问题

### 查看容器IP地址

我们可以通过以下命令查看容器运行的各种数据

```
docker inspect 容器名称（容器ID）
```

也可以直接执行下面的命令直接输出IP地址

```
docker inspect --format='{{.NetworkSettings.IPAddress}}' 容器名称（容器ID）
```

### 删除容器&#x20;

删除指定的容器：

```
docker rm 容器名称（容器ID）
```


# Dockerfile


# 基本结构与常用指令

## 什么是Dockerfile

Dockerfile是由一系列命令和参数构成的脚本，这些命令应用于基础镜像并最终创建一个新的镜像。

&#x20;1、对于开发人员：可以为开发团队提供一个完全一致的开发环境；&#x20;

2、对于测试人员：可以直接拿开发时所构建 的镜像或者通过Dockerfile文件构建一个新的镜像开始工作了；&#x20;

3、对于运维人员：在部署时，可以实现应用的无 缝移植。

## 常用命令

| 命令                                   | 作用                                  |
| ------------------------------------ | ----------------------------------- |
| FROM image\_name:tag                 | 定义了使用哪个基础镜像启动构建流程                   |
| MAINTAINER user\_name                | 声明镜像的创建者                            |
| ENV key value                        | 设置环境变量 (可以写多条)                      |
| RUN command                          | 是Dockerfile的核心部分(可以写多条)             |
| ADD source\_dir/file dest\_dir/file  | 将宿主机的文件复制到容器内，如果是一个压缩文件，将会在复制后自 动解压 |
| COPY source\_dir/file dest\_dir/file | 和ADD相似，但是如果有压缩文件并不能解压               |
| WORKDIR path\_dir                    | 设置工作目录                              |

## 使用脚本创建镜像

步骤：&#x20;

（1）创建目录

```
mkdir –p /usr/local/dockerjdk8
```

（2）下载jdk-8u171-linux-x64.tar.gz并上传到服务器（虚拟机）中的/usr/local/dockerjdk8目录&#x20;

3）创建文件Dockerfile vi Dockerfile

```
#依赖镜像名称和ID
FROM centos:7
#指定镜像创建者信息
MAINTAINER ITCAST
#切换工作目录
WORKDIR /usr
RUN mkdir /usr/local/java
#ADD 是相对路径jar,把java添加到容器中
ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH
```

（4）执行命令构建镜像

```
docker build -t='jdk1.8' .
```

注意后边的空格和点，不要省略&#x20;

（5）查看镜像是否建立完成

```
docker images
```

## 资料

[Dockerfile命令详解（超全版本）](https://www.cnblogs.com/dazhoushuoceshi/p/7066041.html)

### **示例**

```
FROM centos:latest
RUN yum -y install httpd  
RUN  systemctl enable httpd.service 
EXPOSE 80
CMD /usr/sbin/init
```

**构建镜像**

```
docker build -t centos:httpd .  (这里有个点，很重要。代表当前文件夹)
```

当然也可以指定Dockerfile

```
docker build -f /path/to/a/Dockerfile.
```

通过docker images可以看到出现了一个新镜像叫做centos只不过标签变成了httpd

**启用容器**

```
docker run --privileged -d -p 8080:80 --name myhttpd centos:httpd
```

> \--privileged 参数，给容器加特权,否则交互式方式进入容器无法操作一些譬如修改内核、修改系统参数、甚至启动服务等
>
> <https://docs.docker.com/engine/reference/commandline/run/#capture-container-id-cidfile>
>
> 资料
>
> 看github上的一个 问题提交
>
> <https://github.com/moby/moby/issues/7459>
>
> 以及redhat上的一个参考文档
>
> <https://developers.redhat.com/blog/2014/05/05/running-systemd-within-docker-container/>

### **示例java环境**

1、宿主机下载JDK1.8，解压到在/usr/local/jdk1.8.0\_121

2.Dockerfile

```
FROM centos:latest
COPY jdk1.8 /usr/local/jdk1.8.0_121
ENV JAVA_HOME=/usr/local/jdk1.8.0_121
ENV PATH $JAVA_HOME/bin:$PATH
ENV CLASSPATH .:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
CMD /usr/sbin/init
```

3.构建镜像

```
docker build -t centos:jdk1.8
```

ENV 命令参考：<https://docs.docker.com/engine/reference/builder/#env>


# 应用部署=初级

## MySQL部署&#x20;

（1）拉取mysql镜像

```
docker pull centos/mysql-57-centos7
```

（2）创建容器

```
docker run -di --name=tensquare_mysql -p 33306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql
```

-p 代表端口映射，格式为 宿主机映射端口:容器运行端口&#x20;

-e 代表添加环境变量 MYSQL\_ROOT\_PASSWORD 是root用户的登陆密码&#x20;

（3）远程登录mysql&#x20;

连接宿主机的IP ,指定端口为33306

## tomcat部署

（1）拉取镜像

```
docker pull tomcat:7-jre7
```

（2）创建容器&#x20;

创建容器 -p表示地址映射

```
docker run -di --name=mytomcat -p 9000:8080
-v /usr/local/webapps:/usr/local/tomcat/webapps tomcat:7-jre7
```

## Nginx部署

（1）拉取镜像

```
docker pull nginx 
```

（2）创建Nginx容器

```
docker run -di --name=mynginx -p 80:80 nginx
```

## Redis部署&#x20;

（1）拉取镜像

```
docker pull redis
```

&#x20;（2）创建容器

```
docker run -di --name=myredis -p 6379:6379 redis
```


# Docker 数据卷（volume）

资料

[Docker容器学习梳理 - Volume数据卷使用](https://www.cnblogs.com/kevingrace/p/6238195.html)

[Docker容器的数据卷（data volume），数据卷容器，数据卷的备份和还原。](https://www.cnblogs.com/yaowen/p/8431710.html)

volume是存在于一个或多个容器中的特定文件或文件夹，这个目录以独立于联合文件系统的形式在宿主机中存在，并为数据库共享与持久化提供便利．

## 使用

举例

Portainer的基本使用时

```
$ docker volume create portainer_data
$ docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
```

首先：首选创建了一个数据卷

默认存在宿主机器中/var/lib/docker/volumes/目录，创建一个portainer\_data的目录，并将volume中的内容存储在名为 \_data的目录下.

```
/var/lib/docker/volumes/portainer_data
```

其次：

启动的时候通过挂在的方式使用-v参数进行挂在．平时开发当中多个挂在多个，也可以使用自己的目录进行挂载／

也可以通过docker volume inspect 命令获取该volume包括在其宿主机中改文件夹的位置等信息．

```
$ docker volume inspect portainer_data
[
    {
        "CreatedAt": "2018-08-13T09:55:43+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/portainer_data/_data",
        "Name": "portainer_data",
        "Options": {},
        "Scope": "local"
    }
]
```


# 迁移与备份

### 容器保存为镜像&#x20;

我们可以通过以下命令将容器保存为镜像

```
 docker commit mynginx mynginx_i 
```

### 镜像备份

我们可以通过以下命令将镜像保存为tar 文件&#x20;

```
docker save -o mynginx.tar mynginx_i 
```

## 镜像恢复与迁移

首先我们先删除掉mynginx\_img镜像 然后执行此命令进行恢复

```
docker load -i mynginx.tar
```

&#x20;-i 输入的文件&#x20;

执行后再次查看镜像，可以看到镜像已经恢复


# Docker私有仓库

## 私有仓库搭建与配置&#x20;

（1）拉取私有仓库镜像（此步省略）&#x20;

```
docker pull registry
```

&#x20;（2）启动私有仓库容器

```
 docker run -di --name=registry -p 5000:5000 registry
```

（3）打开浏览器 输入地址<http://192.168.40.111:5000/v2/\\_catalog看到> {"repositories":\[]} 表示私有仓库 搭建成功并且内容为空

（4）修改daemon.json

```
vi /etc/docker/daemon.json
```

添加以下内容，保存退出。

```
{"insecure-registries":["192.168.184.141:5000"]}
```

此步用于让 docker信任私有仓库地址&#x20;

（5）重启docker 服务

```
systemctl restart docker
```

## 镜像上传至私有仓库

（1）标记此镜像为私有仓库的镜像&#x20;

```
docker tag jdk1.8 192.168.40.111:5000/jdk1.8 
```

（2）再次启动私服容器

```
 docker start registry
```

&#x20;（3）上传标记的镜像&#x20;

```
docker push 192.168.40.111:5000/jdk1.8
```


# Mysql 集群


# 常见 MySQL 集群方案

## 一、常见 MySQL 集群方案

* Repliaction 集群方案
* PXC 集群方案（ Percona XtraDB Cluster

两种集群方案特性如下图：

![](/files/-LfnTL36aSfGJrFtUx_6)

## 二、PXC方案 和 Replication方案对比

**1. 先看看 PXC方案**

![](/files/-LfnTL38iV6z5E8b_7ob)

很明显 PXC方案在任何一个节点写入的数据都会同步到其他节点，数据**双向同步**的（在任何节点上都可以同时读写）。

**2. Replication 集群方案：**

![](/files/-LfnTL3Aa6LZwm89yAdt)

Replication方案只能在Master数据库进行写操作，在Slave数据库进行读操作。如果在Slave数据库中写入数据，Master数据库是不能知道的（**单向同步**的）。

**3. PXC 数据的强一致性**

PXC 采用同步复制，事务在所有集群节点要么同时提交，要么不提交。\
Replication 采用异步复制，无法保证数据的一致性。

* 下面看看 PXC写入操作：

![](/files/-LfnTL3ClPRnvmbgk0lv)

当一个写入请求到达PXC集群中的一个 mysql（node1数据库） 数据库时，node1数据库会将**该写入请求同步给集群中的其他所有数据库，等待所有数据库都成功提交事务后**，node1节点才会将写入成功的结果告诉给 node1的客户端。

> PXC 的强一致性对保存高价值数据时特别重要。

* 在看Replication集群写入操作：

![](/files/-LfnTL3EplrRKYF6IvBO)

当一个写入请求到达 Master数据库时，Master数据库执行写入操作，然后 Master 向客户端返回写入成功，**同时异步的复制写入操作给 Slave数据库，如果异步复制时出现问题，从数据库将无法执行写入操作，而客户端得到的是写入成功。**&#x8FD9;也是**弱一致性**的体现。


# PXC集群

[docker swarm使用keepalived+haproxy搭建基于percona-xtradb-cluster方案的高可用mysql集群](https://www.cnblogs.com/dowi/p/10309418.html)


# 1、PXC 集群安装

## 一、安装 PXC 镜像

PXC集群比较特殊，需要安装在 linux 或 Docker 之上。这里使用 Docker进行安装！

Docker的镜像仓库中包含了 PXC数据库的官方镜像，

地址：<https://hub.docker.com/r/percona/percona-xtradb-cluster/>

安装PXC镜像有两种方式：

* 下载镜像方式：`docker pull percona/percona-xtradb-cluster`
* 导入本地镜像方式：`docker load < 路径/pxc.tar.gz`

> 由于pxc的镜像名很长，可以使用以下方式
>
> ```
> $ docker images
> $ docker tag docker.io/percona/percona-xtradb-cluster pxc
> $ docker rmi docker.io/percona/percona-xtradb-cluster
> ```

## 二、创建内部网络

> 出于安全考虑，创建出来的 PXC集群不要直接对接Docker以外的网络，因此要给PXC集群实例创建 Docker内部网络。Docker内部网段外部无法直接访问，我们可通过 docker端口映射技术将端口对外开发。

处于安全考虑，需要给PXC集群实例创建 Docker内部网络( 内部默认网段为 172.17.0.XX )：

* `docker network create 网络名` - 创建docker网络
* `docker network inspect 网络名` -  查看docker某网络详细信息
* `docker network rm 网络名` - 删除docker网络

示例

```
docker network create –subnet=172.18.0.0/24 net1
docker network inspect net1 
docker network rm net1
```

## 三、创建 Docker卷 <a href="#san-chuang-jian-docker-juan" id="san-chuang-jian-docker-juan"></a>

一旦创建出docker容器，尽量不要在容器里保存业务数据，将业务数据存储到我们的宿主机上，通常我们通过 docker的目录映射机制（把宿主机上的一个目录映射到容器内），由于业务数据都在宿主机上，即使docker容器出现故障，删除故障 docker容器，重启启动一个新的容器，把业务数据目录映射到新的容器内即可。

但是PXC集群技术比较特殊，如果为PXC集群使用了docker的目录映射技术，PXC会闪退，因此要采用另外一种目录映射技术，即使用 docker卷。

> docker卷的常用操作：
>
> * `docker volume create –name v1`
> * docker inspect v1 - 查看卷的信息，知道卷在哪。
> * `docker volume rm v1`

创建的卷v1 是可以直接在宿主机上看到目录的。将这个卷再映射给容器，此时启动容器，这样PXC容器启动就能将数据映射到卷中，我们通过宿主机也能看到映射出来的数据。

## 四、创建PXC容器 <a href="#si-chuang-jian-pxc-rong-qi" id="si-chuang-jian-pxc-rong-qi"></a>

只需要向PXC镜像传入运行参数就能创建出PXC容器。

> 创建PXC 命令如下：
>
> docker run -d -p 3306:3306\
> -v v1:/var/lib/mysql\
> -e MYSQL\_ROOT\_PASSWORD=abc123456\
> -e CLUSTER\_NAME=PXC\
> -e XTRABACKUP\_PASSWORD=abc123456\
> –privileged –name=node1 –net=net1 –ip 172.18.0.2 pxc\
> 命令解释：\
> -d 代表后台运行\
> -v 表示 v1卷映射到docker的mysql中，mysql路径为 /var/lib/mysql\
> MYSQL\_ROOT\_PASSWORD=abc123456 表示mysql 的密码，用户名默认为root\
> CLUSTER\_NAME=PXC 表示集群的名字\
> XTRABACKUP\_PASSWORD=abc123456 集群之间同步的密码\
> –privileged 为权限\
> –name ：给创建出来的容器起一个名字\
> –net ： 容器分到的内部网段\
> –ip : 容器分到的 ip地址\
> pxc 为镜像名

## 五、实战

**假设我们要创建3个数据库的集群**

内部网

```
$ docker network create –subnet=172.18.0.0/24 net1
```

docker卷

```
$ docker volume create --name v1
$ docker volume create --name v2
$ docker volume create --name v3
```

启动容器

```
/** 
* 集群中数据库端口映射不一样、docker卷不一样、
* 集群中各个容器名不一样、ip地址不一样
* 注意修改这四个地方和 创建其他容器时添加：-e CLUSTER_JOIN=node1。
*/
$ docker run -d -p 3306:3306 -v v1:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 --privileged --name=node1 --net=net1 --ip 172.18.0.2 pxc
// 多了一个加入集群的命令
$ docker run -d -p 3307:3306 -v v2:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 --privileged --name=node2 --net=net1 --ip 172.18.0.3 pxc 

$ docker run -d -p 3308:3306 -v v3:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 --privileged --name=node3 --net=net1 --ip 172.18.0.4 pxc
```

**切记：**

容器的创建是很快的，但是数据库创建比较慢（2分钟以上），**一定要确保第一个容器的mysql 初始化好了在创建其他容器**，其他容器需要集群到第一个容器的mysql上。可以通过mysql客户端连接来判断是否初始化好了。

数据库客户端连接时，主机为公网ip，端口为映射到宿主机上的端口，用户名root，密码为在 run容器时所指定的那个。

此时通过 `docker ps -a` 查看后台运行的容器即可。

**查看日志：**

```
docker logs -f [Container Id]
```

或者

```
docker logs -f [Container Name]
```


# 2、PXC 集群负载均衡

## 数据库负载均衡的必要性

虽然搭建了集群，但是不使用数据库负载均衡，单节点处理所有请求，负载高，性能差。

![](/files/-LfnTL56B4CTkOrQp7bV)

使用Haproxy 做负载均衡，请求被均匀分发给每个节点，单节点负载低，性能好。

![](/files/-LfnTL58UxDXpCf_9s14)

## 负载均衡中间件对比

![](/files/-LfnTL5A_C-bgRsZ2DT-)

lvs不支持虚拟机，所以在docker容器里安装是不可能的，haproxy一个经得起考验的负载均衡中间件。

## 安装Haproxy镜像

Docker仓库中保存了Haproxy的镜像，只需下载即可。

```
$ docker pull haproxy
```

下载了haproxy镜像后，不要着创建容器，因为haproxy镜像里是不包含配置文件的.

## 创建Haproxy配置文件

**宿主机上创建一个配置文件**

```
$ touch /home/soft/hapoxy/haproxy.cfg
```

配置文件目录可以自己去指定，可以采用目录映射技术把soft目录映射到haproxy容器里面。haproxy容器就可以找到这个配置文件；启动Haproxy的服务自然而然就有配置文件了。

> 配置文件详情可以参考：[Haproxy安装部署文档及多配置文件管理方案](https://zhangge.net/5125.html)

**创建Haproxy容器**

```
$ docker run -it -d -p 4001:8888 -p 4002:3306 -v /home/soft/hapoxy:/usr/local/etc/haproxy --name haproxy1 --privileged --net=net1 haproxy

# 进入到后台运行的docker容器
$ docker exec -it haproxy1 bash
$ haproxy -f /usr/local/etc/haproxy/haproxy.cfg
```

> 退出指令exit ,只是退出交互界面，不会停止容器运行。

-p 端口映射：8888端口是haproxy监控画面的端口，可以配置随意端口。

-v 目录映射

\--name 命名

进入到容器中指定haproxy的配置文件。

创建心跳检测MYSQL用户名(%表示任何ip都可以使用这个账号登录到mysql数据库，密码为空)

```
CREATE USER 'haproxy'@'%' IDENTIFIED BY '';
```


# 3、负载均衡的高可用方案

### 为什么要采用双机热备？

单节点Haproxy不具备高可用，必须要有冗余设计

![](/files/-LfnTJprRWI7yzCZRgOh)

## 利用Keepalived实现双机热备方案

原理：虚拟出来一个虚拟IP,keepalived去争抢，谁争抢到谁就是主服务器。

![](/files/-LfnTJptJZ2OKWL-y0Ie)

具体方案架构：

![](/files/-LfnTJpv6146Pj9bNu1b)182.18.0.15是Docker内的虚拟IP不能被外网使用，所以需要借助宿主机器上安装keepalived，把192.168.99.65可以被外网访问的这个ip映射到Docker这个虚拟ip182.18 .0.15。

当应用程序访问192.168.99.65发送数据库请求，这个请求就会路由到docker的这个虚拟ip（182.18 .0.15）上，然后转发到主服务器容器，再负载均衡到PXC集群的某个mysql数据库。

## 安装Keepalived

keepalived必须要安装在Haproxy所在的容器之内。

```
# 进入到后台运行haproxy1的docker容器
$ docker exec -it haproxy1 bash
$ apt-get update
$ apt-get install keepalived
```

> 建议apt-get加速，比如设置成163镜像

## Keepalived 配置文件

Keepalived的配置文件是`/etc/Keepalived/Keepalived.conf`

**修改配置文件**

方式1：可以在容器内修改

```
$ apt-get install vim
$ vim /etc/keepalived/keepalived.conf
```

方式2：宿主机上定义好，传入到容器中

配置文件说明：

```
vrrp_instance  VI_1 {
    state  MASTER
    interface  eth0
    virtual_router_id  51
    priority  100
    advert_int  1
    authentication {
        auth_type  PASS
        auth_pass  123456
    }
    virtual_ipaddress {
        172.18.0.15
    }
}
```

**state MASER:** 标识Keepalived的身份（Master 主服务器，BACKUP备用服务器）。主服务器要抢占虚拟IP,备用服器不会抢占IP。

如果把每个Keepalived的配置文件都定义成身份是MASTER,这些节点启动之后都会去争抢虚拟IP，只会有一个节点抢到，其他节点身份自动降级为SLAVE。

**interface eth0：**&#x865A;拟ip保存到**eth0**网卡，宿主机可以访问，局域网其他电脑是看不到这个**eth0**网卡，所以需要在宿主机上把**eth0这个**网卡里的虚拟IP映射到局域网上的某一个虚拟ip上，所以后续还在宿主机上安装Keepalived。

**virtual\_router\_id 51：**&#x865A;拟路由标识，MASTER和BACKUP的虚拟路由标识必须一致。标识可以 0\~255.

**priority 100：**&#x4D;ASTER权重要高于BACKUP，数字越大优选级越高。

**advert\_int 1：**&#x4B;eepalived节点之间同步检查的实际间隔，单位为秒，主备之间必须一致。

**authentication：**&#x4B;eepalived节点之间通信需要验证，主从服务器验证方式。主备必须使用相同 密码爱能正常通信。

**virtual\_ipaddress：**&#x865A;拟IP地址.可以设置多个虚拟IP地址，每行一个。注意和你的PXC集群同网段.

## 启动Keepalived

haproxy1容器中启动Keepalived

```
$ service keepalived start
```

宿主机器上ping 一下虚拟IP测试

```
$ ping 172.18.0.15
```


# 4、热备份数据

## 热备份数据

> **冷备份**
>
> * 冷备份是关闭数据库时候的备份方式，通常做法是拷贝数据文件或者使用mysql dump指令。
> * 冷备份是最简单最安全的一种备份方式
> * 大型网站无法做到关闭业务备份数据，所以冷备份不是最佳选择。

![](/files/-LfnTJyoNhSsU5fMfr8_)

如果非要进行冷备份方案，可以考虑将PXC集群中的某个节点下线，然后备份数据，完成后让节点再上线，产生同步，这样又可以和其他节点数据保持一致。

### 热备份

热备份是在系统运行的状态下备份数据，也是难度最大的备份。

Mysql常见的热备份又LVM和XtraBackup两种方案。

#### LVM备份方式

是linux自带的一种技术，Linux对某一个分区创建快照实现对这个分区数据的备份。原则上LVM可以备份的数据库有很多：例如mysql，orcale，mongodb等。

缺**点：**

1.备份数据库时，需要对数据库加锁，这个数据库只能读取数据不能写入数据。这样对业务开展还是有一定的影响。

2.指令繁琐

#### XtraBackup备份方式（推荐使用）

XtraBackup是一款基于InnoDB的在线热备工具，具有开源免费，支持在线热备，占用磁盘空间小，能够非常快速地备份与恢复mysql数据库

**优点：**

* XtraBackup备份过程中不锁表、快速可靠
* XtraBackup备份过程不会打断正在执行的事务。
* XtraBackup能够基于压缩等功能节约磁盘空间和流量
* 支持全量备份，也支持增量备份
* 支持mysql官方版，以及衍生版，例如miradb等
* 免费

**全量备份和增量备份**

全量备份是备份全部数据。备份过程时间长，占用空间大。（对数据库的第一次更新一定要采用全量备份，后续的备份就可以采用增量备份）

![](/files/-LfnTJyqtlk54SHNKWW5)

增量备份是只备份变化的那部分数据。备份时间短，占用空间小。（比如一周做一次全量备份，一天做一次增量备份）

![](/files/-LfnTJys_FjQmNe2qWK5)

## XtraBackup的安装

XtraBackup工具需要安装在数据库所在的节点容器内，它备份出来的数据就直接保存在容器里了，这样做不好，我们应该把备份的数据导出到宿主机上，采用映射的技术。

**准备工作具体操作：**

宿主机上创建一个数据卷，将这个卷映射个某一个数据库节点上，然后通过热备工具备份出来的数据就可以在宿主机上看到了。

宿主机上创建数据卷：

```
$ docker volume create backup
```

配置某个数据节节点，映射数据卷(停止删除之前容器，加入热备份数据卷)

```
$ docker stop node1
$ docker run -d -p 3306:3306 -v v1:/var/lib/mysql -v backup:/data -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 --privileged -e CLUSTER_JOIN=node2 --name=node1 --net=net1 --ip 172.18.0.2 pxc
```

对比之前启动node1的不同点：

1.-v backup\:/data：加入备份数据库的数据卷

2.-e CLUSTER\_JOIN=node2：启动后跟哪个节点同步数据

**PXC全量备份的步骤**

PXC节点容器中安装XtraBackup，并执行备份。

```
$ docker exec -it node1 bash
$ apt-get update
$ apt-get install percona-xtrabackup-24
$ innobackupex -user=root --password=abc123456 /data/backup/full
$ exit
```

在宿主机器查看

```
$ docker inspect backup # 查看backup数据卷信息，查看路径
```

**PXC全量恢复步骤**

* 数据库可以热备份，但是不能热还原。为了避免恢复过程中的数据同步，我们采用空白 MYSQL还原数据，然后建立PXC集群。
* 还原数据前要将未提交的事务回滚，还原数据之后重启MySQL

宿主操作

1.删除pxc集群节点

2.删除数据卷

3.重新运行node1，加入备份的数据卷

```
$ docker stop node1 node2 node3
$ docker rm node1 node2 node3
$ docker volume rm v1 v2 v3
$ docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -v v1:/var/lib/mysql -v backup:/data --name=node1 --net=net1 --ip 172.18.0.2 pxc
```

进入node1容器节点：

1.删除数据

2.将没有提交的事务回滚（--apply-back）

3.还原数据（--copy-back）

```
$ docker exec -it node1 bash
$ rm -rf /var/lib/mysql/*
$ innobackupex --user=root --password=abc123456 --apply-back /data/backup/full/2018-xxxx-xx/
$ innobackupex --user=root --password=abc123456 --copy-back /data/backup/full/2018-xxxx-xx/
```

退出容器重启node1节点

```
$ exit 
$ docker stop node1
$ docker start node1
```


# Redis 集群

## 高速缓存介绍

* 高速缓存利用内存保存数据，读写速度远超硬盘
* 高速缓存可以减少I/O操作，降低I/O压力

## Redis介绍

* Redis是VMware开发的开源免费的KV型NoSQL缓存产品
* Redis具有很好的性能，最多可以提供10万次/秒的读写
* 目前新浪微博团队组建了世界上最大规模的Redis集群

## Redis集群介绍

Redis目前的集群方法分为以下几种：

1.RedisCluster：官方推荐，没有中心节点

2.Codis：中间件产品，360公司开发。

3.Twemproxy：中间件产品，存在中心节点

> 存在中心节点，这个中心节点一旦挂掉以后，整个redis集群将不可用。

## **RedisCluster**

* 无中心节点，客户端与redis直连，不需要中间代理层
* 数据可以被分片存储
* 管理方便，后续可自行增加和摘除节点


# Redis 集群介绍

> 主从同步
>
> * Redis集群中的数据库复制是通过主从来实现的
> * 主节点（Master）把数据分发给从节点（Slave）
> * 主从同步的好处在于高可用，Redis节点有冗余设计
>
> ![](/files/-LfnTKeojA_67546Ql2M)

## Redis集群高可用性

采用官方的**RedisCluster方案**，注意redis3.x之后支持，要让 Redis 集群正常工作至少需要 3 个 Master 节点，要想实现高可用，每个 Master 节点要配备 至少 1 个 Slave 节点。根据以上特点和要求，进行如下的集群实施规划： 使用 6 台服务器（物理机或虚拟机）部署 3 个 Master + 3 个 Slave；

> 搭建redis集群时，Redis集群中应该包含奇数个Master，至少应该有3个Master节点，为什么？
>
> 因为redis集群包括PXC集群都有选举机制，当集群中超过一半数量的节点挂点，剩余的节点是无法进行选举组成一个新的集群的。
>
> 比如使用两个节点的Master集群，一个Master节点挂掉，剩余的节点没有超过一半，redis集群不可用。三个节点的Master集群，一个挂掉，剩余节点过半，还可以进行选举组成一个新的集群。

![](/files/-LfnTKeqAo0hG6XTIqIQ)

> 为什么不需要配置redis的负载均衡？ 因为比如java的spring框架，php的包，nodejs的包内部实现了集群的负载均衡


# Redis 集群搭建

## 安装Redis镜像

导入本地Redis镜像文件，运行Redis容器

**下载镜像**

```
$ docker pull yyyyttttwwww/redis
```

**宿主机上创建内部网络net2**

```
docker network create –subnet=172.19.0.0/24 net2
```

**运行redis容器**

```
$ docker -it -d --name r1 -p 5001:6379 -net=net2 --ip 172.19.0.2 redis bash
```

**进入容器修改redis配置文件**

```
docker exec -it r1 bash
```

默认是不开启集群模式，配置文件路径`/etc/redis/redis.conf`

![](/files/-LfnTLDRf2biKjIZ7Kaj)

运行redis

```
$ cd /usr/redis/src
$ ./redis-server ../redis.conf
```

相同步骤启动其他5个节点 redis

## 使用redis-trib.rb组件集群

**安装redis-trib.rb**

redis-trib是基于Ruby的Redis集群命令行工具

容器中执行

```
$ cp /usr/redis/src/redis=trib.rb /usr/redis/cluster/
$ cd /usr/redis/cluster
$ apt-get install ruby
$ apt-get intall rubygems
$ gem install redis
```

创建Redis集群

```
#在r1节点上执行下面的指令
$ cd /usr/redis/src
$ mkdir -p ../cluster
$ cp redis-trib.rb ../cluster/
$ cd ../cluster
#创建Cluster集群
$ ./redis-trib.rb create --replicas 1 172.19.0.2:6379 172.19.0.3:6379 172.19.0.4:6379 172.19.0.5:6379 172.19.0.6:6379 172.19.0.7:6379
```

\--replicas 1 参数表示为每个主节点创建一个从节点

> redis 中通过cluster nodes 查看集群状态


# web服务器集群


# 负载均衡

Nginx是性能非常出色的反向代理服务器，最大可以支持8万/秒的并发访问。

## 安装Nginx镜像

Docker仓库中提供了Nginx镜像，下载安装即可

```
$ docker pull nginx
```

## **宿主机添加配置nginx**

## 启动nginx容器

映射宿主机nginx配置

```
$ docker run -it -d --name n1 -v /home/n1/nginx.conf:/etc/nginx/nginx.conf --net=host --privileged nginx
```


# 负载均衡的高可用方案

利用Keepalived实现双机热备

![](/files/-LfnTK0a-C1vO9xskvVS)

进入到nginx容器安装keepalived

```
$ docker exec it n1 bash
$ apt-get update
$ apt-get install keepalived
$ apt-get install vim
```

配置keepalived

网卡配置的是宿主机的网卡


# Docker 三剑客

为了把容器化技术的优点发挥到极致，docker公司先后推出了三大技术:`docker-machine`,`docker-compose`,`docker-swarm`，可以说是几乎实现了容器化技术中所有可能需要的底层技术手段。

![](/files/-LfnTJbWOFsnw9_6uQ3t)

* docker-machine - 提供容器服务
* docker-compose - 提供脚本执行服务，不用在像以前把容器的启动命令写的非常的长，用compose编写脚本就能简化容器的启动
* 几条简单指令就可以创建一个docker集群，最终实现分布式的服务

## 去中心化的设计

docker-swarm是去中心化的设计，思想与redis cluster集群，pcx集群很像

![](/files/-LfnTJbY2luqAp8sGhuf)

docker-swarm节点：

* Manager 节点：管理swarm集群等其他事情。
* Worker节点：工作节点，运行容器部署项目的。

不管是Manager 节点，还是Worker节点都可以部署多节点。一个Manage节点down机，那么剩余的节点会选举一个新的Manager节点来管理swarm集群，Worker节点同理。

参考资料：

[Docker三剑客实践之部署集群](https://www.jianshu.com/p/0e231a928ee6)


# Docker Machine

## 参考资料

[Docker Machine 简介](https://www.cnblogs.com/sparkdev/p/7044950.html)

[https://www.cnblogs.com/qingzheng/category/1033826.html](https://legacy.gitbook.com/book/xiaoxiami/docker/edit#)


# Docker Compose

[官方文档：Docker-compose介绍](https://docs.docker.com/compose/overview/)

[官方文档：Docker-compose文件语法](https://docs.docker.com/compose/compose-file/)

[官方文档：Docker-compose命令](https://docs.docker.com/compose/reference/overview/)

Docker compose 是 Docker容器编排的工具， 可以配置并启动多个容器，适合复杂业务场景。

## 安装

[官方安装文档](https://docs.docker.com/compose/install/)

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

然后赋予可执行权限

```
sudo chmod +x /usr/local/bin/docker-compose
```

查看下版本`docker-compose --version`

## Docker cmpose 文件编写

文件名：`docker-compose.yml`

> 工具：yaml检查的在线工具<http://www.yamllint.com/>

目前可以使用[compose file version 3](https://docs.docker.com/compose/compose-file/)版本语法语法

## 操作

[官方文档：Docker-compose命令](https://legacy.gitbook.com/book/xiaoxiami/docker/edit#)

启动所有

```
docker-compose up -d
```

`-d` 后台运行，使用`docker-compose up --help`查看更多

停止所有容器

```
docker-compose stop
```

也可以单独停止一个容器`docker stop 容器名`

删除多个容器

```
docker rm 容器1,容器2
```

自我提示示例：

```
services: 
  web1: 
    container_name: web1
    image: "centos:jdk"
    healthcheck:
      test: ["CMD", "curl","-s","-f", "http://localhost:80"]
      interval: 5s
      timeout: 5s
      retries: 3
    ports: 
      - "8080:80"
    privileged: true
    volumes: 
      - "/home/shenyi/nginx/web1/:/var/www/html/"
    networks:
      mynginx-net:
        ipv4_address: ${web1_addr}

  web2: 
    container_name: web2
    image: "centos:jdk"
    ports: 
      - "8081:80"
    privileged: true
    volumes: 
      - "/home/shenyi/nginx/web2/:/var/www/html/"
    networks:
      mynginx-net:
        ipv4_address: 192.156.0.3
    healthcheck:
      test: ["CMD", "curl","-s","-f", "http://localhost:80"]
      interval: 5s
      timeout: 5s
      retries: 3


  nginx:
    container_name: mynginx
    image: "centos:nginx"
    healthcheck:
      test: ["CMD", "curl","-s","-f", "http://localhost:80"]
      interval: 5s
      timeout: 5s
      retries: 3
    ports:
      - "9090:80"
    privileged: true
    volumes:
      - "/home/shenyi/nginx/conf/nginx.conf:/etc/nginx/nginx.conf"
    networks:
      mynginx-net:
        ipv4_address: 192.156.0.2
networks:
  mynginx-net:
    driver: bridge
    ipam: 
     config: 
      - subnet: 192.156.0.0/16
version: "3"
```

## 资料

[Docker-Compose重启策略](http://www.voidcn.com/article/p-gthqvcdm-bte.html)


# Swarm 集群

## 创建Swarm 集群

```
$ docker swarm init
```

`--listen-addr ip : port`- 管理者节点

`advertise-addr ip`- 广播地址

## 加入Swarm 集群

```
$ docker swarm join-token manager
$ docker swarm join-token worker
```

添加manager或者worker节点到集群，只要执行对应的命令即可。

在创建的创建Swarm 集群的机器上，执行以下命令，会生成响应的执行命令，只需要在响应的机器上运行即可，就可以加入奥这个swarm集群。

![](/files/-LfnTJlB9u59zXg2KdSy)

## 查看swarm集群节点

```
$ docker node ls
```

只可以在Manager节点执行命令

## 创建共享网络

如果不同主机容器和容器之间业务通讯，还需要创建一个新的共享网络。

```
$ docker network ls 
$ docker network create -d overlay --attachable swarm_test
```

ingress网络仅用于管理Swarm集群，所以我们需要创建新的共享网络。

搞定之后就可以部署各种各样的集群了。比如PXC集群，只需要`--net=swarm_test`即可。

## 退出Swarm集群

* **主动退出Swarm集群：**

```
$ docker swarm leave --force
```

Manager 退出集群必须要使用`--force`参数,Work节点z直接执行`docker swarm leave`即可

* **被动退出Swarm集群：**

宿主机执行

如果manager节点想要退出集群

```
$ docker node ls
$ docker node demot 节点名字
$ docker stop node1
$ docker rm node1
$ service docker stop
$ docker node rm 节点名字
$ docker node ls
```

删除任何的节点必须要先停止它的Dokcer服务

Manager节点必须先降级成Worker节点，然后再去删除。

> 解除docker集群（解除docker集群，网络自动消失`docker network ls`查看）
>
> ```
> $ docker swarm leave -f
> $ docker network ls
> $ docker network rm docker_gwbridge
> ```

## 资料

[【Docker】 Swarm简单介绍](https://www.cnblogs.com/franknihao/p/8490416.html)


# 附录：网络 network

[network官方文档](https://docs.docker.com/engine/reference/commandline/network/#usage)

首先使用`docker network ls`看一下，默认会创建 桥接模式bridge

**比如：**

当你启动了一个没有指定网络的compose，则会建立一个默认的mycompose\_default 的网络。使用下面的命令查看网络详情。

```
docker network inspect mycompose_default
```

当我们启动容器时，默认会加入bridge这个网络。

**示例创建一个简单的网络**

最简单语法

```
docker network create -d bridge mynginx
```

让我们启动容器时就可以加入`docker run-d--network=mynginx 容器名`，这时创建的容器会加入这个网络

设置子网 地址

```
docke rnetwork create -d bridge--subnet=192.128.0.0/16 mynginx
```

`http://tool.chinaz.com/Tools/subnetmask`这里有个子网掩码的计算地址

![](/files/-LfnTK7yYbc3-xx36vcW)

![](/files/-LfnTK8-Rwbn8JeBxZsA)

## 资料

[Docker的4种网络模式](https://www.cnblogs.com/gispathfinder/p/5871043.html)


# Docker 集群（K8S）


# 资料

[How to deploy a MongoDB Replica Set using Docker](https://towardsdatascience.com/how-to-deploy-a-mongodb-replica-set-using-docker-6d0b9ac00e49)

<https://portainer.io/>

[docker容器轻量级web管理工具之portainer](http://www.mamicode.com/info-detail-1653726.html)

[bamboo](http://www.confluence.cn/display/quickstart/bamboo)

[Docker 教程](http://www.runoob.com/docker/docker-tutorial.html)

## Docker官方英文资源

docker官网：[http://www.docker.com](http://www.docker.com/)

Docker windows入门：<https://docs.docker.com/windows/>

Docker Linux 入门：<https://docs.docker.com/linux/>

Docker mac 入门：<https://docs.docker.com/mac/>

Docker 用户指引：<https://docs.docker.com/engine/userguide/>

Docker 官方博客：<http://blog.docker.com/>

Docker Hub:<https://hub.docker.com/>

Docker开源：<https://www.docker.com/open-source>

## Docker中文资源

Docker中文网站：<https://www.docker-cn.com/>

Docker安装手册：<https://docs.docker-cn.com/engine/installation/>

## Docker 国内镜像

网易加速器：<http://hub-mirror.c.163.com>

官方中国加速器：<https://registry.docker-cn.com>

ustc的镜像：<https://docker.mirrors.ustc.edu.cn>

daocloud加速器：<https://www.daocloud.io/mirror#accelerator-doc（注册后使用）>


# 注意

haproxy：负载均衡中间件，对tcp/IP协议的负载均衡支持的非常的好。

nginx：负载均衡中间件，对http协议支持的非常好，所以做一些web反向代理。

## entrypoint,cmd区别

[docker学习笔记12：Dockerfile 指令 ENTRYPOINT介绍](https://www.cnblogs.com/51kata/p/5262107.html)

[Dockerfile RUN，CMD，ENTRYPOINT命令区别](https://www.jianshu.com/p/f0a0f6a43907)

自我提醒：

1. 在docker run 启动时最后的参数会覆盖掉Dockerfile中的CMD命令

2.docker run 加上 --entrypoint的方式可以替换掉Dockerfile中的entrypoint指令

3.如果没有２的覆盖，entrypoint一定会被执行


# Mongodb 集群


# 资料

[How to deploy a MongoDB Replica Set using Docker](https://legacy.gitbook.com/book/xiaoxiami/docker/edit#)


# 常用操作笔记

**场景1: 当下载了一个镜像,想查看image镜像里面一些信息.**

1.拉取一个镜像

```
$ docker pull php:alpine3.7
```

2.想知道镜像里面的php版本

```
 $ docker run  -it --rm php:alpine3.7 php -v
```

3.想对这个镜像里信息了解的更多,也就是得执行多条语句

```
$ docker run  -it --rm php:alpine3.7 sh -c "php -v && php -m"
```

4.如果想临时进去操作一下,查看更多的信息,加上sh,即可, 在容器中exit退出的时候,容器也随之消失

```
$ docker run -it --rm php:alpine3.7 sh
```

> 你进行docker ps 查看正在运行的容器的时候,发现**并没有运行**的容器.原因是因为 `--rm`, --rm， 指定容器停止后自动删除容器(不支持以docker run -d启动的容器),所以可以使用此方式来查看自己拉取容器里的一些信息.
>
> 备注:
>
> -i:以交互模式运行容器，通常与 -t 同时使用；
>
> -t:为容器重新分配一个伪输入终端，通常与 -i 同时使用；

**场景2: 当你使用了一个已经存在的开发框架的docker环境,那么你需要的是使用本地开发代码,一遍开发一遍使用docker里的环境测试**

以swoft为例,后台运行

```
$　docker run -d -p 80:80 --name swoft swoft/swoft:latest
```

其实就是在启动的时候把自己的开发本地目录映射到容器内的web目录即可.-v参数

```
$ docker run -p 80:80 --name swoft -d \
  -v /home/revin/swoft/:/var/www/swoft \
 swoft/swoft:latest
```

**场景3. 已经有了dockerfile文件,拿swoole开发为例**

1.构建Dockerfile

```
FROM php:alpine3.7
RUN echo http://mirrors.ustc.edu.cn/alpine/v3.7/main > /etc/apk/repositories  && \
echo http://mirrors.ustc.edu.cn/alpine/v3.7/community >> /etc/apk/repositories
RUN apk update && apk upgrade
RUN apk add m4 autoconf make gcc g++
RUN apk add linux-headers
ADD ./install/swoole-2.2.0.tgz /tmp/
RUN cd /tmp/swoole-2.2.0 && phpize && ./configure && make && make install
RUN docker-php-ext-enable swoole
CMD ["php","-m"]
```

> ADD 和COPY的不同之处在于Add 可以在里面帮你自动解压缩.

2.`docker build`指令构建Docker镜像

-t 构建后iamge的名字

```
$ docker build -t swoole-2.2 .
```

构建完成后就可以通过`docker images`指令查看镜像是否创建成功。

并映射了本地开发环境.

```
$ docker run -it --name testpro --rm \
-v /temp/test/swoole:/myapps \
-p 9501:9501 \
swoole-2.2 sh
```

上面的代码是运行一个容器,并进入容器,但是退出后容器会消失.

```
$ docker run --name testpro \
-v /temp/test/swoole:/myapps \
-p 9501:9501 \
-d swoole-2.2
```

上面的代码是后台运行一个容器,可以通过`docker exec -it swoft bash`进入容器进行交互.(alpine中无bash,可以使用sh)

3.当修改了代码,或者配置文件则需要重启容器

```
$ docker restart testpro
```

4.查看容器里的日志

```
$ docker logs testpro
```

5.当开发时,需要了解容器的ip地址等信息

```
$ docker inspect swoft
```

6.停止容器

```
$ docker stop testpro
```

其他的命令则`--help`进行查看

**场景4. 构建自己的image镜像。**

当你使用 别人的基础镜像，你可以镜像进行一些修改安装。

1、使用镜像启动一个容器

2、构建一个新的images

```
docker commit 容器名 image镜像名:tag
```

场景5：容器宿主机间相互拷贝文件

docker cp命令

文档:<https://docs.docker.com/engine/reference/commandline/cp/>

从容器中拷贝到主机:

```
docker cp tmp:/etc/nginx/nginx.conf /home/revin/nginx/conf/
```

也可以从宿主机拷贝到容器中

```
docker cp /home/revin/nginx/conf/ tmp:/etc/nginx/nginx.conf
```

不过一般情况下配置文件，只会挂载到容器中。

#### windows10 下

```
docker volume create portainer_data
docker run -d -p 8000:8000 -p 10001:9000 --name portainer --restart always -v \\.\pipe\docker_engine:\\.\pipe\docker_engine -v portainer_data:C:\data portainer/portainer


docker volume create rabbitmq_data
docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq3.8 -v rabbitmq_data:/var/lib/rabbitmq rabbitmq:3-management

docker volume create mongodb_data
docker run -d -p 27017:27017 --name mongodb -v mongodb_data:/data/db mongo


docker volume create redis_data
docker run -d -p 27017:27017 --name mongodb -v mongodb_data:c:\data\db mongo

# docker network create esnet (linux)
docker network create  --driver nat esnet
docker volume create elasticsearch_data
 docker run -d --name elasticsearch --net esnet -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -e "http.cors.enabled=true" -e "http.cors.allow-origin=*" -v elasticsearch_data:/usr/share/elasticsearch/data elasticsearch:7.8.1
#header
docker run -d -p 9100:9100 --name elasticsearch-manager mobz/elasticsearch-head:5-alpine
```


# 配置远程访问

编辑

```
sudo vi /usr/lib/systemd/system/docker.service
```

```
把原本是 
ExecStart=/usr/bin/dockerd  这一行 注释掉 改成

ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock
```

然后保存后，重启Docker

再一次执行：`ps-ef|grepdocker`

> ubuntu 14 配置方法:<https://www.cnblogs.com/zqifa/p/linux-docker-3.html>
>
> ```
> DOCKER_OPTS="$DOCKER_OPTS -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375"
> ```

测试可以连接到docker api

`curl http://localhost:5251/version`

## 资料

[Ubuntu 开启 Docker远程API](http://blog.topspeedsnail.com/archives/5326)


