本文在docker 用 nginx 部署静态项目基础上,继续利用 docker 环境,运行 node,部署服务器项目,从而更多理解docker。
在网页里使用接口
上一个静态项目里,添加请求即可。接口会在服务端项目添加。
<body>
试试
<script src="https://unpkg.com/axios@0.27.2/dist/axios.min.js"></script>
<script>
axios
.get('/api/json', {
params: {},
})
.then((res) => {
console.log(res);
})
.catch((error) => {
console.log(error);
});
</script>
</body>
创建服务器项目
建一个项目文件夹demo_server,项目路径下运行npm init -y初始化下
然后yarn add express。
创建server.js写接口
项目根目录下,创建server.js。
const express = require('express');
const PORT = 8080;
const HOST = '0.0.0.0';
const app = express();
app.get('/json', (req, res) => {
res.json({
code: 0,
data: 'This is message from node container',
});
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);
拉取node公共镜像
拉取node公共镜像:
docker pull node
创建Dockerfile文件
一般自定义构建镜像,是基于Dockerfile文件构建。
项目根目录下,创建Dockerfile文件
FROM node:latest
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD [ "npm", "start" ]
FROM- 基于哪个镜像来实现WORKDIR- 工作目录COPY- 添加宿主机文件到容器里RUN- 执行的命令EXPOSE- 容器内应用可使用的端口CMD- 容器启动后,所执行的程序,如果docker run后面跟启动命令会被覆盖掉
创建.dockerignore 文件
构建镜像的时候 node_modules 的依赖直接通过 RUN npm install 来安装。
项目中创建一个 .dockerignore 文件来忽略一些直接跳过的文件:
node_modules
npm-debug.log
自定义构建应用镜像
基于Dockerfile文件,自定义构建服务器镜像:
docker build -t server_image .
-t是给镜像命名.是基于当前目录的Dockerfile来构建镜像
基于镜像启动容器
用下面命令,启动容器,之后访问
docker run -p 5000:8080 -d --name server_container server_image
基于镜像,启动容器,来提供接口服务8080端口,并映射宿主的5000端口。
跨域转发
目前静态项目的端口是3333,而服务的端口是5000,这样请求就会跨域,所以需要将静态项目容器的请求转发到服务的容器上。
查看服务容器对应的 ip
查看服务容器对应的 ip:
docker inspect server_container | grep IPAddress
可以看到是172.17.0.3,不同的可能不一样,记录这个值。
修改 nginx 配置
在静态项目的nginx/default.conf,增加一条规则
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# 增加这个
location /api/ {
rewrite /api/(.*) /$1 break;
proxy_pass http://172.17.0.3:8080;
}
将 /api/{path} 转到目标服务的 /{path} 接口上,这里的172.17.0.3就是服务容器对应的 IP。
配置负载均衡
后端服务一般都是双机或者多机以确保服务的稳定性。
我们可以再启动一个后端服务容器,并修改 nginx 的配置,来优化资源利用率,最大化吞吐量,减少延迟,确保容错配置。
先再启动一个服务容器,记录下其 IP
# 容器名和宿主的端口号 需要重命名
docker run -p 5001:8080 -d --name server_container2 server_image
# 得到容器的IP,我这里是172.17.0.4
docker inspect server_container2 | grep IPAddress
修改一下 静态项目的nginx/default.conf(新增 upstream ,修改 location /api/ 中的 proxy_pass)
server {
# ...
location /api/ {
rewrite /api/(.*) /$1 break;
# !!!修改这里
proxy_pass http://backend;
}
; ...
}
# !!!upstream要与server同级
upstream backend {
server 172.17.0.3:8080;
server 172.17.0.4:8080;
}
重启下静态项目的容器docker restart web_container
测试下 — 挂掉其中一个服务容器
docker stop server_container
刷新网页http://localhost:3333/,依旧正常~
启动容器失败 - 怎么查看原因
启动容器之后,docker ps却没发现相应的容器,可以通过logs诊断
# 比如 docker logs web_container
docker logs [容器名 或者 容器id]
写负载均衡的时候,就碰到这种问题,原来我把upstream写在server内部了,logs就提示错误信息,然后根据错误提示google了下,因此找到原因~~
docker部署egg项目
成熟的项目,一般都会有框架,docker部署node服务项目,大同小异,这边示例下egg项目的部署
1. 项目新增Dockerfile文件
项目根目录下加Dockerfile文件:
# 设置基础镜像,如果本地没有该镜像,会从Docker.io服务器pull镜像
FROM node:latest
# 配置环境变量
ENV NODE_ENV production
# 这个是容器中的文件目录
RUN mkdir -p /usr/src/app
# 设置工作目录
WORKDIR /usr/src/app
# 拷贝package.json文件到工作目录
# !!重要:package.json需要单独添加。
# Docker在构建镜像的时候,是一层一层构建的,仅当这一层有变化时,重新构建对应的层。
# 如果package.json和源代码一起添加到镜像,则每次修改源码都需要重新安装npm模块,这样木有必要。
# 所以,正确的顺序是: 添加package.json;安装npm模块;添加源代码。
COPY package.json /usr/src/app/package.json
# 安装npm依赖(使用淘宝的镜像源)
# 如果使用的境外服务器,无需使用淘宝的镜像源,即改为`RUN npm i`。
RUN npm i --production --registry=https://registry.npm.taobao.org
# 拷贝所有源代码到工作目
COPY . /usr/src/app
# 暴露容器端口
EXPOSE 9000
CMD npm start
2. 建立镜像,启动容器即可
之后建立镜像,然后启动容器即可
docker build -t egg_image ./
docker run -itd --net=host --name egg_container -p 8000:8000 egg_image
这样就可以访问http://localhost:8000
再次理解docker容器
- 镜像就像是一个安装包,每个docker容器类似新一个电脑下载了安装包然后启动
- 每个容器既然都是新电脑,那么就拥有自己独立的空间、网络。