过去的咱们,当业务发展须要部署新的应用时,DevOps 小伙伴一般会去买一台服务器,可是殊不知道这个新应用具体须要多高的配置,每每都会形成资源浪费。html
当虚拟机出现后,它可让咱们在一台服务器上运行多个应用,可是却有一个缺陷。每一个 VM 须要运行一整个的操做系统。每一个 OS 又须要 CPU、RAM 等等,须要打补丁、安装证书,这些反过来又增长了成本和弹性。node
Google 在好久以前就开始使用容器模型来解决 VM 模式的弊端。简单来讲容器模型容许咱们在同一台主机上运行多个容器,并且共用主机的 CPU、RAM 等资源。docker
那么它对开发者来讲意味着是么呢?
它能够保证对全部的开发者和服务器来讲,咱们的工做环境都是一致的。好比: 生产环境、仿真环境、测试环境。express
任何人均可以分分钟配置好项目,无需乱搞配置、安装库和设置依赖。npm
简单来讲,docker 是一个平台,它容许咱们使用容器来开发、部署、运行应用程序。
让咱们退一步来看,容器系统在物理上是什么样子的,以及与 VM 有什么区别。json
能够看出来,宿主机的资源在容器化的使用后是共享的,可是在 VM 中却被分割开了。浏览器
接下来,咱们来深刻一些。缓存
为此咱们须要先熟悉一些术语。bash
Docker image: 它是一个可执行文件,包含了运行一个应用程序的操做系统配置和全部的库。它有多个层叠在一块儿,并表示为单个对象。docker image 是经过 docker file 来建立的,咱们稍后再讲。服务器
Docker Container: 它是 docker image 的一个运行实例。同一个 docker image 能够有多个运行的 container。
咱们来尝试容器化一个简单的 node.js 应用,而后建立一个 image:
先建立一个 my-node-app
文件夹,
mkdir my-node-app cd my-node-app
而后建立一个 index.js
来启动一个 node server:
// 咱们用 require 引入 express var express = require('express') var app = express() // 对根 URL 作一个响应 app.get('/', function (req, res) { res.send('Hello World!') }) // 让服务器监听 8081 端口 app.listen(8081, function () { console.log('app listening on port 8081!') })
而后咱们建立一个 package.json
文件,能够经过 npm init -y
来快速生成:
{ "name": "helloworld", "version": "1.0.0", "description": "Dockerized node.js app", "main": "index.js", "author": "", "license": "ISC", "dependencies": { "express": "^4.16.4" } }
到这一步咱们甚至不须要 express 或者 npm 安装在本身的机器,由于 dockerfile 能够为咱们配置和安装这些依赖。
让咱们建立一个 dockerfile,而后保存到 my-node-app
文件夹。这个文件没有扩展名,它的名字就叫做 Dockerfile
,这是里面的内容:
# Dockerfile FROM node:8 WORKDIR /app COPY package.json /app RUN npm install COPY . /app EXPOSE 8081 CMD node index.js
下面解释一下里面的命令:
FROM node:8
-- 从 docker hub 拉取 node.js docker 镜像,能够在这里找到 node 的镜像:https://hub.docker.com/_/node/
WORKDIR /app
-- 设置镜像中的工做目录,能够与下面的命令一块儿使用: COPY
,RUN
和 CMD
COPY package.json /app
-- 将 package.json 从宿主机的 my-node-app
目录复制到了镜像中的 /app
目录
RUN npm install
-- 在镜像中运行此命令来安装 node 包
COPY . /app
-- 复制 my-node-app
目录中的全部文件到镜像中的 /app
目录
EXPOSE 8081
-- 这条命令告诉 container 要暴露一个端口号,这个端口号正是咱们在 index.js
中写的那个。默认状况下,容器会忽略对它全部的请求。
注意看啦~ 打开控制台,到 my-node-app
目录下,执行如下命令:
# Build a image docker build -t <image-name> <relative-path-to-your-dockerfile> docker build -t hello-world .
这条命令在咱们宿主机建立了一个 hello-world
镜像
-t
用来为咱们的镜像指定一个名字,这里就是 hello-world
.
是用来指明 docker file 的路径,因为咱们已经在 my-node-app
中,因此路径用 .
就能够了
你能够在控制台看到相似于如下的输出:
Sending build context to Docker daemon 4.096kB Step 1/7 : FROM node:8 ---> 4f01e5319662 Step 2/7 : WORKDIR /app ---> Using cache ---> 5c173b2c7b76 Step 3/7 : COPY package.json /app ---> Using cache ---> ceb27a57f18e Step 4/7 : RUN npm install ---> Using cache ---> c1baaf16812a Step 5/7 : COPY . /app ---> 4a770927e8e8 Step 6/7 : EXPOSE 8081 ---> Running in 2b3f11daff5e Removing intermediate container 2b3f11daff5e ---> 81a7ce14340a Step 7/7 : CMD node index.js ---> Running in 3791dd7f5149 Removing intermediate container 3791dd7f5149 ---> c80301fa07b2 Successfully built c80301fa07b2 Successfully tagged hello-world:latest
能够看到,它根据 docker file 中的命令依次运行,而后输出了一个 docker 镜像。当你第一次运行的时候可能会须要一些时间,下次就可使用缓存来加快速度了。如今咱们来看下刚才 build 的镜像:
# Get a list of images on your host docker images
这个命令会显示在你电脑上存在的 docker 镜像。其中会有一条:
REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest c80301fa07b2 22 minutes ago 896MB
既然咱们已经建立了镜像,下面咱们就从这个镜像运行一个 docker 容器:
# Default command for this is docker container run <image-name> docker container run -p 4000:8081 hello-world
这条命令用来建立和运行一个 docker 容器
-p 4000:8081
-- 是一个发布(publish)标识,它将本机的 4000 端口映射到了容器中的 8081 端口。如今全部对本机 4000 端口的访问,都会被容器中的 8081 端口监听。
hello-world
-- 这个名字就是刚才用 docker build
命令时指定的镜像名称。
你将会获得如下输出:
app listening on port 8081!
若是你须要进入容器而且挂载一个 bash 终端,能够运行:
# Enter the container docker exec -ti <container id> /bin/bash
为了检查咱们的容器是否运行,打开另外一个命令行,而后输入:
docker ps
能够看到如下输出:
CONTAINER ID IMAGE COMMAND CREATED `<container id>` hello-world "/bin/sh -c 'node in…" 11 seconds ago STATUS PORTS NAMES Up 11 seconds 0.0.0.0:4000->8081/tcp some-random-name
这里能够看咱们从 hello-world 镜像建立的容器,以及它的 <container id>
,它正在运行,而且监听了 8081 端口号。
如今咱们这个简单的 Node.js 应用就已经彻底容器化了。你能够在浏览器访问 http://localhost:4000 ,应该能够看到如下画面:
看,是否是很简单哈哈~
欢迎关注个人公众号:码力全开(codingonfire)