Wednesday, February 6, 2019

学习舵轮(kubernetes)和埠(docker) - 创建NodeJS+MongoDB docker image


讲了很多概念,下面是一些docker的源代码,用来创建前面讲的NodeJS+MongoDB的应用。DockerHub提供很多常用的container image,包括NodeJS image。如下的Dockerfile就会载入最新的NodeJS container,并运行npm(Node Package Manager)根据用户提供的package.json文件来安装需要的Node package。
FROM node:latest
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app/ #package.json like this contains dependencies and entry point
RUN npm install
COPY . /usr/src/app
EXPOSE 3000
CMD [ “npm”, “start” ]
用这个Dockerfile可以build一个NodeJS的container,要加MongoDB支持,需要创建如下YAML compose file:
version: "1"
services:
app:
  container_name: app #optional
  build: . # Dockerfile location for building nodejs App
  ports:
  - "8080:3000" # port forwarding
  depends_on: # same as links?
  - mongo
mongo:
  container_name: mongo #optional
  image: mongo
  ports:
  - "27017:27017"
  volumes:
  - data-volume:/data/db
volumes:
data-volume:
把这个compose file 存为my-compose.yml,然后运行: 
docker-compose -f my-compose.yml up
就会创建和运行一个提供NodeJS+MongoDB的container。打开localhost:8080就可以测试。
 
对我来说,Docker的NodeJS image的size有点大。我更prefer小巧的alpine Linux,所以就创建了如下的Docker file:
FROM alpine
COPY . /app
WORKDIR /app
RUN apk update && apk add nodejs
EXPOSE 3000
CMD ["node","app.js"]
这是基于alpine image,安装NodeJS,并运行app.js script。app.js的内容如下:
var http = require('http');
http.createServer(function (req, res) {
 res.write('Hello World!'); //write a response to the client
 res.end(); //end the response
}).listen(3000);
这是一个简单的‘HelloWorld’ web server code。用类似如下命令build和运行:
docker image build -t my_project:v0.1 .
docker run -d -p 8080:3000 my_project:v0.1 #detach mode, remap port to 8080,or use docker-machine ip to find container ip.
运行结果是web server 不work,查看log就会发现,虽然NodeJS和MongoDB都安装了,但Node的Mongo package没有安装,JS code 就没办法talk to MongoDB。所以需要更新Dockerfile的‘RUN’这一行:
RUN apk add --update nodejs nodejs-npm mongodb; RUN npm install mongodb 
重新build会看到message:
 Step 5/7 : RUN npm install mongodb
---> Running in 216d30b5ce3b
npm WARN saveError ENOENT: no such file or directory, open '/app/package.json'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN enoent ENOENT: no such file or directory, open '/app/package.json' …
再运行还是有问题,这次是JS知道怎样access mongoDB,但MongoDB没有起来,需要运行MongoDB daemon:
Refer this for starting mongod: mongod --port 27017 --dbpath /app/ --fork --logpath /var/log/mongodb.log
#need specify --dbpath before we add the volume mount point; use --fork to run as daemon. Will get:
WARNING: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted.
WARNING: You are running this process as the root user, which is not recommended.
WARNING: This server is bound to localhost. Remote systems will be unable to connect to this server. Start the server with --bind_ip
to specify which IP addresses it should serve responses from, or with --bind_ip_all to bind to all interfaces. If this behavior is desired, start the server with --bind_ip 127.0.0.1 to disable this warning.
Refer to alpine_Init_Scripts, after mongo is installed, mongodb and mongos are created under /etc/init.d. But openrc isn’t installed by default. So need add ‘openrc’ to RUN apk add command in dockerfile. 
不要在Dockerfile里加上RUN上面的启动mongod daemon 的 command line, 那样做会造成生成的significantly size increase of docker container image, from 207M to 508M. It’s a little complex to get the service setup properly (rc-update add mongodb default, may need to setup environment for mongo), 所以我把 mongod cmdline and nodejs cmdline 放在一个 shell script, 然后把run这个shell script 的 CMD line 加到 dockerfile。这样创建的docker image只有208M左右。

常用的MongoDB命令:
mongo cmds: db.stats(), show dbs, use my_db, show collections.
MongoDB v3.0+有些改动,如遇到TypeError: db.collection is not a function,refer to this SO, for mongodb>=3.0, code like var col_history = db.collection('history') will lead to TypeError: db.collection is not a function. Change the code to: var col_history = db.db().collection('history')

把database 数据文件存到另外mount的volume上: use a separate volume for db, run: docker volume create mongo_db, update Dockerfile with VOLUME /data and set --dbpath /data/ in mongod cmdline. Then start container like this: docker container run -d -p8080:3000 --mount type=volume,source=mongo_db,destination=/data my_project:v0.2

0 Comments:

Post a Comment