前段时间做了个 node 全栈项目, 服务端技术栈是 nginx + koa + PostgreSQL. 其中在 CentOS 上搭建环境和部署都挺费周折, 部署测试服务器, 接着上线的时候又部署生产环境服务器. 这中间就有很多既无聊又费精力, 吃力不讨好的 "体力活". 所以就开始思考怎么自动化这部分搭建部署的工作, 也就引出了 Docker.
什么是 Docker
Docker 是比虚拟机还要轻量级的虚拟化技术, 它虚拟化的实体就叫做容器. 容器本身就是一个隔离了作用域的 sandbox, 同时它只包含了基础库和本身承载的服务, 非常精简. 容器运行起来后就只是宿主机中的一个进程而已, 占用的资源是非常小的, 这就为操作系统上运行容器集群创造了条件, 可操作性和灵活性极佳.
镜像和容器又是什么关系呢? 可以把镜像看成是类(class), 容器看成对象(object), 容器是由镜像实例化产生出来的, 当然一个镜像可以生成多个容器.
客户端 Docker
如果不在服务器, 我们在客户端要怎么使用 Docker 呢? 在 Windows 和 OS X 上可以使用 Docker Desktop, 再加上 Kitematic, 这两个都是桌面管理工具, 常规的操作方面非常便利. Docker Desktop 和 Kitematic 只是可视化了部分操作, 命令行还是必备的, 因为很多操作也只能命令行才行.
Docker 基本操作
镜像名称
关于镜像标签, 比如 nginx:1.19.0-alpine,1.19.0 是 nginx 的版本号, alpine 是 os 的代号.
- Jessie: debian 8
- Stretch: debian 9
- Buster: debian 10
Alpine: alpine, 推荐使用, 因为体积非常小
Alpine 是体积最小的一个版本, 有些甚至是其他版本的四分之一. 这意味着构建镜像更快, 运行效率更高, 因为加载的组件更加少, 无形中也意味着漏洞更少更安全.
拉取镜像
docker pull nginx:1.19.0-alpine
启动容器
--name web: 指定容器名称为 Web
-p 8080:80: 容器 nginx 监听端口为 80, 映射到本地端口 8080
-v xxxx:xxxx: 这里是用本地配置文件映射到容器 nginx 配置文件
-d: 后台运行
nginx:1.19.0-alpine: 使用的镜像
docker run --name Web -p 8080:80 -v /usr/etc/nginx/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx:1.19.0-alpine
其他操作
- docker images #显示镜像
- docker rmi xxx #删除镜像
- docker ps #显示运行的容器
- docker rm xxx #删除容器
- Dockerfile
构建镜像比较方便的是使用 Dockerfile, 它就是镜像的配置文件, 只要有 Dockerfile, 随时可以构建镜像. 如下就是构建一个非常简单的 nginx 镜像, from 就是构建时使用的基础镜像:
- FROM nginx
- COPY nginx.conf /etc/nginx/nginx.conf
- Docker-compose
当我们的项目不仅只有单个容器, 而是需要运行多个容器, 而且容器之间还需要互相通信的时候, 就需要更强大的管理工具了. 比如 k8s, 但我们目前的小项目使用官方自带的 Docker-compose 已经足矣.
首先需要 docker-compose.YAML 配置文件, 比如下面就是两个容器的模板, image 表示使用的镜像, ports 则表示端口映射, volumes 则是需要映射的数据卷:
- version: "3"
- services:
- webapp:
- image: Web
- ports:
- - "8080:80"
- volumes:
- - "/data"
- Redis:
- image: "redis:alpine"
接着可以使用以下命令行进行操作:
- docker-compose build [options] [SERVICE...] #构建 (重新构建) 项目中的服务容器
- docker-compose up -d # 运行 compose 项目, 后台执行
docker-compose up 是个非常强大的命令, 它将尝试自动完成包括构建镜像,(重新)创建服务, 启动服务, 并关联服务相关容器的一系列操作. 链接的服务都将会被自动启动, 除非已经处于运行状态. 可以说, 大部分时候都可以直接通过该命令来启动一个项目.
构建 nginx-node-postgres 项目
有了上面的基础, 接着就可以构建我们自己的项目了, 首先是 node 服务的 dockerfile, 主要做了如下步骤
创建容器工作目录
复制相关配置文件到容器
在容器安装 NPM 包
运行 pm2 启动容器
- FROM node:14.5.0-alpine3.12
- # 工作目录
- WORKDIR /usr/src/App
- # 复制配置文件
- COPY package*.JSON ./
- COPY process.YAML ./
- RUN NPM set registry https://registry.npm.taobao.org/ \
- && NPM install pm2 -g \
- && NPM install
- # 使用 pm2 管理
- CMD ["pm2-runtime", "process.yml", "--only", "app", "--env", "production"]
- EXPOSE 3010
接着配置 docker-compose.YAML
db 配置的是数据库 postgres, 其中数据卷 volumes 映射了数据库目录和初始化脚步
App 配置的是 node 服务, 其中的 build 是映射上面 dockerfile 所在的目录; depends_on 表示依赖的容器, 启动先后, 这里先启动 db 再启动 node;links 表示将 db 的名称映射到 App 容器
nginx 容器 depend_on 于 App 容器, 同时配置转发 node 的服务
- version: '3'
- services:
- db:
- image: postgres:12.3-alpine
- container_name: postgres
- environment:
- - TZ=Asia/Shanghai
- - POSTGRES_PASSWORD=xxxx
- volumes:
- - ./postgres/data:/var/lib/PostgreSQL/data
- - ./postgres/init:/docker-entrypoint-initdb.d
- ports:
- - 5432:5432
- restart: always #始终重启, 生产环境中推荐配置为 always
- expose:
- - 5432
- App:
- image: koa-pg
- container_name: koa
- volumes:
- - ./dist:/usr/src/App/dist
- - ./logs:/usr/src/App/logs
- build: ./
- environment:
- - TZ=Asia/Shanghai
- restart: always
- depends_on:
- - db
- links:
- - db
- expose:
- - 3010
- nginx:
- image: nginx:1.19.0-alpine
- container_name: nginx
- volumes:
- - ./nginx.conf:/etc/nginx/nginx.conf
- ports:
- - 8080:80
- environment:
- - TZ=Asia/Shanghai
- restart: always
- depends_on:
- - App
- links: # host 名代替 ip 配置 nginx 的转发
- - App
- expose:
- - 8080
配置完我们的项目之后, 接着就是运行起来
docker-compose up
在我们的本地开发机是如此, 部署到服务器也是如此, 你想要部署几台服务器就部署几台, 只要装了 docker, 都是一句命令行就能解决的事情.
要启动几个容器, 修改下 docker-compose.YAML 的配置, 再次 docker-compose up,so easy !
来源: http://www.jianshu.com/p/a11fe58866fb