0%

2020-04-22 docker 初步探究及研究心得

2020-04-22 docker 初步探究及研究心得

参考:Docker 教程

Nodejs Docker 镜像体积优化实践

Dockerfile 与 docker-compose.yml 文件的作用及自动部署的实现

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。

Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。

容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。

出于一些原因,本人习惯用 centos7,因此下面就以它为基础进行探究。其他版本的操作系统在菜鸟教程上都有,按部就班照做就行。

在 centos 下还是使用 yum 来安装包最方便,因此

1
2
3
4
5
6
7
sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io

另外再提一下镜像加速,国内访问镜像时有时会卡住,因此需要配置下镜像。

例如:

对于使用 systemd 的系统,请在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件):

1
{"registry-mirrors":["https://reg-mirror.qiniu.com/"]}

之后重新启动服务:

1
2
sudo systemctl daemon-reload
sudo systemctl restart docker

Dockerfile 的使用

下面就结合本人自己的体验来说明下 docker 的使用。

docker 以 Dockerfile 为配置,所以需要在根目录下新建一个 Dockerfile 文件,一个简单的例子如下

1
2
3
4
5
6
7
8
9
10
# Dockerfile
FROM node #意思是基于node这个镜像进行开发

COPY . /home/app #将当前项目的文件复制到/home/app

RUN cd /home/app && npm install #安装依赖

WORKDIR /home/app #设置工作目录

CMD ['npm', 'start'] #运行

在项目根目录执行

1
2
docker build -t myapp .
docker images

应该就能看见一个 myapp 镜像了

但直接基于node镜像进行开发是非常不推荐的,只要实际操作过的人就会发现node这个镜像的大小有 918MB,可以说大的离谱,在生产环境中是绝对不能用的

因此需要进行优化,最简单的办法就是选择一个更小的镜像,例如 node:alpine,这个镜像的大小只有 100MB,整整减少了800MB,这是一个非常大的优化。

但是还可以更小

  1. npm 只安装生产环境依赖,即npm install --production

  2. 使用基础版本的 Alpine 镜像自行安装 Nodejs,即

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    FROM alpine:latest

    RUN apk add --no-cache --update nodejs nodejs-npm

    COPY . /home/app

    RUN cd /home/app && npm install --production

    WORKDIR /home/app

    CMD ['npm', 'start']
  3. 使用脚本来清除无关文件

    这个脚本就是清除掉 node_modules 中的一些无关文件,都是些开发环境会用到的东西,但在生产环境就是累赘了。

    1
    2
    3
    4
    #!/bin/bash
    find node_modules -type f | grep -E "(.idea|.vscode|benchmark.js|.eslintrc.js|changelog|CHANGELOG|AUTHORS|license|LICENSE|LICENCE|.travis.yml|.eslintrc.json|.eslintrc.yml|Makefile|.npmignore|.DS_Store|.jshintrc|.eslintrc.BSD|.editorconfig|tsconfig.json|.coveralls.yml|appveyor.yml|.gitattributes|.eslintignore|.eslintrc|.eslintignore.BSD|.babelrc|Thumbs.db|Jenkinsfile|Gulpfile|Gruntfile|gulpfile|gruntfile|.tern-project|.stylelintrc|stylelint.config.js|.stylelintrc.json|.stylelintrc.yml|.stylelintrc.yaml|.stylelintrc.js|htmllint.js|.npmrc|.flowconfig|.documentup.json|.yarn-metadata.json|.gitlab-ci.yml|circle.yml|CHANGES|.yarn-integrity|.yarnclean|.yo-rc.json|jest.config.js|karma.conf.js|wallaby.js|wallaby.conf.js|.prettierrc|.prettierrc.yml|.prettierrc.yaml|.prettierrc.toml|.prettierrc.js|.prettierrc.json|prettierrc.config.js|tslint.json)" | xargs rm -rf;
    find node_modules -type f | grep -E "\.(md|mdon|markdown|log|ts|swp|jst|coffee|txt|BSD|m?js.map)$" | xargs rm -f;
    find node_modules -type d | grep -E "(examples|example|.github|@types)" | xargs rm -rf;

最后给大家看看我自己写的 Dockerfile,和网上的有所不同,针对大陆服务器进行了优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FROM alpine:latest
RUN echo "http://mirrors.aliyun.com/alpine/v3.11/main/" > /etc/apk/repositories && echo "http://mirrors.aliyun.com/alpine/v3.11/community/" >> /etc/apk/repositories && apk update && apk add --no-cache --update "nodejs=12.15.0-r1" nodejs-npm #使用阿里云镜像加速,锁定nodejs版本以免日后版本升级出现问题,生产环境建议锁定版本

ENV NODE_ENV production

WORKDIR /home/app

COPY package.json clean-nm.sh /home/app/

RUN npm install --production --registry=https://registry.npm.taobao.org && sh ./clean-nm.sh

COPY . /home/app

EXPOSE 8080

CMD ["npm", "start"]

docker-compose.yml 的使用

按照 docker 官方的建议,每一个容器只启动一个进程,这样便于管理和解耦。但实际生产环境中往往还会用到其他应用,例如 mongdb、redis、nginx 等等。

因此需要 docker-compose.yml 来配置多个镜像,实现集群部署

在根目录下创建并编辑 docker-compose.yaml 文件:vi docker-compose.yaml,编辑内容如下:

1
2
3
4
5
6
7
8
9
10
version: "3.6"
services:
flask-web:
build: .
ports:
- "5000:9999"
container_name: flask-web
redis:
image: redis
container_name: redis

version:版本注释,不可缺少的字段。
services:该层级下指明使用镜像开启容器的具体配置,是最主要的配置项。
flask-web、redis:自定义的该 service 名字。
build:Dockerfile 的路径,使用它来创建一个定制的镜像,或者可使用 image 指定已有镜像。
image:指定使用已有镜像。
ports:开启容器后暴露的端口映射。
container_name:指定开启容器后的容器名。

注意:docker-compose.yaml 必须按格式规范来写,最好使用两个空格来表示层级关系。每个参数前面都有一个空格。编写完后使用docker-compose config检查是否有语法错误。

大致就是如此。

下面演示一个 nodejs+redis+mongo 的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
version: "3"

services:
docker-test:
build: . #打包当前项目
restart: always
ports:
- "8080:8080" #指定端口映射
environment: #配置环境变量
NODE_ENV: production
CACHE_TYPE: redis
REDIS_URL: "redis://redis:6379/"
MONGO_URL: "mongodb://mongo:27017/docker"
depends_on:
- redis

redis:
image: redis:alpine #这里也建议锁版本
restart: always
volumes:
- redis-data:/data
mongo:
image: mongo:4.2.6 #这里也建议锁版本
restart: always
volumes:
- mongo-data:/data/db
volumes:
redis-data:
mongo-data:

本文作者:草梅友仁
本文地址: https://blog.cmyr.ltd/archives/de634aaf.html
版权声明:转载请注明出处!

坚持原创技术分享,您的支持将鼓励我继续创作!