关于Docker
对于我们大多数前端,接触服务器部署、运维的工作很少,潜意识可能会忽略 Docker 相关信息,但是说vmware、visualbox,我想前端们再熟悉不过了,还记得当年IE67891011怎么调试的吗。。。
Docker 是一个开源项目,基于 Go 语言实现,是一套轻量级的操作系统虚拟化解决方案。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。
想想当年我们曾经部署过的apache、nginx、php、mysql、nodejs,参考网上各种lamp,lnmp搭建教程,在我们买的虚拟主机上折腾良久,搭建了一套博客,开始写文章。之中的苦与乐,我想有很多人都经历过。
场景
我是前端,某一天,我写了一个nodejs服务,我想后端帮我部署在服务器上。
在使用 Docker 以前,他脑海会迅速想到以下问题:
- tmd我的服务器没有nodejs环境。。。
- 你写的代码安不安全,这个可是要对外访问的。。。
- 你的代码依赖太多,有详细部署文档吗。。。
在使用 Docker 之后,他会跟你说:
好处
Docker 带来了什么,粗浅的理解:
- 拥有沙盒机制,系统隔离,绿色无污染;
- 应用服务化,端口即服务;
- 一次创建或配置,可以在任意地方正常运行;
- 分享。
准备折腾
假装你已经初步了解了 Docker ,并且你拥有一台可以折腾的服务器,而且已经安装 Docker 。如果没有请看这里。
现在我们来看个例子。
项目驱动学习:状态条 statusbar
项目描述
通过url访问,传不同参数:title、label、color,来生成一个svg图片。效果如下:
http://main/?title=开发中&label=状态&color=orange
http://main/?title=90&label=进度
项目结构
statusbar\
|
|--index.js
|--package.json
|--README.md
|--Dockerfile
|--.gitignore
\--.dockerignore
项目本身很简单,只有一个js文件,代码如下:
"use strict";
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.type('image/svg+xml');
res.send(getsvg(req.query.title || 'hello', req.query.color, req.query.label, req.query.flat));
res.end();
});
function getsvg(title, color, label, flat) {
// 此处省略 ...
}
// note:这里用到一个环境变量
let port = process.env.HTTP_PORT || 8000;
app.listen(port, () => {
console.log('Listening on port %s', port);
});
这个文件有个依赖 express ,后面我想用 nodemon 启动该项目,所以 package.json 文件简略如下:
{
"name": "statusbar",
"version": "1.0.0",
"description": "status & process bar for markdown",
"main": "index.js",
"scripts": {
"start": "nodemon index.js"
},
"author": "onbing",
"dependencies": {
"express": "~4.13.3",
"nodemon": "~1.8.1"
}
}
.gitignore 大家都懂的,主要是 .dockerignore ,后面我希望部署时,把这个目录直接拷贝至容器,这个目录中肯定会存在一些奇奇怪怪的文件是不希望部署进去的,与 .gitignore 道理一样,一行添加一个进行忽略,根据项目实际情况,文件内容可能会如下:
node_modules/
.git
.gitignore
.idea
.DS_Store
*.swp
*.log
Dockerfile
重点来了,项目构建以 Dockerfile 作为蓝本,先上内容:
# Statusbar
#
# VERSION 1.0.0
FROM daocloud.io/node:5
MAINTAINER me@yanbingbing.com
ENV HTTP_PORT 8000
COPY . /app
WORKDIR /app
RUN npm install --registry=https://registry.npm.
EXPOSE 8000
CMD ["npm", "start"]
基础镜像
通过 FROM 指令来指定基于的image,一般格式如下:
FROM <image>:<tag>
# or
FROM <image>
daocloud.io/node:5 和 node:5 其实是同一个image,出于速度考虑选择 daocloud.io/node:5 。
设定环境变量
ENV 指令用来设定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持。格式如下:
ENV <KEY> <value>
可以看到之前js文件有用到 process.env.HTTP_PORT ,就是在这里设定的。
拷贝项目文件
COPY 指令用来复制本地主机的文件到容器中,格式如下:
COPY <src> <dest>
这里把我们项目目录本身,即当前目录 . 拷贝至容器的 /app 位置。然后通过指令 WORKDIR 将 /app 目录设为工作目录。工作目录可以理解为运行时的 pwd 。
npm install
然后在 /app 目录中执行我们特别熟悉的 npm install ,这里我们要用 RUN 指令来执行。
开放端口
作为一个服务,来让外部通过端口来访问,通过 EXPOSE 指令来指定端口号,很像我们的 module.exports ,模块化思路无处不在。
npm start
最后指定,当这个容器运行的时候,如何启动这个服务。我们 npm start 就可以了,因为我们在 package.json 中设置了 scripts.start 。
提交代码
开发环节暂且告一段落,将代码提交至 github 或 gitlab ,如果不想分享,可以忽略这一步。
本文项目代码地址:
https://github.com/yanbingbing/statusbar
部署
以我的服务器centos7为例,我已安装好 Docker ,我只需要将项目拿过来,build一下,run一下就可以了。
首先检出代码:
git clone https://github.com/yanbingbing/statusbar.git statusbar
进入目录构建:
cd statusbar
docker build -t statusbarimg .
构建目标名称 statusbarimg ,是一个镜像,可以通过 docker images 来列出所有的镜像。
通过镜像 statusbarimg 创建一个容器并运行。
docker run --name statusbarcontainer -d -p 80:8000 statusbarimg
创建的容器名称是 statusbarcontainer ,你可以理解为 pid ,这个名称唯一,创建之后如果不删除会一直存在。-p 用来指定端口映射,将容器的端口8000映射到主机80端口上,这样就可外部访问了。
最后可以通过以下命令来管理这个容器:
# 停止
docker stop statusbarcontainer
# 重启容器
docker restart statusbarcontainer
# 删除容器
docker rm statusbarcontainer
结语
通过一个简单例子下来,发现 Docker 的实现思路和我们前端模块化思路很像,正所谓天下大同(就算总结少也要高大上)。
|