[root@dss ~]# docker search node # 搜素镜像
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
node Node.js is a JavaScript-based platform for... 2462 [OK]
strongloop/node StrongLoop, Node.js, and tools. 30 [OK]
bitnami/node Bitnami Node.js Docker Image 16 [OK]
siomiz/node-opencv _/node + node-opencv 8 [OK]
dahlb/alpine-node small node for gitlab ci runner 7 [OK]
tatsushid/tinycore-node A small but a fully functional Node.js run... 6 [OK]
cusspvz/node Super small Node.js container (~20MB)... 4 [OK]
azukiapp/node Docker image to run Node.js by Azuki - htt... 4 [OK]
tutum/node Run a Tutum node inside a container 3 [OK]
anigeo/node-forever Daily build node.js with forever 3 [OK]
redjack/node Node + Nave 1 [OK]
xataz/node very light node image 1 [OK]
joxit/node Slim node docker with some utils for dev 1 [OK]
centralping/node Bare bones CentOS 7 NodeJS container. 1 [OK]
urbanmassage/node Some handy (read, better) docker node images 1 [OK]
tectoro/node-compass Node JS minimal version with compass and b... 1 [OK]
starefossen/ruby-node Docker Image with Ruby and Node.js installed 1 [OK]
atomiq/node Use as base image for new Node.js images. 1 [OK]
robbertkl/node Docker container running Node.js 0 [OK]
lynxtp/node https://github.com/lynxtp/docker-node 0 [OK]
codexsystems/node Node.js for Development and Production 0 [OK]
instructure/node Instructure node images 0 [OK]
stylisted/node Stylisted's base Docker node image with gr... 0 [OK]
maxird/node Node 0 [OK]
c4tech/node NodeJS images, aimed at generated single-p... 0 [OK]
安装 Node.Js 官方镜像 [root@dss ~]# yum pull node
查看已安装镜像
[root@dss workspace]# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
node latest 47abb70784d6 8 days ago 660.6 MB
新建目录 src
, 在src目录下新建 package.json
:
{
"name": "docker-node-test",
"private": true,
"version": "0.0.1",
"description": "Node.js test app on node docker image",
"author": "Shaoshuai Dong " ,
"dependencies": {
"express": "^4.13.4"
}
}
在src目录下新建index.js
:
const express = require('express');
// Creates an Express application
let app = express();
// Assigns settings
app.set('port', 8080);
// Routes HTTP GET requests
app.get('/', (req, res) => {
res.send('Hello world --- from nodejs docker image\n');
});
// Binds and listens
app.listen(app.get('port'), () => {
console.info("Listen port %s for app", app.get("port"));
在src同级目录下新建文件 Dockerfile
:
From node:6.3
ADD src/ /src
RUN cd /src; npm install
EXPOSE 8080
CMD ["node", "/src/index.js"]
创建镜像 docker build --tag="node/app-test" ./
, docker build --help
查看详细参数
创建成功会提示 Successfully built 2199b2aa9cd1
查看创建的镜像
[root@dss test]# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
node/app-test latest 2199b2aa9cd1 7 seconds ago 663.6 MB
node 6.3 47abb70784d6 8 days ago 660.6 MB
node latest 47abb70784d6 8 days ago 660.6 MB
运行刚刚创建的镜像, docker run --help
查看详细参数:
[root@dss test]# docker run -d -p 8081:8080 node/app-test
873ac198368799f9bf56262e097f55e66241f47cedd336349236b43e9001539d
查看运行中的容器,是否存在:
[root@dss test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
873ac1983687 node/app-test "node /src/index.js" 53 seconds ago Up 52 seconds 0.0.0.0:8081->8080/tcp desperate_swartz
测试 Node.Js 服务:
[root@dss ~]# curl localhost:8081 -i
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 41
ETag: W/"29-onjHxbOtTbPH0+vlfe2YtA"
Date: Fri, 15 Jul 2016 10:49:54 GMT
Connection: keep-alive
Hello world --- from nodejs docker image
创建 Dockerfile
:
From node:6.3
RUN npm install pm2 -g --registry=https://registry.npm.taobao.org
RUN mkdir -p /usr/src/node-app
WORKDIR /usr/src/node-app
COPY src/. /usr/src/node-app/
RUN npm install --registry=https://registry.npm.taobao.org
EXPOSE 8080
CMD ["npm", "start"]
先看看目录结构吧
[root@dss workspace]# tree test/
test/
├── Dockerfile
└── src
├── index.js
├── package.json
└── pm2.json
package.json
:
{
"name": "docker-node-test",
"private": true,
"version": "0.0.1",
"description": "Node.js test app on node docker image",
"author": "Shaoshuai Dong " ,
"scripts": {
"start": "pm2 startOrGracefulReload ./pm2.json --no-daemon"
},
"dependencies": {
"express": "^4.13.4"
}
}
index.js
const express = require('express');
// Creates an Express application
let app = express();
// Assigns settings
app.set('port', 8080);
// Routes HTTP GET requests
app.get('/', (req, res) => {
res.send('Hello world --- from nodejs docker image\n');
});
// Binds and listens
app.listen(app.get('port'), () => {
console.info("Listen port %s for app", app.get("port"));
});
pm2.json
:
{
"apps": [
{
"name": "app-test",
"script" : "index.js",
"args" : [],
"watch" : false,
"merge_logs" : true,
"max_memory_restart": "100M",
"env": {
"NODE_ENV": "local"
}
}
]
}
创建镜像 docker build --tag="node/app-test" ./
查看创建的镜像 docker images
:
[root@dss test]# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
node/app-test latest 1a3325c28c8c 14 minutes ago 678 MB
node latest 47abb70784d6 10 days ago 660.6 MB
node 6.3 47abb70784d6 10 days ago 660.6 MB
运行 docker run -d -p 8081:8080 node/app-test
查看运行中的容器
[root@dss test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9e49f7c5270a node/app-test "pm2 start index.js 7 minutes ago Up 7 minutes 0.0.0.0:8081->8080/tcp gloomy_sammet
测试
[root@dss test]# curl -i localhost:8081
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 41
ETag: W/"29-onjHxbOtTbPH0+vlfe2YtA"
Date: Sun, 17 Jul 2016 09:12:48 GMT
Connection: keep-alive
Hello world --- from nodejs docker image
在容器内运行命令(docker exec --help
查看更多用法)
[root@dss test]# docker exec -i 9e49f7c5270a pm2 list
┌──────────┬────┬──────┬─────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├──────────┼────┼──────┼─────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ app-test │ 0 │ fork │ 17 │ online │ 0 │ 9m │ 23.730 MB │ disabled │
└──────────┴────┴──────┴─────┴────────┴─────────┴────────┴─────────────┴──────────┘
这里介绍将 pm2 日志和程序日志记录在宿主机文件之中, 目标是:
/data/logs/app-test-out.log
/data/logs/app-test-err.log
/data/logs/hello.log
./
├── Dockerfile
└── src
├── index.js
├── package.json
└── pm2.json
Dockerfile
From node:6.3
RUN npm install pm2 -g --registry=https://registry.npm.taobao.org
RUN mkdir -p /usr/src/node-app
WORKDIR /usr/src/node-app
COPY src/. /usr/src/node-app/
RUN npm install --registry=https://registry.npm.taobao.org
EXPOSE 8080
CMD ["npm", "start"]
index.js
const express = require('express');
const log4js = require('log4js');
// Creates an Express application
let app = express();
// Init logger
log4js.configure({
appenders: [{
type: 'dateFile',
pattern: '-yyyyMMddhh.log',
filename: '/data/logs/hello.log',
category: 'hello'
}],
levels: {
action: 'INFO',
alarm_api: 'INFO'
}
});
global.logger = log4js.getLogger('hello');
// Assigns settings
app.set('port', 8080);
// Routes HTTP GET requests
app.get('/', (req, res) => {
console.info('On request: hello world');
global.logger.info(req.method, req.path);
res.send('Hello world --- from nodejs docker image\n');
});
// Binds and listens
app.listen(app.get('port'), () => {
console.info('Listen port %s for app', app.get('port'));
});
package.json
{
"name": "docker-node-test",
"private": true,
"version": "0.0.1",
"description": "Node.js test app on node docker image",
"author": "Shaoshuai Dong " ,
"scripts": {
"start": "pm2 startOrGracefulReload ./pm2.json --no-daemon"
},
"dependencies": {
"express": "^4.13.4",
"log4js": "^0.6.33"
}
}
pm2.json
{
"apps": [
{
"name": "app-test",
"script": "index.js",
"args": [],
"watch": false,
"merge_logs": true,
"error_file": "/data/logs/app-test-err.log",
"out_file": "/data/logs/app-test-out.log",
"log_date_format": "YYYY-MM-DD HH:mm:ss.SSS",
"max_memory_restart": "100M",
"env": {
"NODE_ENV": "local"
}
}
]
}
创建镜像 docker build --tag="node/app-test:0.1" ./
运行容器 docker run -p 8081:8080 -v /data/logs:/data/logs --name hello node/app-test:0.1
使用 -v
参数在容器上挂载宿主机上的指定目录
查看容器和测试:
[root@dss test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
63eb2a3aea8b node/app-test:0.1 "npm start" 17 seconds ago Up 16 seconds 0.0.0.0:8081->8080/tcp hello
[root@dss test]# curl localhost:8081
Hello world --- from nodejs docker image
[root@dss test]#
在宿主机上查看日志
[root@dss test]# ls /data/logs/
app-test-err.log app-test-out.log hello.log
[root@dss test]# cat /data/logs/app-test-out.log
2016-07-18 05:56:56.406: Listen port 8080 for app
2016-07-18 05:57:21.289: On request: hello world
[root@dss test]# cat /data/logs/hello.log
[2016-07-18 05:57:21.290] [INFO] hello - GET /
命令 docker inspect hello
可以看到容器的 volume 配置
...
"Volumes": {
"/data/logs": "/data/logs"
},
"VolumesRW": {
"/data/logs": true
},
...
Data volumes
有如下特性:
使用 Volume
可以将容器与容器产生的数据分离,容器产生的数据可以持久化。
Docker volumes 使用 -v
指定和 在 Dockerfile 指定 VOLUME
的区别:
-v /data/logs:/data/logs
: 将宿主机的 /data/logs
目录挂载到容器的 /data/logs
目录(如果目录不存在会被创建), 宿主机和容器共享该目录,二者对该目录下的修改相互受影响。VOLUME /data/logs
: 在宿主机创建一个目录(默认是 /var/lib/docker/volumes/
)并挂载到容器的 /data/logs
目录(如果目录不存在会被创建), 宿主机和容> 器共享该目录,二者对该目录下的修改相互受影响。-v /data/logs
: 同上, 在宿主机创建一个目录(默认是 /var/lib/docker/volumes/
)并挂载到容器的 /data/logs
目录(如果目录不存在会被创建), 宿主机和容器共享该目录,二者对该目录下的修改相互受影响。Docker volumes 默认是 read-write 模式,也可以设置为 read-only 模式。
目标
新建 Dockerfile
# Mongodb image from centos:6
# run -v /data/db:/data/db -p 27017:27017
From centos:6
MAINTAINER Shaoshuai Dong
# install mongodb v3.2
COPY mongodb.repo /etc/yum.repos.d/
RUN yum install -y mongodb-org
# volume
VOLUME ["/data/db"]
# expose port
EXPOSE 27017
# command
CMD ["mongod"]
mongodb.repo
[MongoDB]
name=MongoDB Repository
baseurl=http://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.2/x86_64/
gpgcheck=0
enabled=1
创建镜像 docker build --tag="centos/mongo:0.1" ./
运行容器 docker run -d -p 27017:27017 -v /data/db:/data/db --name mongo centos/mongo:0.1
查看容器运行状态
[root@dss mongodb]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c9ddd14992e6 centos/mongo:0.1 "mongod" 5 seconds ago Up 4 seconds 0.0.0.0:27017->27017/tcp mongo
测试远程连接 mongodb
[dongshaoshuai~/test] ]$mongo --port 27017 --host x.x.x.x
^[[AMongoDB shell version: 3.0.6
connecting to: x.x.x.x:27017/test
也可以通过 Robomongo
远程连接(如果mongodb 版本 >= v3,Robomongo 的版本需 > v0.8.5)
Dockerfile
From centos:6
MAINTAINER Shaoshuai Dong .com>
# install redis v3.2.1
RUN yum install -y gcc-c++
RUN yum install -y tcl
RUN yum install -y wget
RUN wget http://download.redis.io/releases/redis-3.2.1.tar.gz
RUN tar -xzvf redis-3.2.1.tar.gz
RUN mv redis-3.2.1 /usr/local/redis
RUN cd /usr/local/redis; make; make install
COPY redis.conf /etc/redis.conf
EXPOSE 6379
CMD ["/usr/local/bin/redis-server", "/etc/redis.conf"]
redis.conf: wget http://download.redis.io/redis-stable/redis.conf
将 protected-mode yes
改为 protected-mode no
创建镜像 docker build --tag="centos/redis:0.1" ./
运行容器 docker run -d -p 6379:6379 --name redis centos/redis:0.1
查看运行容器
[root@dss redis]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5aa2aa34764e centos/redis:0.1 "/usr/local/bin/redi 6 seconds ago Up 3 seconds 0.0.0.0:6379->6379/tcp redis
c9ddd14992e6 centos/mongo:0.1 "mongod" 2 hours ago Up 2 hours 0.0.0.0:27017->27017/tcp mongo
目录结构
├── app
│ ├── index.js
│ ├── package.json
│ └── pm2.json
└── Dockerfile
Dockerfile
# run -v /data/logs:/data/logs --link mongo:mongo
From centos:6
MAINTAINER Shaoshuai Dong
# install nodejs v6
RUN curl --silent --location https://rpm.nodesource.com/setup_6.x | bash -
RUN yum -y install nodejs
# install pm2
RUN npm install pm2 -g --registry=https://registry.npm.taobao.org
# make dir
RUN mkdir -p /usr/src/myapp
# envs
ENV NODE_ENV=local
# copy files
COPY app/. /usr/src/myapp/
# work dir
WORKDIR /usr/src/myapp
# install dependencies
RUN npm install --registry=https://registry.npm.taobao.org
# expose port
EXPOSE 8080
# cmd
CMD ["npm", "start"]
package.json
{
"name": "docker-node-test",
"private": true,
"version": "0.0.1",
"description": "Node.js test app on node docker image",
"author": "Shaoshuai Dong " ,
"scripts": {
"start": "pm2 startOrGracefulReload ./pm2.json --no-daemon"
},
"dependencies": {
"express": "^4.13.4",
"log4js": "^0.6.33",
"mongoose": "^4.0.8",
"express-session": "^1.13.0",
"connect-redis": "^3.1.0"
}
}
pm2.json
{
"apps": [
{
"name": "app",
"script": "index.js",
"args": [],
"watch": false,
"merge_logs": true,
"error_file": "/data/logs/app-err.log",
"out_file": "/data/logs/app-out.log",
"log_date_format": "YYYY-MM-DD HH:mm:ss.SSS",
"max_memory_restart": "100M",
"env": {
"NODE_ENV": "local"
}
}
]
}
一个简单的服务,仅作为演示 index.js
const express = require('express');
const log4js = require('log4js');
const mongoose = require('mongoose');
const cookieParser = require("cookie-parser");
const session = require('express-session');
const redisStore = require('connect-redis')(session);
// Creates an Express application
let app = express();
// NODE_ENV
const ENV = app.get('env');
// Init logger
log4js.configure({
appenders: [{
type: 'dateFile',
pattern: '-yyyyMMddhh.log',
filename: '/data/logs/app.log',
category: 'app'
}],
levels: {
app: 'INFO',
}
});
global.logger = log4js.getLogger('app');
// Assigns settings
app.set('port', 8080);
// Middlewares
app.use(cookieParser('tadf@a213!sdfa6'));
app.use(session({
secret: 'tadf@a213!sdfa6',
resave: false,
saveUninitialized: false,
store: new redisStore({
logErrors: true,
// host: 'redis', // Can be solved by docker-compose
host: process.env.REDIS_PORT_6379_TCP_ADDR,
port: 6379,
ttl: 60 // expiration in 60s
})
}));
// MongoDB connection: 'mongo' resolves to a docker container
let mongoUrl = 'mongodb://mongo:27017/test';
mongoose.connect(mongoUrl);
let Monkey = mongoose.model('Monkey', { name: String });
/**
* Routes HTTP GET requests
*/
app.all('*', (req, res, next) => {
global.logger.info(req.method, req.path);
if (req.path === '/login') {
next();
return;
}
if (!req.session || !req.session.isLoggedIn) {
// TODO: redirect to login page
res.send('Please login first');
return;
}
next();
});
app.get('/login', (req, res) => {
let userName = 'admin';
let password = 'admin';
if (req.query.name === userName && req.query.password === password) {
req.session.isLoggedIn = true;
res.json({
RetCode: 0
});
return;
}
res.json({
RetCode: 5,
ErrMsg: 'Username or password wrong'
});
});
app.get('/hello', (req, res) => {
console.info('On request: hello world');
res.send('Hello world --- from nodejs docker image\n');
});
app.get('/mongo/insert', (req, res) => {
let newData = { name: req.query.name };
let newMonkey = new Monkey(newData);
newMonkey.save(err => {
if (err) {
global.logger.error('Insert data failed: ', err, newData);
res.json({
RetCode: 100,
ErrMsg: 'Insert data failed'
});
return;
}
global.logger.info('Insert data success:', newData);
res.json({
RetCode: 0
});
});
});
app.get('/mongo/find', (req, res) => {
Monkey.find((err, monkeys) => {
if (err) {
global.logger.error('Find data failed: ', err);
res.json({
RetCode: 200,
ErrMsg: 'Find data failed'
});
return;
}
global.logger.info('Find data success:', monkeys);
res.json({
RetCode: 0,
Data: monkeys
});
});
});
// Binds and listens
app.listen(app.get('port'), () => {
console.info('Listen port %s for app', app.get('port'));
console.info('NODE_ENV', ENV);
});
创建镜像 docker build --tag="centos/node-app:0.1" ./
运行容器 docker run -d -p 8181:8080 -v /data/logs:/data/logs --link mongo:mongo --link redis:redis --name app centos/node-app:0.1
查看服务状态
[root@dss app]# docker exec app pm2 list
┌──────────┬────┬──────┬─────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├──────────┼────┼──────┼─────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ app │ 0 │ fork │ 25 │ online │ 0 │ 21s │ 47.879 MB │ disabled │
└──────────┴────┴──────┴─────┴────────┴─────────┴────────┴─────────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app
未登录, 在浏览器访问 yourhost:8181/hello
Please log in first
登录, yourhost:8181/login?name=admin&password=admin
{
"RetCode": 0
}
登陆后,测试 yourhost:8181/hello
Hello world --- from nodejs docker image
测试 yourhost:8181/mongo/find
{"RetCode":0,"Data":[{"_id":"578ded8321be5919003c0dd8","name":"mmmm","__v":0},{"_id":"578df6f638a6a11b008a9bd0","name":"mmmmmm","__v":0}]}
查看日志
[root@dss logs]# cat /data/logs/app.log
[2016-07-20 02:31:40.097] [INFO] app - GET /hello
[2016-07-20 02:31:45.088] [INFO] app - GET /login
[2016-07-20 02:32:12.375] [INFO] app - GET /hello
[2016-07-20 02:32:16.476] [INFO] app - GET /mongo/find
[2016-07-20 02:32:16.477] [INFO] app - Find data success: [ { _id: 578ded8321be5919003c0dd8, name: 'mmmm', __v: 0 },
{ _id: 578df6f638a6a11b008a9bd0, name: 'mmmmmm', __v: 0 } ]
docker 镜像、容器默认存储在 /var/lib/docker
,对于云主机通常系统盘不大,最好存储在数据盘。
通过 --graph
参数可以指定存储位置。修改 /etc/sysconfig/docker
文件:
# 数据盘
other_args="--graph=/data/docker"
停止 docker 服务 service docker stop
copy 数据至数据盘 cp -r /var/lib/docker /data/docker/
移除、备份原数据 mv /var/lib/docker /data/bak/docker.bak
重新启动 docker 服务 service docker start
测试镜像和容器是否正常 docker images
, docker ps -a
原文