Docker学习总结(6)——通过 Docker 化一个博客网站来开启我们的 Docker 之旅

news/2024/5/18 23:14:14/文章来源:https://blog.csdn.net/weixin_33796177/article/details/93559653

通过 Docker 化一个博客网站来开启我们的 Docker 之旅

通过 Docker 化一个博客网站来开启我们的 Docker 之旅

这篇文章包含 Docker 的基本概念,以及如何通过创建一个定制的 Dockerfile 来 Docker 化Dockerize一个应用。

Docker 是一个过去两年来从某个 idea 中孕育而生的有趣技术,公司组织们用它在世界上每个角落来部署应用。在今天的文章中,我将讲述如何通过“Docker 化Dockerize”一个现有的应用,来开始我们的 Docker 之旅。这里提到的应用指的就是这个博客!

什么是 Docker?

当我们开始学习 Docker 基本概念时,让我们先去搞清楚什么是 Docker 以及它为什么这么流行。Docker 是一个操作系统容器管理工具,它通过将应用打包在操作系统容器中,来方便我们管理和部署应用。

容器 vs. 虚拟机

容器和虚拟机并不完全相似,它是另外一种提供操作系统虚拟化的方式。它和标准的虚拟机还是有所不同。

标准的虚拟机一般会包括一个完整的操作系统、操作系统软件包、最后还有一至两个应用。这都得益于为虚拟机提供硬件虚拟化的管理程序。这样一来,一个单一的服务器就可以将许多独立的操作系统作为虚拟客户机运行了。

容器和虚拟机很相似,它们都支持在单一的服务器上运行多个操作环境,只是,在容器中,这些环境并不是一个个完整的操作系统。容器一般只包含必要的操作系统软件包和一些应用。它们通常不会包含一个完整的操作系统或者硬件的虚拟化。这也意味着容器比传统的虚拟机开销更少。

容器和虚拟机常被误认为是两种对立的技术。虚拟机采用一个物理服务器来提供全功能的操作环境,该环境会和其余虚拟机一起共享这些物理资源。容器一般用来隔离一个单一主机上运行的应用进程,以保证隔离后的进程之间不能相互影响。事实上,容器和 BSD Jails以及chroot进程的相似度,超过了和完整虚拟机的相似度。

Docker 在容器之上提供了什么

Docker 本身不是一个容器运行环境,事实上,只是一个与具体实现无关的容器技术,Docker 正在努力支持 Solaris Zones[1] 和BSD Jails[2]。Docker 提供了一种管理、打包和部署容器的方式。虽然一定程度上,虚拟机多多少少拥有这些类似的功能,但虚拟机并没有完整拥有绝大多数的容器功能,即使拥有,这些功能用起来都并没有 Docker 来的方便或那么完整。

现在,我们应该知道 Docker 是什么了,然后,我们将从安装 Docker,并部署一个公开的预构建好的容器开始,学习 Docker 是如何工作的。

从安装开始

默认情况下,Docker 并不会自动被安装在您的计算机中,所以,第一步就是安装 Docker 软件包;我们的教学机器系统是 Ubuntu 14.0.4,所以,我们将使用 Apt 软件包管理器,来执行安装操作。

  1. # apt-get install docker.io

  2. Reading package lists... Done

  3. Building dependency tree

  4. Reading state information... Done

  5. The following extra packages will be installed:

  6. aufs-tools cgroup-lite git git-man liberror-perl

  7. Suggested packages:

  8. btrfs-tools debootstrap lxc rinse git-daemon-run git-daemon-sysvinit git-doc

  9. git-el git-email git-gui gitk gitweb git-arch git-bzr git-cvs git-mediawiki

  10. git-svn

  11. The following NEW packages will be installed:

  12. aufs-tools cgroup-lite docker.io git git-man liberror-perl

  13. 0 upgraded, 6 newly installed, 0 to remove and 0 not upgraded.

  14. Need to get 7,553 kB of archives.

  15. After this operation, 46.6 MB of additional disk space will be used.

  16. Do you want to continue? [Y/n] y

为了检查当前是否有容器运行,我们可以执行docker命令,加上ps选项

  1. # docker ps

  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

docker命令中的ps功能类似于 Linux 的ps命令。它将显示可找到的 Docker 容器及其状态。由于我们并没有启动任何 Docker 容器,所以命令没有显示任何正在运行的容器。

部署一个预构建好的 nginx Docker 容器

我比较喜欢的 Docker 特性之一就是 Docker 部署预先构建好的容器的方式,就像yumapt-get部署包一样。为了更好地解释,我们来部署一个运行着 nginx web 服务器的预构建容器。我们可以继续使用docker命令,这次选择run选项。

  1. # docker run -d nginx

  2. Unable to find image 'nginx' locally

  3. Pulling repository nginx

  4. 5c82215b03d1: Download complete

  5. e2a4fb18da48: Download complete

  6. 58016a5acc80: Download complete

  7. 657abfa43d82: Download complete

  8. dcb2fe003d16: Download complete

  9. c79a417d7c6f: Download complete

  10. abb90243122c: Download complete

  11. d6137c9e2964: Download complete

  12. 85e566ddc7ef: Download complete

  13. 69f100eb42b5: Download complete

  14. cd720b803060: Download complete

  15. 7cc81e9a118a: Download complete

docker命令的run选项,用来通知 Docker 去寻找一个指定的 Docker 镜像,然后启动运行着该镜像的容器。默认情况下,Docker 容器运行在前台,这意味着当你运行docker run命令的时候,你的 shell 会被绑定到容器的控制台以及运行在容器中的进程。为了能在后台运行该 Docker 容器,我们使用了-d(detach)标志。

再次运行docker ps命令,可以看到 nginx 容器正在运行。

  1. # docker ps

  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

  3. f6d31ab01fc9 nginx:latest nginx -g 'daemon off 4 seconds ago Up 3 seconds 443/tcp, 80/tcp desperate_lalande

从上面的输出信息中,我们可以看到正在运行的名为desperate_lalande的容器,它是由nginx:latest image(LCTT 译注: nginx 最新版本的镜像)构建而来得。

Docker 镜像

镜像是 Docker 的核心特征之一,类似于虚拟机镜像。和虚拟机镜像一样,Docker 镜像是一个被保存并打包的容器。当然,Docker 不只是创建镜像,它还可以通过 Docker 仓库发布这些镜像,Docker 仓库和软件包仓库的概念差不多,它让 Docker 能够模仿yum部署软件包的方式来部署镜像。为了更好地理解这是怎么工作的,我们来回顾docker run执行后的输出。

  1. # docker run -d nginx

  2. Unable to find image 'nginx' locally

我们可以看到第一条信息是,Docker 不能在本地找到名叫 nginx 的镜像。这是因为当我们执行docker run命令时,告诉 Docker 运行一个基于 nginx 镜像的容器。既然 Docker 要启动一个基于特定镜像的容器,那么 Docker 首先需要找到那个指定镜像。在检查远程仓库之前,Docker 首先检查本地是否存在指定名称的本地镜像。

因为系统是崭新的,不存在 nginx 镜像,Docker 将选择从 Docker 仓库下载之。

  1. Pulling repository nginx

  2. 5c82215b03d1: Download complete

  3. e2a4fb18da48: Download complete

  4. 58016a5acc80: Download complete

  5. 657abfa43d82: Download complete

  6. dcb2fe003d16: Download complete

  7. c79a417d7c6f: Download complete

  8. abb90243122c: Download complete

  9. d6137c9e2964: Download complete

  10. 85e566ddc7ef: Download complete

  11. 69f100eb42b5: Download complete

  12. cd720b803060: Download complete

  13. 7cc81e9a118a: Download complete

这就是第二部分输出信息显示给我们的内容。默认情况下,Docker 会使用 Docker Hub[3] 仓库,该仓库由 Docker 公司维护。

和 Github 一样,在 Docker Hub 创建公共仓库是免费的,私人仓库就需要缴纳费用了。当然,部署你自己的 Docker 仓库也是可以的,事实上只需要简单地运行docker run registry命令就行了。但在这篇文章中,我们的重点将不是讲解如何部署一个定制的注册服务。

关闭并移除容器

在我们继续构建定制容器之前,我们先清理一下 Docker 环境,我们将关闭先前的容器,并移除它。

我们利用docker命令和run选项运行一个容器,所以,为了停止同一个容器,我们简单地在执行docker命令时,使用kill选项,并指定容器名。

  1. # docker kill desperate_lalande

  2. desperate_lalande

当我们再次执行docker ps,就不再有容器运行了

  1. # docker ps

  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

但是,此时,我们这是停止了容器;虽然它不再运行,但仍然存在。默认情况下,docker ps只会显示正在运行的容器,如果我们附加-a(all) 标识,它会显示所有运行和未运行的容器。

  1. # docker ps -a

  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

  3. f6d31ab01fc9 5c82215b03d1 nginx -g 'daemon off 4 weeks ago Exited (-1) About a minute ago desperate_lalande

为了能完整地移除容器,我们在用docker命令时,附加rm选项。

  1. # docker rm desperate_lalande

  2. desperate_lalande

虽然容器被移除了;但是我们仍拥有可用的nginx镜像(LCTT 译注:镜像缓存)。如果我们重新运行docker run -d nginx,Docker 就无需再次拉取 nginx 镜像即可启动容器。这是因为我们本地系统中已经保存了一个副本。

为了列出系统中所有的本地镜像,我们运行docker命令,附加images选项。

  1. # docker images

  2. REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE

  3. nginx latest 9fab4090484a 5 days ago 132.8 MB

构建我们自己的镜像

截至目前,我们已经使用了一些基础的 Docker 命令来启动、停止和移除一个预构建好的普通镜像。为了“Docker 化(Dockerize)”这篇博客,我们需要构建我们自己的镜像,也就是创建一个 Dockerfile

在大多数虚拟机环境中,如果你想创建一个机器镜像,首先,你需要建立一个新的虚拟机、安装操作系统、安装应用,最后将其转换为一个模板或者镜像。但在 Docker 中,所有这些步骤都可以通过 Dockerfile 实现全自动。Dockerfile 是向 Docker 提供构建指令去构建定制镜像的方式。在这一章节,我们将编写能用来部署这个博客的定制 Dockerfile。

理解应用

我们开始构建 Dockerfile 之前,第一步要搞明白,我们需要哪些东西来部署这个博客。

这个博客本质上是由一个静态站点生成器生成的静态 HTML 页面,这个生成器是我编写的,名为 hamerkop。这个生成器很简单,它所做的就是生成该博客站点。所有的代码和源文件都被我放在了一个公共的Github 仓库[4]。为了部署这篇博客,我们要先从 Github 仓库把这些内容拉取下来,然后安装Python和一些Python模块,最后执行hamerkop应用。我们还需要安装nginx,来运行生成后的内容。

截止目前,这些还是一个简单的 Dockerfile,但它却给我们展示了相当多的 Dockerfile 语法[5])。我们需要克隆 Github 仓库,然后使用你最喜欢的编辑器编写 Dockerfile,我选择vi

  1. # git clone https://github.com/madflojo/blog.git

  2. Cloning into 'blog'...

  3. remote: Counting objects: 622, done.

  4. remote: Total 622 (delta 0), reused 0 (delta 0), pack-reused 622

  5. Receiving objects: 100% (622/622), 14.80 MiB | 1.06 MiB/s, done.

  6. Resolving deltas: 100% (242/242), done.

  7. Checking connectivity... done.

  8. # cd blog/

  9. # vi Dockerfile

FROM - 继承一个 Docker 镜像

第一条 Dockerfile 指令是FROM指令。这将指定一个现存的镜像作为我们的基础镜像。这也从根本上给我们提供了继承其他 Docker 镜像的途径。在本例中,我们还是从刚刚我们使用的nginx开始,如果我们想从头开始,我们可以通过指定ubuntu:latest来使用UbuntuDocker 镜像。

  1. ## Dockerfile that generates an instance of http://bencane.com

  2. FROM nginx:latest

  3. MAINTAINER Benjamin Cane <ben@bencane.com>

除了FROM指令,我还使用了MAINTAINER,它用来显示 Dockerfile 的作者。

Docker 支持使用#作为注释,我将经常使用该语法,来解释 Dockerfile 的部分内容。

运行一次测试构建

因为我们继承了 nginxDocker镜像,我们现在的 Dockerfile 也就包括了用来构建nginx镜像的Dockerfile[6] 中所有指令。这意味着,此时我们可以从该 Dockerfile 中构建出一个 Docker 镜像,然后以该镜像运行一个容器。虽然,最终的镜像和nginx镜像本质上是一样的,但是我们这次是通过构建 Dockerfile 的形式,然后我们将讲解 Docker 构建镜像的过程。

想要从 Dockerfile 构建镜像,我们只需要在运行 docker命令的时候,加上build选项。

  1. # docker build -t blog /root/blog

  2. Sending build context to Docker daemon 23.6 MB

  3. Sending build context to Docker daemon

  4. Step 0 : FROM nginx:latest

  5. ---> 9fab4090484a

  6. Step 1 : MAINTAINER Benjamin Cane <ben@bencane.com>

  7. ---> Running in c97f36450343

  8. ---> 60a44f78d194

  9. Removing intermediate container c97f36450343

  10. Successfully built 60a44f78d194

上面的例子,我们使用了-t(tag)标识给镜像添加“blog”的标签。实质上我们就是在给镜像命名,如果我们不指定标签,就只能通过 Docker 分配的Image ID来访问镜像了。本例中,从 Docker 构建成功的信息可以看出,Image ID值为60a44f78d194

除了-t标识外,我还指定了目录/root/blog。该目录被称作“构建目录”,它将包含 Dockerfile,以及其它需要构建该容器的文件。

现在我们构建成功了,下面我们开始定制该镜像。

使用 RUN 来执行 apt-get

用来生成 HTML 页面的静态站点生成器是用 Python语言编写的,所以,在 Dockerfile 中需要做的第一件定制任务是安装 Python。我们将使用 Apt 软件包管理器来安装 Python 软件包,这意味着在 Dockerfile 中我们要指定运行apt-get updateapt-get install python-dev;为了完成这一点,我们可以使用RUN指令。

  1. ## Dockerfile that generates an instance of http://bencane.com

  2. FROM nginx:latest

  3. MAINTAINER Benjamin Cane <ben@bencane.com>

  4. ## Install python and pip

  5. RUN apt-get update

  6. RUN apt-get install -y python-dev python-pip

如上所示,我们只是简单地告知 Docker 构建镜像的时候,要去执行指定的apt-get命令。比较有趣的是,这些命令只会在该容器的上下文中执行。这意味着,即使在容器中安装了python-devpython-pip,但主机本身并没有安装这些。说的更简单点,pip命令将只在容器中执行,出了容器,pip命令不存在。

还有一点比较重要的是,Docker 构建过程中不接受用户输入。这说明任何被RUN指令执行的命令必须在没有用户输入的时候完成。由于很多应用在安装的过程中需要用户的输入信息,所以这增加了一点难度。不过我们例子中,RUN命令执行的命令都不需要用户输入。

安装 Python 模块

Python安装完毕后,我们现在需要安装 Python 模块。如果在 Docker 外做这些事,我们通常使用pip命令,然后参考我的博客 Git 仓库中名叫requirements.txt的文件。在之前的步骤中,我们已经使用git命令成功地将 Github 仓库“克隆”到了/root/blog目录;这个目录碰巧也是我们创建Dockerfile的目录。这很重要,因为这意味着 Docker 在构建过程中可以访问这个 Git 仓库中的内容。

当我们执行构建后,Docker 将构建的上下文环境设置为指定的“构建目录”。这意味着目录中的所有文件都可以在构建过程中被使用,目录之外的文件(构建环境之外)是不能访问的。

为了能安装所需的 Python 模块,我们需要将requirements.txt从构建目录拷贝到容器中。我们可以在Dockerfile中使用COPY指令完成这一需求。

  1. ## Dockerfile that generates an instance of http://bencane.com

  2. FROM nginx:latest

  3. MAINTAINER Benjamin Cane <ben@bencane.com>

  4. ## Install python and pip

  5. RUN apt-get update

  6. RUN apt-get install -y python-dev python-pip

  7. ## Create a directory for required files

  8. RUN mkdir -p /build/

  9. ## Add requirements file and run pip

  10. COPY requirements.txt /build/

  11. RUN pip install -r /build/requirements.txt

Dockerfile中,我们增加了3条指令。第一条指令使用RUN在容器中创建了/build/目录。该目录用来拷贝生成静态 HTML 页面所需的一切应用文件。第二条指令是COPY指令,它将requirements.txt从“构建目录”(/root/blog)拷贝到容器中的/build/目录。第三条使用RUN指令来执行pip命令;安装requirements.txt文件中指定的所有模块。

当构建定制镜像时,COPY是条重要的指令。如果在 Dockerfile 中不指定拷贝文件,Docker 镜像将不会包含requirements.txt 这个文件。在 Docker 容器中,所有东西都是隔离的,除非在 Dockerfile 中指定执行,否则容器中不会包括所需的依赖。

重新运行构建

现在,我们让 Docker 执行了一些定制任务,现在我们尝试另一次 blog 镜像的构建。

  1. # docker build -t blog /root/blog

  2. Sending build context to Docker daemon 19.52 MB

  3. Sending build context to Docker daemon

  4. Step 0 : FROM nginx:latest

  5. ---> 9fab4090484a

  6. Step 1 : MAINTAINER Benjamin Cane <ben@bencane.com>

  7. ---> Using cache

  8. ---> 8e0f1899d1eb

  9. Step 2 : RUN apt-get update

  10. ---> Using cache

  11. ---> 78b36ef1a1a2

  12. Step 3 : RUN apt-get install -y python-dev python-pip

  13. ---> Using cache

  14. ---> ef4f9382658a

  15. Step 4 : RUN mkdir -p /build/

  16. ---> Running in bde05cf1e8fe

  17. ---> f4b66e09fa61

  18. Removing intermediate container bde05cf1e8fe

  19. Step 5 : COPY requirements.txt /build/

  20. ---> cef11c3fb97c

  21. Removing intermediate container 9aa8ff43f4b0

  22. Step 6 : RUN pip install -r /build/requirements.txt

  23. ---> Running in c50b15ddd8b1

  24. Downloading/unpacking jinja2 (from -r /build/requirements.txt (line 1))

  25. Downloading/unpacking PyYaml (from -r /build/requirements.txt (line 2))

  26. <truncated to reduce noise>

  27. Successfully installed jinja2 PyYaml mistune markdown MarkupSafe

  28. Cleaning up...

  29. ---> abab55c20962

  30. Removing intermediate container c50b15ddd8b1

  31. Successfully built abab55c20962

上述输出所示,我们可以看到构建成功了,我们还可以看到另外一个有趣的信息---> Using cache。这条信息告诉我们,Docker 在构建该镜像时使用了它的构建缓存。

Docker 构建缓存

当 Docker 构建镜像时,它不仅仅构建一个单独的镜像;事实上,在构建过程中,它会构建许多镜像。从上面的输出信息可以看出,在每一“步”执行后,Docker 都在创建新的镜像。

  1. Step 5 : COPY requirements.txt /build/

  2. ---> cef11c3fb97c

上面片段的最后一行可以看出,Docker 在告诉我们它在创建一个新镜像,因为它打印了Image ID:cef11c3fb97c。这种方式有用之处在于,Docker能在随后构建这个blog镜像时将这些镜像作为缓存使用。这很有用处,因为这样, Docker 就能加速同一个容器中新构建任务的构建流程。从上面的例子中,我们可以看出,Docker 没有重新安装python-devpython-pip包,Docker 则使用了缓存镜像。但是由于 Docker 并没有找到执行mkdir命令的构建缓存,随后的步骤就被一一执行了。

Docker 构建缓存一定程度上是福音,但有时也是噩梦。这是因为决定使用缓存或者重新运行指令的因素很少。比如,如果requirements.txt文件发生了修改,Docker 会在构建时检测到该变化,然后 Docker 会重新执行该执行那个点往后的所有指令。这得益于 Docker 能查看requirements.txt的文件内容。但是,apt-get命令的执行就是另一回事了。如果提供 Python 软件包的Apt仓库包含了一个更新的 python-pip 包;Docker 不会检测到这个变化,转而去使用构建缓存。这会导致之前旧版本的包将被安装。虽然对python-pip来说,这不是主要的问题,但对使用了存在某个致命攻击缺陷的软件包缓存来说,这是个大问题。

出于这个原因,抛弃 Docker 缓存,定期地重新构建镜像是有好处的。这时,当我们执行 Docker 构建时,我简单地指定--no-cache=True即可。

部署博客的剩余部分

Python 软件包和模块安装后,接下来我们将拷贝需要用到的应用文件,然后运行hamerkop应用。我们只需要使用更多的COPYRUN指令就可完成。

  1. ## Dockerfile that generates an instance of http://bencane.com

  2. FROM nginx:latest

  3. MAINTAINER Benjamin Cane <ben@bencane.com>

  4. ## Install python and pip

  5. RUN apt-get update

  6. RUN apt-get install -y python-dev python-pip

  7. ## Create a directory for required files

  8. RUN mkdir -p /build/

  9. ## Add requirements file and run pip

  10. COPY requirements.txt /build/

  11. RUN pip install -r /build/requirements.txt

  12. ## Add blog code nd required files

  13. COPY static /build/static

  14. COPY templates /build/templates

  15. COPY hamerkop /build/

  16. COPY config.yml /build/

  17. COPY articles /build/articles

  18. ## Run Generator

  19. RUN /build/hamerkop -c /build/config.yml

现在我们已经写出了剩余的构建指令,我们再次运行另一次构建,并确保镜像构建成功。

  1. # docker build -t blog /root/blog/

  2. Sending build context to Docker daemon 19.52 MB

  3. Sending build context to Docker daemon

  4. Step 0 : FROM nginx:latest

  5. ---> 9fab4090484a

  6. Step 1 : MAINTAINER Benjamin Cane <ben@bencane.com>

  7. ---> Using cache

  8. ---> 8e0f1899d1eb

  9. Step 2 : RUN apt-get update

  10. ---> Using cache

  11. ---> 78b36ef1a1a2

  12. Step 3 : RUN apt-get install -y python-dev python-pip

  13. ---> Using cache

  14. ---> ef4f9382658a

  15. Step 4 : RUN mkdir -p /build/

  16. ---> Using cache

  17. ---> f4b66e09fa61

  18. Step 5 : COPY requirements.txt /build/

  19. ---> Using cache

  20. ---> cef11c3fb97c

  21. Step 6 : RUN pip install -r /build/requirements.txt

  22. ---> Using cache

  23. ---> abab55c20962

  24. Step 7 : COPY static /build/static

  25. ---> 15cb91531038

  26. Removing intermediate container d478b42b7906

  27. Step 8 : COPY templates /build/templates

  28. ---> ecded5d1a52e

  29. Removing intermediate container ac2390607e9f

  30. Step 9 : COPY hamerkop /build/

  31. ---> 59efd1ca1771

  32. Removing intermediate container b5fbf7e817b7

  33. Step 10 : COPY config.yml /build/

  34. ---> bfa3db6c05b7

  35. Removing intermediate container 1aebef300933

  36. Step 11 : COPY articles /build/articles

  37. ---> 6b61cc9dde27

  38. Removing intermediate container be78d0eb1213

  39. Step 12 : RUN /build/hamerkop -c /build/config.yml

  40. ---> Running in fbc0b5e574c5

  41. Successfully created file /usr/share/nginx/html//2011/06/25/checking-the-number-of-lwp-threads-in-linux

  42. Successfully created file /usr/share/nginx/html//2011/06/checking-the-number-of-lwp-threads-in-linux

  43. <truncated to reduce noise>

  44. Successfully created file /usr/share/nginx/html//archive.html

  45. Successfully created file /usr/share/nginx/html//sitemap.xml

  46. ---> 3b25263113e1

  47. Removing intermediate container fbc0b5e574c5

  48. Successfully built 3b25263113e1

运行定制的容器

成功的一次构建后,我们现在就可以通过运行docker命令和run选项来运行我们定制的容器,和之前我们启动 nginx 容器一样。

  1. # docker run -d -p 80:80 --name=blog blog

  2. 5f6c7a2217dcdc0da8af05225c4d1294e3e6bb28a41ea898a1c63fb821989ba1

我们这次又使用了-d(detach)标识来让Docker在后台运行。但是,我们也可以看到两个新标识。第一个新标识是--name,这用来给容器指定一个用户名称。之前的例子,我们没有指定名称,因为 Docker 随机帮我们生成了一个。第二个新标识是-p,这个标识允许用户从主机映射一个端口到容器中的一个端口。

之前我们使用的基础 nginx镜像分配了80端口给 HTTP 服务。默认情况下,容器内的端口通道并没有绑定到主机系统。为了让外部系统能访问容器内部端口,我们必须使用-p标识将主机端口映射到容器内部端口。上面的命令,我们通过-p 8080:80语法将主机80端口映射到容器内部的80端口。

经过上面的命令,我们的容器看起来成功启动了,我们可以通过执行docker ps核实。

  1. # docker ps

  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

  3. d264c7ef92bd blog:latest nginx -g 'daemon off 3 seconds ago Up 3 seconds 443/tcp, 0.0.0.0:80->80/tcp blog

总结

截止目前,我们拥有了一个运行中的定制 Docker 容器。虽然在这篇文章中,我们只接触了一些 Dockerfile 指令用法,但是我们还是要学习所有的指令。我们可以检查 Docker's reference page[7] 来获取所有的 Dockerfile 指令用法,那里对指令的用法说明得很详细。

另一个比较好的资源是 Dockerfile Best Practices page[8],它有许多构建定制 Dockerfile 的最佳练习。有些技巧非常有用,比如战略性地组织好 Dockerfile 中的命令。上面的例子中,我们将articles目录的COPY指令作为 Dockerfile 中最后的COPY指令。这是因为articles目录会经常变动。所以,将那些经常变化的指令尽可能地放在最后面的位置,来最优化那些可以被缓存的步骤。

转载于:https://www.cnblogs.com/zhanghaiyang/p/7213031.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_797350.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

dedecms网站迁移时记得将安装目录放空 附迁移的正确方法

这段时间在赶一些新项目&#xff0c;我们建站一般都在本地服务器搭建起来&#xff0c;测试得差不多了才传到网上&#xff0c;这样对蜘蛛也相对友好一些&#xff0c;要不然改来改去变化太大给搜索引擎的第一印象很不好。但是由于本地环境和服务器环境还是有一些差别&#xff0c;…

listctrl 优化_留学教育类整站SEO优化公司_官网SEO优化外包费用

原标题&#xff1a;留学教育类整站SEO优化公司_官网SEO优化外包费用百度营销凭借强大的用户产品优势&#xff0c;每天数十亿次搜索请求、超过1亿用户浏览百度信息流、800亿次定位服务请求&#xff0c;为客户提供全系列产品广告资源覆盖用户生活全场景。百度搜索seo搜索优化具体…

我的网站搭建 (第六天) Ckeditor编辑器

2019独角兽企业重金招聘Python工程师标准>>> 富文本编辑器&#xff0c;Rich Text Editor, 简称 RTE, 是一种可内嵌于浏览器&#xff0c;所见即所得的文本编辑器&#xff0c;这是百度百科的对富文本编辑器的解释。我们可以借助富文本编辑器&#xff0c;编辑出来一个包…

什么是SEM?SEM是否包括SEO?

什么是SEM&#xff1f;SEM是否包括SEO&#xff1f; 在最近一次营销专业人士和有兴趣了解数字营销的人聚会上&#xff0c;我很惊讶于有人要求我确认他们对“SEM”的理解是准确的。 虽然这个术语本身看起来很基本&#xff0c;但这个问题并不是一个糟糕的问题&#xff0c;因为这个…

23.模拟登录cookies请求速询网站数据

23.模拟登录cookies请求速询网站数据 采集速询网站数据&#xff1a;网站地址&#xff1a;http://www.suxun0752.com/index.html网站是需要账号登录才给返回信息的&#xff0c;我这里是直接拿的登录后的cookies请求的数据&#xff0c;cookies我也给了注释&#xff0c;没做深层的…

域名添加cdn_优化网站-设置内容分发cdn和对象存储cos

刚开始接触花了不少时间去弄&#xff0c;通过搜网上资料&#xff0c;才解决问题。以腾讯云为例&#xff0c;为什么要用腾讯云&#xff0c;因为CDN 用户每月均可享受10GB免费流量包&#xff0c;接入加速域名后于次月1号发放至您的账户。还有新开通 CDN 的用户还会在开通后的6个月…

html漂亮的表格模板+背景_App开发主题响应式网站着陆页模板

哈喽&#xff01;大家好&#xff0c;这里公众号&#xff0c;Adobe素材助手。App开发主题响应式网站着陆页模板&#xff0c;用于应用程序站点。它是干净&#xff0c;现代和创造性的设计适合所有类型的应用程序风格的网站。这个模板是创造性和专业性的完美结合&#xff0c;所有部…

10个留美必备生活网站

不少同学习惯了天朝各种方便的互联网服务&#xff0c;一到美国往往感到不适应&#xff0c;其实美国也有很多提供类似服务的网站。今天小编就给你做一个大盘点。帮助你在美国也能轻松享受和国内类似的服务。1.Yelp 美国最大的点评网站民以食为天&#xff0c;今天我们首先要介绍的…

html颜色渐变配色方案,css网站推荐 渐变色配色方案 - 小俊学习网

渐变色彩搭配方案的酷站&#xff0c;推荐2个渐变色方案的网站。无论网页配色还是设计人员都可以参考这些美丽的色彩。UIgradients – 美丽的UI渐变色分享站 并可转成CSS代码通过渐变彩色滤镜实现很多漂亮的效果&#xff0c;然而用什么渐变颜色才好呢&#xff1f;可以看看今天为…

大型网站技术架构(四)网站的高性能架构

2019独角兽企业重金招聘Python工程师标准>>> 网站性能是客观的指标&#xff0c;可以具体体现到响应时间、吞吐量、并发数、性能计数器等技术指标。 1、性能测试指标 1.1 响应时间 指应用执行一个操作需要的时间&#xff0c;指从发出请求到最后收到响应数据所需要的时…

大型网站技术架构(三)架构核心要素

2019独角兽企业重金招聘Python工程师标准>>> 所谓架构&#xff0c;一种通俗的说法就是“最高层次的规划&#xff0c;难以改变的决定”&#xff0c;这些规划和决定奠定了事物未来发展的方向和最终的蓝图。 而软件架构即“有关软件整体结构与组件的抽象描述&#xff0…

【读书笔记《Bootstrap 实战》】6.单页营销网站

我们已经掌握了很多实用 Bootstrap 的重要技能。现在&#xff0c;是时候拿出更多的创意来帮助客户实现他们全方位在线营销的愿望了。此次将带领大家做一个漂亮的单页高端营销网站。 主要任务如下&#xff1a; □ 一个大型介绍性传送带图片展示区&#xff0c;配有自定义的响应式…

【JavaWeb开发】初步实现网站应用钉钉扫码登录

写在前面&#xff1a;如果你还不知道钉钉是什么&#xff0c;就赶紧问问Google。当然&#xff0c;这篇博客是用流水线的形式完成钉钉扫码登录。 第一步&#xff0c;看官方文档 网站应用钉钉扫码登录开发指南&#xff08;钉钉官网&#xff09; 如果你想要通过用户扫码获取到他的…

大型网站技术架构(四)网站的高性能架构

2019独角兽企业重金招聘Python工程师标准>>> 网站性能是客观的指标&#xff0c;可以具体体现到响应时间、吞吐量、并发数、性能计数器等技术指标。 1、性能测试指标 1.1 响应时间 指应用执行一个操作需要的时间&#xff0c;指从发出请求到最后收到响应数据所需要的时…

大型网站技术架构(七)网站的可扩展性架构

2019独角兽企业重金招聘Python工程师标准>>> 扩展性是指对现有系统影响最小的情况下&#xff0c;系统功能可持续扩展或提升的能力。 设计网站可扩展架构的核心思想是模块化&#xff0c;并在此基础上&#xff0c;降低模块间的耦合性&#xff0c;提供模块的复用性。模…

使用apache2在ubuntu下搭建简易网站(新手小白适用)

使用apache2在ubuntu下搭建简易网站 写在开头 本文章适合有一点linux基础但是不会网站搭建的小白&#xff0c;这里使用的网页是我之前写的一个作业&#xff0c;所以大家就不要嫌丑啦~~ 正文 本文使用阿里云云服务器进行部署 安装apache2 安装前先更新下软件 sudo apt upda…

苹果cms模板_万词无限模板站群黑帽SEO利器

万词无限模板排名站群&#xff0c;端口站群,无限模板,关键词,可做百度搜狗360各大引擎。100万流量利器&#xff0c;强悍无与伦比。无需任何推送&#xff0c;全自动收录&#xff0c;动态轮链池&#xff0c;内部有秒收课程霸屏关键词技巧。程序自带蜘蛛池功能无需任何辅助蜘蛛池&…

Nginx从入门到实战(七):定时器动态切换nginx配置-实现网站自动启停

背景&#xff1a; 有些网络由于某种特殊需求&#xff0c;需要每日在指定时间内开放&#xff0c;在其余时间展示“系统正在维护中…”的页面。 基于类似需求&#xff0c;最好的当然是定时自动处理了&#xff0c;省去人工处理的麻烦&#xff1b; 一、整体思路 1、设计2个nginx.…

一个网站的LOGO

今天董事长叫我去谈了话&#xff0c;有了一个网站的构想于是就先做一个LOGO也来了&#xff0c;好久没有做美工方面的东东了希望这个LOGO能用上&#xff0c;把网站做起来像我这种人天生就是为做网站的董事长也说以前让我们做那些&#xff0c;对我们来说也是和自己的专长搭不上现…

我要自学网polyworks_四大适合年轻人自学的网站!知乎超100万人推荐,自学改变人生...

在这个互联网时代&#xff0c;想要学点什么东西&#xff0c;上网搜一搜就有&#xff0c;但网上的资源五花八门&#xff0c;看得人眼花缭乱&#xff0c;想要找到高质量又免费的自学资源还真不是见容易的事&#xff01;不过别着急&#xff0c;今天就来跟大家分享几个质量杠杠的自…