## 一、欢迎来到 Docker 世界
### 1\. Docker 与虚拟化
在没有 Docker 的时代,我们会使用硬件虚拟化(虚拟机)以提供隔离。这里,虚拟机通过在操作系统上建立了一个中间虚拟软件层 Hypervisor ,并利用物理机器的资源虚拟出多个虚拟硬件环境来共享宿主机的资源,其中的应用运行在虚拟机内核上。但是,虚拟机对硬件的利用率存在瓶颈,因为虚拟机很难根据当前业务量动态调整其占用的硬件资源,因此容器化技术得以流行。其中,Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上。
![](https://img.kancloud.cn/24/40/244007da9cf45e36587c666e0be60720_694x306.jpg)
Docker 容器不使用硬件虚拟化,它的守护进程是宿主机上的一个进程,换句话说,应用直接运行在宿主机内核上。因为容器中运行的程序和计算机的操作系统之间没有额外的中间层,没有资源被冗余软件的运行或虚拟硬件的模拟而浪费掉。
Docker 的优势不仅如此,我们来比较一番。
| 特性 | Docker | 虚拟机 |
| --- | --- | --- |
| 启动速度 | 秒级 | 分钟级 |
| 交付/部署 | 开发、测试、生产环境一致 | 无成熟体系 |
| 性能 | 近似物理机 | 性能损耗大 |
| 体量 | 极小(MB) | 较大(GB) |
| 迁移/扩展 | 跨平台,可复制 | 较为复杂 |
### 2\. 镜像、容器和仓库
Docker 由镜像(Image)、容器(Container)、仓库(Repository) 三部分组成。
Docker 的镜像可以简单的类比为电脑装系统用的系统盘,包括操作系统,以及必要的软件。例如,一个镜像可以包含一个完整的 centos 操作系统环境,并安装了 Nginx 和 Tomcat 服务器。注意的是,镜像是只读的。这一点也很好理解,就像我们刻录的系统盘其实也是可读的。我们可以使用`docker images` 来查看本地镜像列表。
Docker 的容器可以简单理解为提供了系统硬件环境,它是真正跑项目程序、消耗机器资源、提供服务的东西。例如,我们可以暂时把容器看作一个 Linux 的电脑,它可以直接运行。那么,容器是基于镜像启动的,并且每个容器都是相互隔离的。注意的是,容器在启动的时候基于镜像创建一层可写层作为最上层。我们可以使用`docker ps -a` 查看本地运行过的容器。
Docker 的仓库用于存放镜像。这一点,和 Git 非常类似。我们可以从中心仓库下载镜像,也可以从自建仓库下载。同时,我们可以把制作好的镜像 commit 到本地,然后 push 到远程仓库。仓库分为公开仓库和私有仓库,最大的公开仓库是官方仓库 Dock Hub,国内的公开仓库也有很多选择,例如阿里云等。
![](https://img.kancloud.cn/eb/1b/eb1be08475629eaa24236dad9c193de3_2000x1389.jpg)
### 3\. Docker 促使开发流程变更
笔者认为,Docker 对开发流程的影响在于使环境标准化。例如,原来我们存在三个环境:开发(日常)环境、测试环境、生产环境。这里,我们对于每个环境都需要部署相同的软件、脚本和运行程序,如图所示。事实上,对于启动脚本内容都是一致的,但是没有统一维护,经常会出问题。此外,对于运行程序而言,如果所依赖的底层运行环境不一致,也会造成困扰和异常。
![](https://img.kancloud.cn/23/bb/23bbbbec6a7d600126c6c7348c7478a0_655x512.jpg)
现在,我们通过引入 Docker 之后,我们只需要维护一个 Docker 镜像。换句话说,多套环境,一个镜像,实现系统级别的一次构建到处运行。此时,我们把运行脚本标准化了,把底层软件镜像化了,然后对于相同的将要部署的程序实行标准化部署。因此,Docker 为我们提供了一个标准化的运维模式,并固化运维步骤和流程。
![](https://img.kancloud.cn/bb/14/bb14496f2e1b4ba692fb5db3eaee33b6_657x456.jpg)
通过这个流程的改进,我们更容易实现 DevOps 的目标,因为我们的镜像生成后可以跑在任何系统,并快速部署。此外,使用 Docker 的很大动力是基于 Docker 实现弹性调度,以更充分地利用机器资源,节省成本。
哈哈,笔者在使用 Docker 过程中,还发现了一些很棒的收益点,例如我们发布回滚的时候只需要切换 TAG 并重启即可。还比如,我们对环境升级,也只需要升级基础镜像,那么新构建的应用镜像,自动会引用新的版本。(欢迎补充~~~)
## 二、从搭建 Web 服务器开始说起
### 1\. 环境先行,安装 Docker
现在,我们需要安装以下步骤安装 Docker。
* 注册帐号:在[https://hub.docker.com/](https://link.segmentfault.com/?enc=3fEqfDbhnMyUeVkm36SPrg%3D%3D.uXjJrY0%2BMvh8QvTRFQnOdJ89%2Fxr7%2B2opfffmQFRAsRc%3D)注册账号。
* 下载安装
> 官方下载地址:(Mac):[https://download.docker.com/mac/stable/Docker.dmg](https://link.segmentfault.com/?enc=bnhl4MQZqJrkm%2B0b9Um0SQ%3D%3D.xlledHBMTUkBsEQKtHjGkmdpv%2FYjsoe%2F839Sn%2B7rI%2FAYk6XjLzOgr5M2A1u0SHujNZSdX632TG8FIDrzlaodpw%3D%3D)
> 阿里云下载地址(Mac):[http://mirrors.aliyun.com/docker-toolbox/mac/docker-for-mac/](https://link.segmentfault.com/?enc=1%2BajUSvB5%2BH87EwgRMK7Xw%3D%3D.%2BHuTJitVL%2BI9O9YD9llOOlEYXLwIBr8AovkF7qVCMpeEnce7d9CdckBQUaSzQriUXb7YcjgqT0UxVl7M4CQ15V%2BupVUPJx%2Fv68Ph%2BDILPgAkry6ekK7BDBkEGK8Y6JvTN3LOmZzEFH4FsKx7y88aIQ%3D%3D)
> 阿里云下载地址(Windows):[http://mirrors.aliyun.com/docker-toolbox/windows/docker-for-windows/](https://link.segmentfault.com/?enc=TG%2BloDqMAd9o%2BV6H5dQ42Q%3D%3D.8rwSadWUVeYK9gr44D6G8JqzS%2FIq1D7bmWuIDQ602psIrCn58%2FUw1y0j%2BWfenvBsH3IVU6jX8N6lNjELdBynSZlUZPgwbQZIxpywwX7Q19k%3D)
* 安装指南
这里,双击刚刚下载的 Doker.dmg 安装包进行安装。
![](https://img.kancloud.cn/72/e1/72e15a95218f8ef9a9bf662646992b47_723x343.jpg)
安装完成后启动, Mac 顶部导航栏出现了一个图标,通过菜单可以进行 docker 配置和退出等操作。
> 官方指南:[https://docs.docker.com/install/](https://link.segmentfault.com/?enc=5lxUhqldVNoPSo%2FZxZw3ig%3D%3D.mDqLkQAHTGH%2BqMatUfHQPnQvE7slGieqcsFk4i%2BR5lhMxs5iPaBmbI%2FsPaYh%2BeDz)
> 阿里云指南(Linux):[https://yq.aliyun.com/articles/110806?spm=5176.8351553.0.0.468b1991jdT95t](https://link.segmentfault.com/?enc=oDkJ2YpaOIgRowA%2Fd20vIA%3D%3D.d94qt1xshFm%2F0ACUlr0cskq3DB3y8aQ%2BVNMD58zdYcoskBKh8wmhZp%2FleHlWuSNtw6lErcQjpV9kVQ6iErgqqyR4vkSpuG8RdD69bbQV%2Fd4%3D)
* 设置加速服务
市面上有很多加速服务的提供商,如:DaoCloud,阿里云等。这里,笔者使用的是阿里云。(注意的是,笔者操作系统是 Mac,其他操作系列参见阿里云操作文档)
![](https://img.kancloud.cn/4a/7b/4a7b8d0969698ae819588a3ef5ac648a_1400x704.jpg)
右键点击桌面顶栏的 docker 图标,选择 Preferences ,在 Daemon 标签(Docker 17.03 之前版本为 Advanced 标签)下的 Registry mirrors 列表中将
`https://xxx.mirror.aliyuncs.com` 加到"registry-mirrors"的数组里,点击 Apply & Restart 按钮,等待 Docker 重启并应用配置的镜像加速器。
![](https://img.kancloud.cn/81/07/810764df50086c0c321d4e3889ae2a06_994x1134.jpg)
> 阿里云操作文档:[https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors](https://link.segmentfault.com/?enc=OtIYF2HOo8dYFakbguLSLA%3D%3D.Drl0a7eEpFdIDzAfvhxGV8W9iWvaLMi36Pldhg%2BP8v5CmKytMGchmp6ojmZMlKVwXZQFLELI9r%2BzjEOAPfZxlg%3D%3D)
* 查看版本
至此,我们已经安装完成了。这里,我们来查看版本。
~~~applescript
docker version
~~~
查看结果,如下所示。
![](https://img.kancloud.cn/56/09/5609dd0e4fbdd2244a50a069e94b8151_393x159.jpg)
### 2\. 实干派,从搭建 Web 服务器开始
我们作为实干派,那么先来搭建一个 Web 服务器吧。然后,笔者带你慢慢理解这个过程中,做了什么事情。首先,我们需要拉取 centos 镜像。
~~~css
docker run -p 80 --name web -i -t centos /bin/bash
~~~
紧接着,我们安装 nginx 服务器,执行以下命令:
~~~awk
rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
~~~
安装完 Nginx 源后,就可以正式安装 Nginx 了。
~~~cmake
yum install -y nginx
~~~
至此,我们再输入`whereis nginx` 命令就可以看到安装的路径了。最后,我们还需要将 Nginx 跑起来。
~~~ebnf
nginx
~~~
现在,我们执行 `ctrl + P + Q` 切换到后台。然后,通过 `docker ps -a` 来查看随机分配的端口。
![](https://img.kancloud.cn/13/2d/132d60654d38c046ed738b963c4b317b_1064x51.jpg)
这里,笔者分配的端口是`32769` ,那么通过浏览器访问`http://127.0.0.1:32769` 即可。
![](https://img.kancloud.cn/6d/13/6d1358247c2befc189e53946dfe7ee0f_747x214.jpg)
大功告成,哈哈哈~
### 3\. 复盘理解全过程
现在,我们来理解下这个流程。首先,我们输入`docker run -p 80 --name web -i -t centos /bin/bash` 命令会运行交互式容器,其中`-i` 选项告诉 Docker 容器保持标准输入流对容器开放,即使容器没有终端连接,另一个`-t` 选项告诉 Docker 为容器分配一个虚拟终端,以便于我们接下来安装 Nginx 服务器。(笔者备注:Docker 还支持输入`-d` 选项告诉 Docker 在后台运行容器的守护进程)
Docker 会为我们创建的每一个容器自动生成一个随机的名称。事实上,这种方式虽然便捷,但是可读性很差,并且对我们后期维护的理解成本会比较大。因此,我们通过`--name web` 选项告诉 Docker 创建一个名称是`web` 的容器。此外,我们通过`-p 80` 告诉 Docker 开放 80 端口,那么, Nginx 才可以对外通过访问和服务。但是,我们的宿主机器会自动做端口映射,比如上面分配的端口是 `32769` ,注意的是,如果关闭或者重启,这个端口就变了,那么怎么解决固定端口的问题,笔者会在后面详细剖析和带你实战。
这里,还有一个非常重要的知识点`docker run` 。Docker 通过 run 命令来启动一个新容器。Docker 首先在本机中寻找该镜像,如果没有安装,Docker 在 Docker Hub 上查找该镜像并下载安装到本机,最后 Docker 创建一个新的容器并启动该程序。
![](https://img.kancloud.cn/86/0a/860a19988f1e6bcc04d549faaa21f74d_1025x360.jpg)
但是,当第二次执行 `docker run` 时,因为 Docker 在本机中已经安装该镜像,所以 Docker 会直接创建一个新的容器并启动该程序。
![](https://img.kancloud.cn/22/a8/22a82ab5c5cf0644611359c5c2b08957_579x360.jpg)
注意的是,`docker run` 每次使用都会创建一个新的容器,因此,我们以后再次启动这个容器时,只需要使用命令`docker start` 即可。这里,`docker start` 的作用在用重新启动已存在的镜像,而`docker run` 包含将镜像放入容器中`docker create` ,然后将容器启动 `docker start` ,如图所示。
![](https://img.kancloud.cn/13/75/1375d416abbcbec8693c87fb9365bd7e_929x282.jpg)
现在,我们可以在上面的案例的基础上,通过`exit` 命令关闭 Docker 容器。当然,如果我们运行的是后台的守护进程,我们也可以通过`docker stop web` 来停止。注意的是,`docker stop` 和 `docker kill` 略有不同,`docker stop` 发送 SIGTERM 信号,而 `docker kill` 发送SIGKILL 信号。然后,我们使用 `docker start` 重启它。
~~~crmsh
docker start web
~~~
Docker 容器重启后会沿用 `docker run` 命令指定的参数来运行,但是,此时它还是后台运行的。我们必须通过`docker attach` 命令切换到运行交互式容器。
~~~arduino
docker attach web
~~~
### 4\. 不止如此,还有更多命令
Docker 提供了非常丰富的命令。所谓一图胜千言,我们可以从下面的图片了解到很多信息和它们之前的用途。(可以直接跳过阅读,建议收藏,便于扩展阅读)
![](https://img.kancloud.cn/95/b0/95b066f571962fa438eccd849410da2b_1024x768.jpg)
如果希望获取更多信息,可以阅读官方使用文档。
| Command | Description |
| --- | --- |
| [docker attach](https://link.segmentfault.com/?enc=51nzk%2FmYh7Vag4K9a%2BD09A%3D%3D.nkCKD6a6VjAFWjJhoJidH4r71L8lcjY%2Ff6XUW1jmOwTDhlrPykE0yokDfxz8p4slHV5VrnmjQ%2BSCYZsV5wiDwg%3D%3D) | Attach local standard input, output, and error streams to a running container |
| [docker build](https://link.segmentfault.com/?enc=3BYam3VH0BKx0Fd3gNyrEA%3D%3D.EXVBtPbrq96uqMMJ1houSs%2B7u6z5Z5kkUjU%2Frh2FdSae9iT8AnFkpPifNCgZ%2BX8XaiOGL6D0tNeWBBiNH8z7hw%3D%3D) | Build an image from a Dockerfile |
| [docker builder](https://link.segmentfault.com/?enc=YQ0YYLgcYCe2uXZ%2BVzkSCg%3D%3D.X7QOuM64T3WucLhxoO4BeYYR6ehwp7ivyPNEAzPgflwbdgkzHwGyBHoRvDNB5%2F9jpxbpFnnbNYmgMTDF%2B6PjNA%3D%3D) | Manage builds |
| [docker checkpoint](https://link.segmentfault.com/?enc=XXOvu0bllsqwkhjtDYpiMA%3D%3D.4eDGhpSw1Ji10PPL%2F5NokLnoPN9Cu1eJpMvmTV0T09nhqo2ZjbPa2sMFI%2Bu8krIFes%2Ft8H02SjRTHT5X2z8fftagGobuj1OTZx%2FQMe9lYGE%3D) | Manage checkpoints |
| [docker commit](https://link.segmentfault.com/?enc=qrfWP51ghwkPkP%2F6sqN3Dg%3D%3D.veAuG%2B4zofT%2FMNGCGwSXoOHvlf2S1AqxI60pok4zDDlFuCzie9inOw5ke%2BGfw8aLpVVx82guQCRgxV6yeo9Qkw%3D%3D) | Create a new image from a container’s changes |
| [docker config](https://link.segmentfault.com/?enc=jPLOQt25RhZqDnoylXDZzg%3D%3D.cIFim9OLPTRk34XBViNGhCYjZDrsIxDLyYWgDS3wV0kV41TZjLA%2BHbZCsOpAhV4dbfllQxYDIz6YD5GG3%2BiwKA%3D%3D) | Manage Docker configs |
| [docker container](https://link.segmentfault.com/?enc=L%2BBRU6YR9KvoiJHihIiGsQ%3D%3D.ZNP1N3Cb7spvAmw5N9S8JtfLItV1lVvDE%2BM26kRM3sAaBTTPUIdcKFNryK7CI%2FegKDNQszq0gx%2F0krIRj6vIiQ%3D%3D) | Manage containers |
| [docker cp](https://link.segmentfault.com/?enc=sFmdnmgqFqcJW6n1%2FzRlwA%3D%3D.5PeuMi%2FcKuQdqWzqPAsj5BjGmFIvtVZ9Qbg7cS3DZeuGqTqFMSobL5ttqy%2BvNvpyYvlS86mpSKx%2Fvq4wfkgj8g%3D%3D) | Copy files/folders between a container and the local filesystem |
| [docker create](https://link.segmentfault.com/?enc=LwmPIT8hOq0tGRZIGJacZA%3D%3D.Io53d5sHLjeFoBd9OamR274wia5gsaKej8eZfS0KrDwbnliX3Lc869ScrbF6dniCd0N0jk50gbc3ifQ13NbUTw%3D%3D) | Create a new container |
| [docker deploy](https://link.segmentfault.com/?enc=JmoMIEdLy5mEpvsWG8SZdA%3D%3D.Vd3SqG5z34luyBxKMOjcl3QreD0ANN7tUJO2KDbgf0EkK8itr5MMrk2V%2B4ZEmK7ultlV3DGX68RkQN40wRHZIw%3D%3D) | Deploy a new stack or update an existing stack |
| [docker diff](https://link.segmentfault.com/?enc=SmtBFPzkpYFt5NtuOMj%2Fgw%3D%3D.kOl02rOsin5lgCxFI7bi%2FKeltFXadlM%2BlLNc0UW0f85JVHjtIphTln%2FsGTGXkZLmnVoSq9Os5xXuoO%2BifL1o4A%3D%3D) | Inspect changes to files or directories on a container’s filesystem |
| [docker engine](https://link.segmentfault.com/?enc=E1D8woQ%2Bp0BGGyzpmYldsA%3D%3D.iZnNIhc7nzAXADLTg2%2Bbd%2Fqu6wUy7MnPBMXjcKBz8%2F4nOVhxPaJsTjrIj%2BogPOEJ8JHeykg9sENVum73FqfLvA%3D%3D) | Manage the docker engine |
| [docker events](https://link.segmentfault.com/?enc=d4%2FGiguEgTZQknJBFBjdjg%3D%3D.1mF5k%2FJgb7xIa2dCHW5e1H1PJBUYqmKZvlikAOCvtDk6Yr6QZ218FKgqOo6NtVEx7jjX0nVxFS4nSqKJXlF6Fg%3D%3D) | Get real time events from the server |
| [docker exec](https://link.segmentfault.com/?enc=vSytHkN0UjCeNuMcjr577g%3D%3D.ArCnPVjF2zabfQylIY63oW4ypTNTN1jH7Rzp37mjC1%2BEXmA2VORrwchxtObFsAW2QfL4jkiLoCtHOZUfD8UVkg%3D%3D) | Run a command in a running container |
| [docker export](https://link.segmentfault.com/?enc=MbapZ2bztrQw6IE3QzR45A%3D%3D.L3UxIGQtBKDTBUQgJEaO3Ko4pZiovE1nqv5bngMs6pUb7ssrAB%2BWjWvmxUFvQv9zma%2BOw%2F%2B4xlHNC5Ez3M%2FLdw%3D%3D) | Export a container’s filesystem as a tar archive |
| [docker history](https://link.segmentfault.com/?enc=iEm0PS2UQUHi6pXieD790Q%3D%3D.DE%2FscQYtksxm70NAnW%2FBg%2FhovWMEjRs9%2Fy%2FscVaPliaueb%2FeX%2BdasrxxDSqpstEzHQAJcTvl1VqTsoLKMkpEVA%3D%3D) | Show the history of an image |
| [docker image](https://link.segmentfault.com/?enc=modvyNQtJB9HAthXPxB%2FEA%3D%3D.io%2FRQWwBxR0iCZKBBHROHkSHB%2FviIhEeUvCzFKLELRoWy6poZ27whdnrCSURTujkVViNsKI5a0xNEf2vW6xLXw%3D%3D) | Manage images |
| [docker images](https://link.segmentfault.com/?enc=nEGYkN9cTQH0t%2Fu1BrdtHg%3D%3D.GgK9H4aeSuHFKKQ1j4FMSvndGw2of5G0aCTSZUQvKApVzs%2BtkNTrVuR%2BSKGcrH45jXbAukdGWrW6f5EThZPTsA%3D%3D) | List images |
| [docker import](https://link.segmentfault.com/?enc=nSDclK26nSeDzesHDESF3w%3D%3D.gLc4WiWCzmmzPRb07kH2jqk6yMMQtMJQzvY2OkA4tbqv32iGimrC0jYzURFdZGEroh526KPUX0Kw3Q4H40uGVw%3D%3D) | Import the contents from a tarball to create a filesystem image |
| [docker info](https://link.segmentfault.com/?enc=X3gHvFHcotfDinGAqDimtg%3D%3D.pHsYmVn9kFznJUQ1OoN9%2Bynyo%2FQALl4CIaBEO5ubjv4koZ2Dz5iouDFH4LVA2yKcn0q%2BA5OXaeJQJB6xCYhdHA%3D%3D) | Display system-wide information |
| [docker inspect](https://link.segmentfault.com/?enc=ZVKZu5BE1ECURq48Fs9EOg%3D%3D.UyPryKWTcOa9LCD%2FVs%2BJTyH3zppCz%2BDcuQ2BeewCUYjECiImGT4vVNcDH5LvjxgvKNdqIyT9n5QMwF8gC6bdnA%3D%3D) | Return low-level information on Docker objects |
| [docker kill](https://link.segmentfault.com/?enc=CXYeKunk%2FQ%2F9vScMzDsc1Q%3D%3D.za%2BPuQqieYpWmK%2BPc7shc7vwhJlulTPyuOBdimNUAIOshIBU47DeMRcTxI6c%2B9HumMB4z1L2TCyF9kkkk3opeg%3D%3D) | Kill one or more running containers |
| [docker load](https://link.segmentfault.com/?enc=ZIrBzU5V%2BhgXh9s%2BlF%2Bxjw%3D%3D.eIJeSSzJlnkodVIbS9if0SZPmCdu6xDXpJHRFznweX%2BSCgCCVsW6%2BTkv6Lqej8Y4Uer2iy1251VTX8LTU2yP1A%3D%3D) | Load an image from a tar archive or STDIN |
| [docker login](https://link.segmentfault.com/?enc=hWx4rzbQnXNZdhmScngMbw%3D%3D.m4%2BZR1Bt5sYBWH0FlnF0EmquOfTU2PyXOqUwaw8dCkoR%2BvnZPOGdOT2sLvibIRL9WRUMNMw06nRsnqQG1sfYYg%3D%3D) | Log in to a Docker registry |
| [docker logout](https://link.segmentfault.com/?enc=cAbVFwoIWI2p2IjvpJB43w%3D%3D.UE431MHWh4U2w436%2F52wgvKmObRKPJNgr4CD0oNbZQzgHRKuuLPbcMW3bMw2Ys4Q1J1ujIhaVhNap11rtbJ1%2Fw%3D%3D) | Log out from a Docker registry |
| [docker logs](https://link.segmentfault.com/?enc=T2tVc217zkCvk9lRRwwv6A%3D%3D.jMH%2BC7boH1sQ9hv%2BAlM9xCUyouyhwTybK9ZabSqisoo%2BXDIsdl7w3FpEDae4Oq3NxYjBsXMJtwWhrv1q1Fve1w%3D%3D) | Fetch the logs of a container |
| [docker manifest](https://link.segmentfault.com/?enc=uvdNpkI5alDwXYqZ00oqaA%3D%3D.3QMWIRCJT1YCgZtJooSHNLdQqeyo6pv9LC6Oz5XqIsLfPYqowT5mslLcSm2gNNPyec5kY30xFEm17xjeCFImdw%3D%3D) | Manage Docker image manifests and manifest lists |
| [docker network](https://link.segmentfault.com/?enc=QVc60iWjbU60%2FIS0kjwqlA%3D%3D.sRPLW86MARsdI5nb2QOXXbnZvzFtXUYBVzCymTcsaQ1KmwlHe4OvP%2Fyit7XVZFpGH3HYfWLt0Y58sRjgVta1iQ%3D%3D) | Manage networks |
| [docker node](https://link.segmentfault.com/?enc=kWufUa6d4aiEHjvovEg36w%3D%3D.n5xERDJALwuzwhsVS%2Bpd4qU%2BnJlfzUa22ytHaUxmXxNEvpVr8t5RoD%2F9i8ifxFe9BucgKifb1%2Bg%2BEWEzMcyDJw%3D%3D) | Manage Swarm nodes |
| [docker pause](https://link.segmentfault.com/?enc=NaRIrO8EJvZCX9SiZBGgAQ%3D%3D.FDLBCtNQ2wBwJYg0%2Ftv0Xl58535QbWtEfO4d9sfkx3aAedJek%2BHNRKAeMqn55pg5YE1bIW%2B%2FyrELZgIUSqVinQ%3D%3D) | Pause all processes within one or more containers |
| [docker plugin](https://link.segmentfault.com/?enc=1EwNOSXc9jXiWbmPO06mxQ%3D%3D.DW%2BnDBjAsQUQL01gcJqcFu4QTET6gi3r3vkkxzQU5CaeotmVHbJ6%2B1wTpZ0T1mzkOTIfJV3HiE8ZMnI0fWSAxA%3D%3D) | Manage plugins |
| [docker port](https://link.segmentfault.com/?enc=2wcNoVhue508Y%2BvoXnvJjA%3D%3D.zAP708hhFU3RnXiPVzlnmcmsd7mAnNXIEMVBmtWxDpR%2Bc7m8M9zojaJvl7YNMGPK9%2Fg83rwG4QpmQCmd6hWatQ%3D%3D) | List port mappings or a specific mapping for the container |
| [docker ps](https://link.segmentfault.com/?enc=5HcUHYVgTkSeFWMA2ubAQA%3D%3D.Zt3s69kBPi7t0BlBLUZtTXqSPPVXLK5ho0fU8zwMTZYtmkI8h7lOMFjJ3%2BUhVsH4YmVVdx8lw6ETl9i2QP27SQ%3D%3D) | List containers |
| [docker pull](https://link.segmentfault.com/?enc=gMq%2Fpi35tOm%2Fz4IBLjDgRQ%3D%3D.LmQycLyZsbYai9y70yuPCiS55ysSCfi3PSwKXBgsWHjWZ%2BXOTEnqiu2BiITzH1QirbwShtjp1WAGUjLmnd11fg%3D%3D) | Pull an image or a repository from a registry |
| [docker push](https://link.segmentfault.com/?enc=n7mw0HTiflx7miJ%2F2kjkWg%3D%3D.qfGyO%2F3Cm3608HsQC8FtYDmLTsJ7VHjtXFxzEAHhynbhebNml87mWXdpVq3BIWh9v%2BolrRhhoQoBUfXcV5nBbQ%3D%3D) | Push an image or a repository to a registry |
| [docker rename](https://link.segmentfault.com/?enc=c3c0rnJSO5NIwR0vClGy0A%3D%3D.KfElnfykQ8FMlDyRIKkNWlv5deOTr0Dn3DBsbaPguafkP9oHtq29J%2BfUzpXtrIB95IQjjGG%2FRSMQK258N%2B4H7Q%3D%3D) | Rename a container |
| [docker restart](https://link.segmentfault.com/?enc=XDo8v1D5vizWAZt%2F4s7jww%3D%3D.BXZf%2Fauec%2BOMGeeYy9CjFfDsFu2kRQEwrSCFhFhBZPbqsxi8SP8tChImTUW1zS56npXRBi6gJsnMcfxhWBiMnQ%3D%3D) | Restart one or more containers |
| [docker rm](https://link.segmentfault.com/?enc=s8qGvgOGQys35t4C2do57w%3D%3D.eXc6C3EkP0VLKrJjZYDRadoXsLv3z7Wgc70iKrnXsKSLVk5FgvgjPo6VyUlmr9xtgDpsYh8Ht7G3os7LGaU21A%3D%3D) | Remove one or more containers |
| [docker rmi](https://link.segmentfault.com/?enc=s8VRuS%2B9YV6aokKs4KC6CA%3D%3D.4j%2BBZsBGa2UkKxUmEE7BJLWFkJt0cLj%2FOR08Z%2BGG1UORlPbSq0wKKW%2BxxFLulNwWKvyudYWh5SIEzfwejthMWA%3D%3D) | Remove one or more images |
| [docker run](https://link.segmentfault.com/?enc=KscT86Lpt8yjfqJ5uWEJ9w%3D%3D.NI33A%2BP8Pk%2F%2F%2Bfz2vLPYA6Q%2FPwD79htmSk0VreEgTGU4fJEnTLVo%2B45V%2BUocSqVtYe8VowHkar1HGMOXdSb%2BXg%3D%3D) | Run a command in a new container |
| [docker save](https://link.segmentfault.com/?enc=YZJ3%2BMQZy6CkWVeQpazvjw%3D%3D.N6OEgaYv6CgSn5oARib%2Bptb7lsKy%2FkcARIHbLF%2BgkhM%2BTcQz1l424V7R9QST0SBAccOEwG%2FCuhDACOTiFvFVpw%3D%3D) | Save one or more images to a tar archive (streamed to STDOUT by default) |
| [docker search](https://link.segmentfault.com/?enc=pIOn4OyKRdDOzl8ISyqGRg%3D%3D.onoGDK66CdTYMdw%2BzF0mReOIeVyOb9N1bKkTnNcQvYZgIVL4Eo4o4iKX%2BzuNcYoNLHp6NC0YNLBNlefJhtJPdQ%3D%3D) | Search the Docker Hub for images |
| [docker secret](https://link.segmentfault.com/?enc=3ldCnXaSBU4ue%2BJalZfaTg%3D%3D.XhbQRNQ72umQM%2BH5yc33tVkpRt4Bcnrw%2BQzs37iKle7iFOOI64ZglYE7tTnPJbSKLibiadfcwPAdDNLuPNx4mA%3D%3D) | Manage Docker secrets |
| [docker service](https://link.segmentfault.com/?enc=YuncbzmIgqOir0q00l1Taw%3D%3D.YiEL0JXEF3WHAQop%2Bvo7mGdeedzAyIq9Zo1lWc%2B0dWkLT5rpnov2bHGpM8Yedqxgg7SJaw3HA4okPUdJnbCWLQ%3D%3D) | Manage services |
| [docker stack](https://link.segmentfault.com/?enc=6GKntnIHP4lPLQ20OMPO1w%3D%3D.AMSb%2BVfJlu6bqLRxYTQ2mZhc3gwllUxP%2FzTcdAPLUveN4IrqIXUXBIqc23VootiEskETDEOke%2BzB0mu4lQd8pg%3D%3D) | Manage Docker stacks |
| [docker start](https://link.segmentfault.com/?enc=w4Jok7qqqb0YFbzX1ng1Vg%3D%3D.w80DypaGn61v99PrFKw7jLhcBuZjxjz%2Bx1f66%2Bruj3SScuWx6fr9NghtcPeC1EIrbOMJbfLGdIdWzl0wuYzJLg%3D%3D) | Start one or more stopped containers |
| [docker stats](https://link.segmentfault.com/?enc=Kuyt0bQjvI%2FMpiy1wPpvrw%3D%3D.HDgBF3%2BFxnFs4ZhLnEw2%2BSdIA3ovctZ8XumMD4a3KZNkL%2FIN%2FlMS1JUfPQH7ftLiuDAZ%2FONmfr0eAISEUj59Sw%3D%3D) | Display a live stream of container(s) resource usage statistics |
| [docker stop](https://link.segmentfault.com/?enc=C2umDkIV33iiHWVENJ4ymQ%3D%3D.T8VeMJ5qW7uDS7DdteqEuIe0WAruUvwI0b%2Fgy90j%2FqPLNOtKfqh%2FWtWiMkKy1V9RXCyg4lJZcVRkXQuzyoOIRQ%3D%3D) | Stop one or more running containers |
| [docker swarm](https://link.segmentfault.com/?enc=XCcYJm%2F2U7BsJhOEX%2B8FrA%3D%3D.qrTfdjcM3bTMn6NWM6ReOFjlvGFfvTZtTmzmvKYh%2B0MXIHyabU7cGCMFvw1nYORJTbfP62oJ6yQhc1GVeVDbTA%3D%3D) | Manage Swarm |
| [docker system](https://link.segmentfault.com/?enc=ClT4vJJ%2F8lpHgHqFqVcNFQ%3D%3D.6OoeKWTwVGz4DaFhpviAO0f%2Bn4pygkUjb50Qzz6eXBpyZVObbKp%2FsG6FGWq9AyAZ6LIIYSXq3PcTHZ5BDlZrDA%3D%3D) | Manage Docker |
| [docker tag](https://link.segmentfault.com/?enc=2xGYq%2B5oHJN8m333aTqDSw%3D%3D.lfu25PCvLK7QH%2FEvqHTbK9y8Q5A6%2FyzRWZgpBH1aULgg57ey5ACVUNX9JTwXHafB11Vmx577QDSY3NfQDCB0kg%3D%3D) | Create a tag TARGET\_IMAGE that refers to SOURCE\_IMAGE |
| [docker top](https://link.segmentfault.com/?enc=RNGGj8c0vCkV%2FVcHiKaacQ%3D%3D.SC5VM0GBwQ%2FV%2Fs7fiUaRXZ%2BLuHso%2Bko3wYlKbDM7CA0krwr2xdWo7rs8d7Hee3sjDCJn8DslmFTOTGCygAeR%2Fw%3D%3D) | Display the running processes of a container |
| [docker trust](https://link.segmentfault.com/?enc=5LyGdCzot5hJnvoOVUprdA%3D%3D.etFirTwQv1dJxZzzOTRaVCcvoRv3ryLgxwGhL1IBf4w6W%2B98skOnr8djhXbDRQPomJasv39iLpF67H%2BaqCWk6Q%3D%3D) | Manage trust on Docker images |
| [docker unpause](https://link.segmentfault.com/?enc=diW0Cxg6RvF84r574MXdWA%3D%3D.CrDa7YDM4udOkCIIPkFGKeENd2dRBx%2BMUJyRtOpYHh86opoNDXnOUMcRdJENomKit%2BxbqerhoW4vQTVhzrajWA%3D%3D) | Unpause all processes within one or more containers |
| [docker update](https://link.segmentfault.com/?enc=DjrjocdrStoi99NRYbtl2A%3D%3D.MQAA10KVl5zZw2qdIIdeQswLyhZEhvCaaFiuInSyw%2F9OLMwm7%2FP1o6B8lKRaSGq8Y59rPnYkk8wWlJGsX%2FtmuQ%3D%3D) | Update configuration of one or more containers |
| [docker version](https://link.segmentfault.com/?enc=d0eoB%2FAts79rClPVMukvOA%3D%3D.NG6b5aE1M9XeDi3sQpBNwNznAbeGe9rIjv3%2Flh5WUrbQscvZRxwnMTNHglGuBbOhffchydvG7smClZ8qGlYp9Q%3D%3D) | Show the Docker version information |
| [docker volume](https://link.segmentfault.com/?enc=sgENp387ZD%2Bs78h9LzQSkg%3D%3D.AMnvROwi82h97I6RoIJ3bEfNOpQH3hkTRdITjD2lw5ArhZ7v2ZR%2BAfa7nzyzZpekKCP6rcllv3DzfSygBRg02A%3D%3D) | Manage volumes |
| [docker wait](https://link.segmentfault.com/?enc=HJm2XMHsKm9Kn7EFESSg4Q%3D%3D.I4UOFWm0hXa9YzFfDktThLP2c58HZbmCYdmYarf8cOGijzaWMEIFu6QK1H9ICbALfKT5GTgcjaMWGzyseZlW1w%3D%3D) | Block until one or more containers stop, then print their exit codes |
> 官方阅读链接:[https://docs.docker.com/engine/reference/commandline/docker/](https://link.segmentfault.com/?enc=S2ceUllWkY%2F6slJ6fxR3PQ%3D%3D.vZIKWfT7ufeoyFpQ9N0gtEzZkwGbx3zH%2FJjgiZT%2FqvV8uEFqJJzSzdEcgCTa9oqCWq5fn5Fh2u%2BmQ4yRmkayJw%3D%3D)
### 5\. 进阶:仓库与软件安装的简化
还记得笔者在文章开头介绍的「镜像、容器和仓库」吗?Docker 的仓库用于存放镜像。我们可以从中心仓库下载镜像,也可以从自建仓库下载。同时,我们可以把制作好的镜像从本地推送到远程仓库。
首先,笔者先引入一个知识点:Docker 的镜像就是它的文件系统,一个镜像可以放在另外一个镜像的上层,那么位于下层的就是它的父镜像。所以,Docker 会存在很多镜像层,每个镜像层都是只读的,并且不会改变。当我们创建一个新的容器时,Docker 会构建出一个镜像栈,并在栈的最顶层添加一个读写层,如图所示。
![](https://img.kancloud.cn/7b/82/7b8298895c43361a8808e7d3d52733c1_610x862.jpg)
现在,我们可以通过`docker images` 命令查看本地的镜像。
~~~ebnf
docker images
~~~
查询结果,如图所示。
![](https://img.kancloud.cn/21/0f/210fba4d65523d6f2d0de7d10777e4cc_641x71.jpg)
这里,对几个名词解释一下含义。
* REPOSITORY:仓库名称。
* TAG: 镜像标签,其中 lastest 表示最新版本。注意的是,一个镜像可以有多个标签,那么我们就可以通过标签来管理有用的版本和功能标签。
* IMAGE ID :镜像唯一ID。
* CREATED :创建时间。
* SIZE :镜像大小。
那么,如果第一次我们通过`docker pull centos:latest` 拉取镜像,那么当我们执行 `docker run -p 80 --name web -i -t centos /bin/bash` 时,它就不会再去远程获取了,因为本机中已经安装该镜像,所以 Docker 会直接创建一个新的容器并启动该程序。
事实上,官方已经提供了安装好 Nginx 的镜像,我们可以直接使用。现在,我们通过拉取镜像的方式重新构建一个 Web 服务器。首先,我们通过`docker search` 来查找镜像。我们获取到 Nginx 的镜像清单。
~~~ebnf
docker search nginx
~~~
补充一下,我们也可以通过访问 Docker Hub ([https://hub.docker.com/](https://link.segmentfault.com/?enc=o3c0AWSVx1g9vB%2BN4ldXig%3D%3D.i5mxxIK5v5b06PsLc4gzWJeDSL3MF%2F4dz5lK5trZzmo%3D))搜索仓库,那么 star 数越多,说明它越靠谱,可以放心使用。
![](https://img.kancloud.cn/a1/d3/a1d32a56ea042804a9caff39b8eb9333_2872x1292.jpg)
现在,我们通过`docker pull nginx` 拉取最新的 Nginx 的镜像。当然,我们也可以通过 `docker pull nginx:latest` 来操作。
~~~ebnf
docker pull nginx
~~~
然后,我们创建并运行一个容器。与前面不同的是,我们通过`-d` 选项告诉 Docker 在后台运行容器的守护进程。并且,通过`8080:80` 告诉 Docker 8080 端口是对外开放的端口,80 端口对外开放的端口映射到容器里的端口号。
~~~apache
docker run -p 8080:80 -d --name nginx nginx
~~~
我们再通过 `docker ps -a` 来查看,发现容器已经后台运行了,并且后台执行了 nginx 命令,并对外开放 8080 端口。
![](https://img.kancloud.cn/bb/e4/bbe4d672f820e4af639aeb43c74e5374_958x80.jpg)
因此,通过浏览器访问 `http://127.0.0.1:8080` 即可。
![](https://img.kancloud.cn/6d/13/6d1358247c2befc189e53946dfe7ee0f_747x214.jpg)
### 6\. 其他选择,使用替代注册服务器
Docker Hub 不是软件的唯一来源,我们也可以切换到国内的其他替代注册服务器,例如阿里云。我们可以登录 [https://cr.console.aliyun.com](https://link.segmentfault.com/?enc=OVOPPohEfpdJQ4IMe2tnnw%3D%3D.ilhUyBFJ89PxX2UkaH3bfgNhX1Oyrn3KkNXTkzDXKYA%3D) 搜索,并拉取公开的镜像。
![](https://img.kancloud.cn/40/6c/406cf99660221a7dc31190e1fefdd852_2870x1254.jpg)
![](https://img.kancloud.cn/63/7f/637fdd16da1cc57c25b0d653ade270fd_2860x1294.jpg)
现在,我们输入`docker pull` 命令进行拉取。
~~~vim
docker pull registry.cn-hangzhou.aliyuncs.com/qp_oraclejava/orackejava:8u172_DCEVM_HOTSWAPAGEN_JCE
~~~
这里,笔者继续补充一个知识点:注册服务器的地址。事实上,注册服务器的地址是有一套规范的。完整格式是:仓库主机/容器短名\[:标签\]。这里,仓库主机是 registry.cn-hangzhou.aliyuncs.com,用户名是 qp\_oraclejava,容器短名是 orackejava,标签名是 8u172\_DCEVM\_HOTSWAPAGEN\_JCE。事实上,我们上面通过 `docker pull centos:latest` 拉取镜像,相当于 `docker pull registry.hub.docker.com/centos:latest` 。
## 三、构建我的镜像
通过上面的学习,笔者相信你已经对 Docker 使用有了一个大致的了解,就好比我们通过 VMware 安装了一个系统,并让它跑了起来,那么我们就可以在这个 Linux 系统(CentOS 或者 Ubuntu ) 上面工作我们想要的任何事情。事实上,我们还会经常把我们安装好的 VMware 系统进行快照备份并实现克隆来满足我们下次快速的复制。这里,Docker 也可以构建定制内容的 Docker 镜像,例如上面我们使用官方提供的安装好 Nginx 的 Docker 镜像。注意的是,我们通过基于已有的基础镜像,在上面添加镜像层的方式构建新镜像而已。
总结一下,Docker 提供自定义镜像的能力,它可以让我们保存对基础镜像的修改,并再次使用。那么,我们就可以把操作系统、运行环境、脚本和程序打包在一起,并在宿主机上对外提供服务。
Docker 构建镜像有两种方式,一种方式是使用 `docker commit` 命令,另外一种方式使用`docker build` 命令和`Dockerfile` 文件。其中,不推荐使用 `docker commit` 命令进行构建,因为它没有使得整个流程标准化,因此,在企业的中更加推荐使用 `docker build` 命令和 `Dockerfile` 文件来构建我们的镜像。我们使用`Dockerfile` 文件可以让构建镜像更具备可重复性,同时保证启动脚本和运行程序的标准化。
### 1\. 构建第一个 Dockerfile 文件
现在,我们继续实战。这里,我们把一开始搭建的 Web 服务器构建一个镜像。首先,我们需要创建一个空的 Dokcerfile 文件。
~~~bash
mkdir dockerfile_test
cd dockerfile_test/
touch Dockerfile
nano Dockerfile
~~~
紧接着,我们需要编写一个 Dockerfile 文件,代码清单如下
~~~awk
FROM centos:7
MAINTAINER LiangGzone "lianggzone@163.com"
RUN rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
RUN yum install -y nginx
EXPOSE 80
~~~
最后,我们通过`docker build` 命令进行构建。
~~~ebnf
docker build -t="lianggzone/nginx_demo:v1" .
~~~
现在, 我们来通过 `docker images` 看下我们的新镜像吧。
![](https://img.kancloud.cn/b0/68/b068561a2fb26ff4ec9e7c9b3770230a_1059x145.jpg)
### 2\. 理解 Dockerfile 全过程
哇,我们通过编写一个 Dockerfile 文件顺利构建了一个新的镜像。这个过程简单得让人无法相信。现在,让我们来理解一下这个全过程吧。首先, `FROM centos:7` 是 Dockerfile 必须要的第一步,它会从一个已经存在的镜像运行一个容器,换句话说,Docker 需要依赖于一个基础镜像进行构建。这里,我们指定 centos 作为基础镜像,它的版本是 7 (CentOS 7)。然后,我们通过 `MAINTAINER LiangGzone "lianggzone@163.com"` 指定该镜像的作者是 LiangGzone,邮箱是 lianggzone@163.com。这有助于告诉使用者它的作者和联系方式。接着,我们执行两个 RUN 指令进行 Nginx 的下载安装,最后通过 `EXPOSE 80` 暴露 Dokcer 容器的 80 端口。注意的是,Docker 的执行顺序是从上而下执行的,所以我们要明确整个流程的执行顺序。除此之外,Docker 在执行每个指令之后都会创建一个新的镜像层并且进行提交。
我们使用 `docker build` 命令进行构建,指定`- t` 告诉 Docker 镜像的名称和版本。注意的是,如果没有指定任何标签,Docker 将会自动为镜像设置一个 lastest 标签。还有一点,我们最后还有一个`.` 是为了让 Docker 到当前本地目录去寻找 Dockerfile 文件。注意的是,Docker 会在每一步构建都会将结果提交为镜像,然后将之前的镜像层看作缓存,因此我们重新构建类似的镜像层时会直接复用之前的镜像。如果我们需要跳过,可以使用 `--no-cache` 选项告诉 Docker 不进行缓存。
### 3\. Dockerfile 指令详解
Dockerfile 提供了非常多的指令。笔者这里特别整理了一份清单,建议收藏查看。
![](https://img.kancloud.cn/fd/51/fd51c40867cd1e7d43489210872cefd3_2202x838.jpg)
> 官方地址:[https://docs.docker.com/engine/reference/builder/#usage](https://link.segmentfault.com/?enc=LYtyl0eignVs6%2FngiHh%2Bhw%3D%3D.k5GtoYaBg3mLeGVnkNdOmjMUqIgt2GHC5G2LirFqzA15G%2B%2Be%2BmVX%2B03cyFUJXVjgHu8f9C%2BgPZpGhQhhVa62Zg%3D%3D)
#### 指令辨别一:RUN、CMD、ENTRYPOINT
`RUN` 、`CMD` 、`ENTRYPOINT` 三个指令的用途非常相识,不同在于,`RUN` 指令是在容器被构建时运行的命令,而`CMD` 、 `ENTRYPOINT` 是启动容器时执行 shell 命令,而 `RUN` 会被`docker run` 命令覆盖,但是 `ENTRYPOINT` 不会被覆盖。事实上,`docker run` 命令指定的任何参数都会被当作参数再次传递给 `ENTRYPOINT` 指令。`CMD` 、 `ENTRYPOINT` 两个指令之间也可以一起使用。例如,我们 可以使用 `ENTRYPOINT` 的 exec 形式设置固定的默认命令和参数,然后使用任一形式的`CMD` 来设置可能更改的其他默认值。
~~~css
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
~~~
#### 指令辨别二:ADD、COPY
`ADD` 、`COPY` 指令用法一样,唯一不同的是 `ADD` 支持将归档文件(tar, gzip, bzip2, etc)做提取和解压操作。注意的是,`COPY` 指令需要复制的目录一定要放在 Dockerfile 文件的同级目录下。
### 4\. 将镜像推送到远程仓库
#### 远程仓库:Docker Hub
镜像构建完毕之后,我们可以将它上传到 Docker Hub 上面。首先,我们需要通过`docker login` 保证我们已经登录了。紧接着,我们使用`docker push` 命令进行推送。
~~~armasm
docker push lianggzone/nginx_demo:v1
~~~
这里,我们了解下它的使用,格式是`docker push [OPTIONS] NAME[:TAG]` ,其中,笔者设置 NAME 是 lianggzone/nginx\_demo,TAG 是 v1。 (笔者注:推送 Docker Hub 速度很慢,耐心等待) 最后,上传完成后访问:[https://hub.docker.com/u/lianggzone](https://link.segmentfault.com/?enc=NS4l7eYONYnbiWtMMF890g%3D%3D.abA3jJtAjm90GI1A6NXokARTajq3pZ%2FnU6Og4rZKiYi05mtRy04wdVDn07AGGZV8)/,如图所示。
![](https://img.kancloud.cn/d3/26/d326e71f450646e3559d1f49a43c49b4_2674x1138.jpg)
#### 远程仓库:阿里云
同时,我们也可以使用国内的仓库,比如阿里云。首先,在终端中输入访问凭证,登录 Registry 实例。如果你不知道是哪个,可以访问 [https://cr.console.aliyun.com/cn-hangzhou/instances/credentials](https://link.segmentfault.com/?enc=QpGTBoXndE2nTrec1vx9RA%3D%3D.6nX5fz6NiChWTgPhwiWDKNKgdZgI%2FiPzJoB1ahJjGALNnFHXenb9hDj3eIkbT0ZY%2B3b2GgUtwPuByycoYZm%2FAQ%3D%3D)。
~~~stylus
docker login --username=帐号 registry.cn-hangzhou.aliyuncs.com
~~~
现在,将镜像推送到阿里云镜像仓库。其中,`docker tag [IMAGE_ID] registry.cn-hangzhou.aliyuncs.com/[命名空间]/[镜像名称]:[版本]` 和`docker push registry.cn-hangzhou.aliyuncs.com/[命名空间]/[镜像名称]:[版本]` 命令的使用如下所示。
~~~gradle
docker tag 794c07361565 registry.cn-hangzhou.aliyuncs.com/lianggzone/nginx_demo:v1
docker push registry.cn-hangzhou.aliyuncs.com/lianggzone/nginx_demo:v1
~~~
最后,上传完成后访问:[https://cr.console.aliyun.com/cn-hangzhou/instances/repositories](https://link.segmentfault.com/?enc=wdTcZfABjsTg5PoDp5J36g%3D%3D.vd1NCKejTWSc%2BSLeEJl5PMPisksxadFOco9yny0x%2BAY52OgmvHThNGEXtMDmmT1JnPw3Q7tyRGQs5NDaUMWuF%2FK%2B35L%2FUVAM6OQ%2FoOmuNJM%3D),如图所示。
![](https://img.kancloud.cn/97/76/977688f6059e003515f934e12afbed18_2874x1188.jpg)
### 5. Dockerfile 的 Github 源码地址
这里,附上我整理的 Dockerfile 的仓库。后面,笔者会陆续更新用到的一些常用文件,欢迎 star 关注。
> [https://github.com/lianggzone/dockerfile-images](https://link.segmentfault.com/?enc=rYXa4qBUf0Wx8igwqd%2By0Q%3D%3D.B5MTnRML4mwJgmfopPcmYK3DiELBA5e9kgAi%2BW3WIGEgJ%2BlDNsnACl6O5Q0Ba9HW)
## 附:参考资料
* 《Docker实战》
* 《第一本Docker书》
* [Docker 命令参考文档](https://link.segmentfault.com/?enc=gyqEUC%2FD%2B2DtN8xpua2Zmg%3D%3D.kBPHn%2BXWnoC%2Ba%2Fv3uFt6uMhR2JVchRHHJ9jk5%2BBOoLRw9tUjNj3YUw2M31iaIp9kGjTRwcYU99ffn%2BTuXOPi2my%2BugoTxgLX3o8dvH%2BbmzoFRQEHHInf4JfWDOct%2FHKX)
* [Dockerfile 镜像构建参考文档](https://link.segmentfault.com/?enc=53AZ0gq%2FgQZ7IndYEPq5fA%3D%3D.HZJ60WLawCItRJGnE0%2BNHAnEd0619ykVZuoCc%2FuxaC650Cdk78dp9xcsyJqLXAkSpw3BSzg1Rib38XTtkcugyufoVcvspBfv%2BFYaBKcXrz3gH1vzx8Cr8PpOoheD7Fvc)
(完,转载请注明作者及出处。)
## 写在末尾
【服务端思维】:我们一起聊聊服务端核心技术,探讨一线互联网的项目架构与实战经验。同时,拥有众多技术大牛的「后端圈」大家庭,期待你的加入,一群同频者,一起成长,一起精进,打破认知的局限性。
- php开发
- 常用技巧
- 字符数组对象
- php换行替换,PHP替换回车换行符的三种方法
- PHP 数组转字符串,与字符串转数组
- php将img中的宽高删除,PHP删除HTML中宽高样式的详解
- php去除换行(回车换行)的三种方法
- php 过滤word 样式
- php如何设置随机数
- 2个比较经典的PHP加密解密函数分享
- php怎么去除小数点后多余的0
- php中判断是一维数组还是二维数组的解决方案
- php 获取数组中出现次数最多的值(重复最多的值)与出现的次数
- PHP过滤掉换行符、特殊空格、制表符等
- PHP中json_endoce转义反斜杠的问题
- PHP过滤Emoji表情和特殊符号的方法
- PHP完美的提取链接正则
- php很牛的图片采集
- 日期处理
- php 获取今日、昨日、上周、本月的起始时间戳和结束时间戳的方法非常简单
- PHP指定时间戳/日期加一天,一年,一周,一月
- 使用php 获取时间今天明天昨天时间戳的详解
- php获得当月的节假日函数(包含周末,年度节假日)
- PHP获取本月起始和截止时间戳
- php 获取每月开始结束时间,php 获取指定月份的开始结束时间戳
- PHP获取今天,昨天,本月,上个月,本年 起始时间戳
- php、mysql查询当天,本周,本月的用法
- php获取两个时间戳之间相隔多少天多少小时多少分多少秒
- 毫秒级时间戳和日期格式转换
- php-倒计时
- 请求提交上传
- php+put+post,Curl和PHP-如何通过PUT,POST,GET通过curl传递json
- PHP put提交和获取数据
- PHP curl put方式上传文件
- 数据导入导出
- PHP快速导入大量数据到数据库的方法
- PHP快速导出百万级数据到CSV或者EXCEL文件
- PHP解析大型Excel表格的库:box/spout
- PHP导入(百万级)Excel表格数据
- PHP如何切割excel大文件
- 使用 PHP_XLSXWriter 代替 PHPExcel 10W+ 数据秒级导出
- 安装php扩展XLSXWriter
- 解决php导入excel表格时获取日期变成浮点数的方法
- xml处理
- PHP XML和数组互相转换
- php解析xml字符串
- php 生成vcf通讯录
- 文件操作相关
- php获取文件后缀的9种方法
- PHP判断远程文件是否存在
- PHP获取文件修改时间,访问时间,inode修改时间
- php获取远程文件大小教程
- php 读取文件并以文件方式下载
- php 把数字转化为大写中文
- 请求响应
- PHP 获取当前访问的URL
- 压缩
- php生成zip压缩包
- PHPMailer
- 整理PHPMailer 发送邮件 邮件内容为html 可以添加多个附件等
- 通达oa
- OA管理员密码忘了怎么办,这里教你分分钟搞定…
- 跨域
- php解决多站点跨域
- php设置samesite cookie,有效防止CSRF
- Chrome 配置samesite=none方式
- Cookie 的 SameSite 属性
- 图片
- php pdf首页截图,PHP_PHP中使用Imagick读取pdf并生成png缩略图实例,pdf生成png首页缩略图
- PHP -- 七牛云 在线视频 获取某一帧作为封面图
- PHP图片压缩方法
- 如何解决PHP curl或file_get_contents下载图片损坏或无法打开的问题
- php远程下载文章中图片并保存源文件名不变
- 详解PHP如何下载采集图片到本地(附代码实例)
- php如何将webp格式图片转为jpeg
- PHP获取远程图片的宽高和体积大小
- php 软件版本号比较
- 使用PHP通过SMTP发送电邮
- 常用正则表达式
- php如何用正则表达式匹配中文
- 用于分割字符串的 PHP preg_match_all 正则表达式
- 性能优化
- php.ini配置调优
- PHP 几种常见超时的设置方法
- PHP函数in_array、array_key_exists和isset效率分析
- php array push 和array_merge 效率谁高,php 通过array_merge()和array+array合并数组的区别和效率比较...
- php 两个数组取交集、并集、差集
- 设置PHP最大连接数及php-fpm 高并发 参数调整
- 小工具
- php 获取代码执行时间和消耗的内存
- PHP如何判断某项扩展是否开启
- centos7.x下php 导出扩展 XLSXWriter 安装
- php生成mysql数据库字典
- PHP 实现 word/excel/ppt 转换为 PDF
- composer的使用
- showdoc sqlite3 找回管理员密码
- php怎么将数组转为xml
- PHP抖音最新视频提取代码
- yii
- Yii2 如何获取Header参数?
- swoole
- Linux下搭建swoole服务的基本步骤
- 相关学习资料
- 带你学习swoole_process详解
- 按照官方文档 在win10下安装 docker for windows easyswoole镜像 挂载目录
- php常用框架
- Hyperf
- 常用算法PHP版
- thinkphp6
- TP6 事件绑定、监听、订阅
- Thinkphp 模板中输出HTML的变量
- Thinkphp6(操作SQL数据库)
- thinkphp6 mysql查询语句对于为null和为空字符串给出特定值处理
- Thinkphp 6 - 连接配置多个数据库并实现自由切换(详细过程及实例demo)
- TP框架中的Db::name 和 dB::table 以及 db('') 的区别
- thinkphp6.0模型篇之模型的软删除
- thinkphp6自定义日志驱动,增加显示全部请求信息
- 其他系统
- 微擎数据库字段字典
- Flutter实现微信支付和iOS IAP支付
- Flutter上线项目实战——苹果内购
- PHP接入苹果支付
- 调试
- php如何获取当前脚本所有加载的文件
- php跟踪所有调用方法,日志方法
- 解析phpstorm + xdebug 远程断点调试
- PHP XDEBUG调试 PHPSTORM配置
- 异常处理
- PHP 出现 502 解决方案
- php 语法解析错误 syntax error unexpected namespace T_NAMESPACE
- Composer 安装与使用
- 数据库相关
- php pdo怎么设置utf8
- php 如何根据最新聊天对用户进行排序
- php lic&fpm
- 让php程序在linux后台执行
- PHPcli模式和fpm模式优缺点在哪里?
- 运行模式
- php运行模式之cli模式
- 自己库
- php批量获取所有公众号粉丝openid
- 地图
- php 判断点在多边形内,php百度地图api判断地址是否在多边形区域内
- PHP,Mysql-根据一个给定经纬度的点,进行附近地点查询
- MySQL 根据经纬度查找排序
- PHP+MySQL获取坐标范围内的数据
- 【百度地图】删除指定覆盖物
- 百度地图多点+画连接线+数字标注
- laravel5.8
- laravel5.8(四)引入自定义常量文件及公共函数文件
- Lumen 查询执行SQL
- 使你的 Laravel 项目模块化
- Laravel 多条件 AND , OR条件组合查询
- Laravel 查询 多个or或者and条件
- laravel redis操作大全
- laravel中外部定义whereIn的用法和where中使用in
- lumen5.8
- 创建laravel5.8 lumen前后台api项目--记录请求和响应日志
- Laravel和Lumen开启SQL日志记录
- Laravel 5.8 常用操作(路径+日志+分页+其他操作)
- 升级php7.4 laravel lumen报错Trying to access array offset on value of type null
- Laravel 任务调度(计划任务,定时任务)
- laravel的command定时任务时间的设置
- Laravel任务调度的简单使用
- laravel单数据库执行事务和多数据库执行事务
- laravel中锁以及事务的简单使用
- 申请其他相关
- 小程序地理位置接口申请
- PHP高并发
- php 高并发下 秒杀处理思路
- 记录 PHP高并发 商品秒杀 问题的 Redis解决方案
- thinkphp3.2
- thinkphp3.2 数据库 AND OR连缀使用
- laravel
- laravel的联表查询with方法的使用
- laravel获取请求路由对应的控制器和方法
- Laravel 模型关联建立与查询
- Laravel多表(3张表以上)with[]关联查询,对关联的模型做条件查询(has,跟join一样结果 )
- Laravel模型属性的隐藏属性、显示属性和临时暴露隐藏属性用法介绍
- aravel获取当前的url以及当前的基础域名方法汇总
- Laravel 模型实现多库查询或者多表映射
- 关于 Laravel 的 with 多表查询问题
- Laravel 模型过滤(Filter)设计
- 懒加载、预加载、with()、load() 傻傻分不清楚?
- laravel模型$castsl属性
- Laravel Query Builder 复杂查询案例:子查询实现分区查询 partition by
- Laravel 模型关联、关联查询、预加载使用实例
- laravel 中with关联查询限定查询字段
- laravel 原生字段查询 whereRaw 和 where(DB::raw(''))
- lavarel - where条件分组查询(orWhere)
- 通过 Laravel 查询构建器实现复杂的查询语句
- 两个结果集合并成一个
- Laravel 对某一列进行筛选然后求和 sum()
- laravel怎么优雅的拼接where,处理whereIn与where数组查询的问题
- laravel查询时判断是否存在数据
- laravel中的whereNull和whereNotNull
- laravel框架中的子查询
- Laravel框架中 orwhere 多条件查询的使用
- Laravel中where的高级使用方法
- laravel复杂的数据库查询(事例)
- laravel多条件查询方法(and,or嵌套查询)
- Laravel 的 where or 查询
- Laravel 进行where 多个or和and的条件查询可用
- laravel Middleware 中间件 $next($request) 报错不执行问题
- 数据库
- mysql
- mysql联合索引(复合索引)详解
- MYSQL 清空表和截断表
- MySQL快速生成大量测试数据(100万、1000万、1亿)
- 提高mysql千万级大数据SQL查询优化30条经验(Mysql索引优化注意)
- MySQL常用命令
- MySQL(三)|《千万级大数据查询优化》第一篇:创建高性能的索引
- MySQL(一)|性能分析方法、SQL性能优化和MySQL内部配置优化
- MySQL(二)|深入理解MySQL的四种隔离级别及加锁实现原理
- MySQL(四)|《千万级大数据查询优化》第一篇:创建高性能的索引(补充)
- MySQL(五)|《千万级大数据查询优化》第二篇:查询性能优化(1)
- MySQL(六)|《千万级大数据查询优化》第二篇:查询性能优化(2)
- MySQL(七)|MySQL分库分表的那点事
- Mysql索引优化 Mysql通过索引提升查询效率(第二棒)
- MySQL查询的性能优化(查询缓存、排序跟索引)
- 【总结】MySQL数据库
- MySQL存储引擎、事务日志并发访问以及隔离级别
- 技巧
- 数据库 SQL查询重复记录 方法
- 替换数据库中某个字段中的部分字符
- mysql开启bin log 并查看bin log日志(linux)
- 分表分区
- 千万级别数据的mysql数据表优化
- MYSQL百万级数据,如何优化
- MySQL备份和恢复
- MySQL间隙锁死锁问题
- 小技巧
- 基础
- MySQL中sql_mode参数
- mysql数据库异常
- this is incompatible with sql_mode=only_full_group_by
- mysql安全
- MySQL数据库被比特币勒索及安全调整
- MongoDB
- sql查询
- MYSQL按时间段分组查询当天,每小时,15分钟数据分组
- 高级
- 基于 MySQL + Tablestore 分层存储架构的大规模订单系统实践-架构篇
- 数据库安全
- 服务器被黑,MySQL 数据库遭比特币勒索!该如何恢复?
- 数千台MySQL数据库遭黑客比特币勒索,该怎么破?
- MySQL 数据库规范
- MySQL数据库开发的36条铁律
- Elasticsearch
- 安装与配置
- ElasticSearch关闭重启命令
- 设置ES默认分词器IK analyzer
- 查询
- elasticsearch 模糊查询不分词,实现 mysql like
- elasticSearch多条件高级检索语句,包含多个must、must_not、should嵌套示例,并考虑nested对象的特殊检索
- elasticSearch按字段普通检索,结果高亮
- Elasticsearch 如何实现查询/聚合不区分大小写?
- 索引更新&刷新
- refresh与批量操作的效率
- Elasticsearch 删除type
- 分词器
- ElasticSearch最全分词器比较及使用方法
- 异常错误
- 解决ES因内存不足而无法查询的错误,Data too large, data for [<http_request>]
- linux
- 基本知识
- CentOS7.5 通过wget下载文件到指定目录
- 【CentOS】vi命令
- centos7查看硬盘使用情况
- CentOS7 查看目录大小
- Centos 7下查看当前目录大小及文件个数
- 普通用户sudo\su 到root免密码
- 普通用户切换到root用户下的免密配置方法
- linux 获取进程启动参数,linux查看进程启动及运行时间
- Linux 查看进程
- linux删除文件后不释放磁盘的问题
- Linux查找大文件命令
- linux 如何关闭正在执行的php脚本
- linux三剑客(grep、sed、awk)基本使用
- centos 卸载软件
- centos查看内存、cpu占用、占用前10,前X
- Centos 查看系统状态
- 异常
- 问题解决:Failed to download metadata for repo ‘appstream‘: Cannot prepare internal mirrorlist:...
- php相关
- centos 安装phpize
- Centos7.2下phpize安装php扩展
- 切换版本
- 运营工具
- 资深Linux运维工程师常用的10款软件/工具介绍
- 一款良心的终端连接工具
- 六款Linux常用远程连接工具介绍,看看哪一款最适合你
- Finalshell
- Linux Finalshell连接centos7和文件无显示问题
- WSL2:我在原生的Win10玩转Linux系统
- MobaXterm
- 运维
- linux服务器上定时自动备份数据库,并保留最新5天的数据
- Centos系统开启及关闭端口
- CentOS7开放和关闭端口命令
- Linux中查看所有正在运行的进程
- 防火墙firewall-cmd命令详解
- centos 7.8阿里云服务器挂载 数据盘
- Linux Finalshell连接centos7和文件无显示问题
- Centos7系统端口被占用问题的解决方法
- vi
- 如何在Vim/Vi中复制,剪切和粘贴
- 命令
- [Linux kill进程] kill 进程pid的使用详解
- 备份还原
- Linux的几种备份、恢复系统方式
- Linux系统全盘备份方法
- 相关软件安装
- linux下 lua安装
- python
- 升级pip之后出现sys.stderr.write(f“ERROR: {exc}“)
- lua
- centos源码部署lua-5.3
- deepin
- deepin20.6设置默认的root密码
- 任务相关
- 宝塔定时任务按秒执行
- CentOS 7 定时任务 crontab 入门
- centos7定时任务crontab
- Linux下定时任务的查看及取消
- Linux(CentOS7)定时执行任务Crond详细说明
- Linux 查看所有定时任务
- linux查看所有用户定时任务
- Linux 定时任务(超详细)
- 防火墙
- Centos7开启防火墙及特定端口
- CentOS防火墙操作:开启端口、开启、关闭、配置
- 生成 SSH 密钥(windows+liunx)
- 阿里云,挂载云盘
- 前端
- layui
- layui多文件上传
- layer.msg()弹框,弹框后继续运行
- radio取值
- layui-数据表格排序
- Layui select选择框添加搜索选项功能
- 保持原来样式
- layui表格单元如何自动换行
- layui-laydate时间日历控件使用方法详解
- layui定时刷新数据表格
- layer 延时设置
- layer.open 回调函数
- 【Layui内置方法】layer.msg延时关闭msg对话框(代码案例)
- layui多图上传图片顺序错乱及重复上传解决
- layer.confirm关闭弹窗
- vue
- Vue跨域解决方法
- vue 4.xx.xx版本降级至2.9.6
- vue-cli 2.x升级到3.x版本, 和3.x降级到2.x版本命令
- 最新版Vue或者指定版本
- Vue2.6.11按需模块安装配置
- jQuery
- jQuery在页面加载时动态修改图片尺寸的方法
- jquery操作select(取值,设置选中)
- 日历
- FullCalendar中文文档:Event日程事件
- js
- JS 之 重定向
- javascript截取video视频第一帧作为封面方案
- HTML <video> preload 属性
- jQuery使用ajax提交post数据
- JS截取视频靓丽的帧作为封面
- H5案例分享:移动端touch事件判断滑屏手势的方向
- JS快速获取图片宽高的方法
- win
- Windows环境下curl的使用
- Cygwin
- Windows下安装Cygwin及apt-cyg
- Cygwin 安装、CMake 安装
- mklink命令 详细使用
- Nginx
- Nginx高级篇-性能优化
- Nginx常用命令(Linux)
- linux+docker+nginx如何配置环境并配置域名访问
- Nginx的启动(start),停止(stop)命令
- linux 查看nginx 安装路径
- 安装配置
- Linux 查看 nginx 安装目录和配置文件路径
- 【NGINX入门】3.Nginx的缓存服务器proxy_cache配置
- thinkphp6.0 伪静态失效404(win下)
- 深入
- nginx rewrite及多upstream
- Nginx负载均衡(upstream)
- 专业术语
- 耦合?依赖?耦合和依赖的关系?耦合就是依赖
- PHP常用六大设计模式
- 高可用
- 分布式与集群
- Nginx 实践案例:反向代理单台web;反向代理多组web并实现负载均衡
- 容器
- Docker
- 30 分钟快速入门 Docker 教程
- linux查看正在运行的容器,说说Docker 容器常用命令
- Windows 安装Docker至D盘
- 配置
- win10 快速搭建 lnmp+swoole 环境 ,部署laravel6 与 swoole框架laravel-s项目1
- win10 快速搭建 lnmp+swoole 环境 ,部署laravel6 与 swoole框架laravel-s项目2
- docker 容器重命名
- Linux docker常用命令
- 使用
- docker 搭建php 开发环境 添加扩展redis、swoole、xdebug
- docker 单机部署redis集群
- Docker 退出容器不停止容器运行 并重新进入正在运行的容器
- 进入退出docker容器
- Docker的容器设置随Docker的启动而启动
- 使用异常处理
- docker容器中bash: vi: command not found
- OCI runtime exec failed: exec failed:解决方法
- docker启动容器慢,很慢,特别慢的坑
- 解决windows docker开发thinkphp6启动慢的问题
- 【Windows Docker】docker挂载解决IO速度慢的问题
- Docker的网络配置,导致Docker使用网路很慢的问题及解决办法
- golang工程部署到docker容器
- Docker 容器设置自启动
- 如何优雅地删除Docker镜像和容器(超详细)
- 5 个好用的 Docker 图形化管理工具
- Docker 可能会用到的命令
- Kubernetes
- 消息队列
- RabbitMQ
- php7.3安装使用rabbitMq
- Windows环境PHP如何使用RabbitMQ
- RabbitMQ学习笔记:4369、5672、15672、25672默认端口号修改
- Window10 系统 RabbitMQ的安装和简单使用
- RabbitMQ默认端口
- RabbitMQ可视化界面登录不了解决方案
- RocketMQ
- Kafka
- ActiveMQ
- mqtt
- phpMQTT详解以及处理使用过程中内存耗死问题
- MQTT--物联网(IoT)消息推送协议
- php实现mqtt发布/发送 消息到主题
- Mqtt.js 的WSS链接
- emqx
- 如何在 PHP 项目中使用 MQTT
- emqx 修改dashboard 密码
- 其他
- Windows 系统中单机最大TCP的连接数详解
- EMQX
- Linux系统EMQX设置开机自启
- Centos7 EMQX部署
- docker安装 EMQX 免费版 docker安装并配置持久化到服务器
- 实时数仓
- 网易云音乐基于 Flink + Kafka 的实时数仓建设实践
- 实时数仓-基于Flink1.11的SQL构建实时数仓探索实践
- 安全
- 网站如何保护用户的密码
- 关于web项目sessionID欺骗的问题
- php的sessionid可以伪造,不要用来做防刷新处理了
- DVWA-Weak Session IDs (弱会话)漏洞利用方式
- 保证接口数据安全的10种方案
- cookie和session的窃取
- 万能密码漏洞
- 黑客如何快速查找网站后台地址方法整理
- 网站后台万能密码/10大常用弱口令
- 万能密码漏洞02
- 大多数网站后台管理的几个常见的安全问题注意防范
- token可以被窃取吗_盗取token
- token被劫持[token被劫持如何保证接口安全性]
- PHP给后台管理系统加安全防护机制的一些方案
- php - 重新生成 session ID
- 隐藏响应中的server和X-Powered-By
- PHP会话控制之如何正确设置session_name
- Session攻击001
- PHP防SQL注入代码,PHP 预防CSRF、XSS、SQL注入攻击
- php25个安全实践
- php架构师 系统管理员必须知道的PHP安全实践
- 版本控制
- Linux服务器关联Git,通过执行更新脚本实现代码同步
- PHP通过exec执行git pull
- git 在linux部署并从windows上提交代码到linux
- git上传到linux服务器,git一键部署代码到远程服务器(linux)
- linux更新git命令,使用Linux定时脚本更新服务器的git代码
- git異常
- 如何解决remote: The project you were looking for could not be found
- git status显示大量文件修改的原因是什么
- PHPstorm批量修改文件换行符CRLF为LF
- git使用
- git常用命令大全
- centos git保存账户密码
- GIT 常用命令
- git怎样还原修改
- Git 如何放弃所有本地修改的方法
- Git忽略文件模式改变
- git: 放弃所有本地修改
- Git三种方法从远程仓库拉取指定的某一个分支
- 杂七杂八
- h5视频
- H5浏览器支持播放格式:H264 AVCA的MP4格式,不能转换为mpeg-4格式,
- iOS无法播放MP4视频文件的解决方案 mp4视频iphone播放不了怎么办
- h5点播播放mp4视频遇到的坑,ios的h5不能播放视频等
- 【Linux 并发请求数】支持多少并发请求数
- Linux下Apache服务器并发优化
- 缓存
- redis
- Linux启动PHP的多进程任务与守护redis队列
- 重启redis命令
- golang