创建dockerfile

创建一个Dockerfile用于构建Nginx容器。

1
2
3
4
5
6
7
8
9
10
11
12
# 使用Nginx镜像作为基础镜像 最新版本
FROM nginx:latest

# 删除默认Nginx配置
RUN rm /etc/nginx/conf.d/default.conf

# 复制自定义Nginx配置文件 只能复制同级目录下的文件
# 这种复制的并不灵活 如果我们确定以后一定不会有改动,或者如果有改动就进行删除容器然后在重新创建,或者进入docker bash 去里面改的话,不觉得麻烦的话也可以采用这种方式
COPY nginx.conf /etc/nginx/conf.d/

# 复制前端构建好的项目文件到Nginx的webroot目录
COPY dist/ /usr/share/nginx/html

image-20231011213424645

创建Nginx配置文件

推荐文章:

在Dockerfile所在目录创建一个Nginx配置文件(例如nginx.conf)。

多环境配置:

花了很多时间去调试这个,直接哭死。

不过我用的是映射,相对好一些,试想一下如果用第一种岂不是累死,当然也可以进入容器内部进行调试

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
events {
worker_connections 1024;
}
http{
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# 解决前端页面css样式失败原因
include mime.types;
default_type application/octet-stream;
# ---------------------------
# 负载均衡
upstream service_oj{
server 47.95.26.11:8101 max_fails=1 fail_timeout=60s weight=1;
}
# 要放在 '/code/nginx/' 目录下
server {
#监听的端口,80端口是默认端口,在访问时,就无需输入端口号,其他的都需要输入端口号,比如这里访问地址就是127.0.0.1,而若是8080端口,则是127.0.0.1:8080
listen 80;
#编码
charset utf-8;
# 此处localhost可改为要访问的域名或者ip地址,若有多个用空格隔开。例如 server_name www.baidu.com baidu.com test.baidu.com
server_name www.staro.cc; # 替换为您的域名
# 配置默认 nginx默认的根目录访问的是html下的index.html页面
location / {
#nginx下HTML文件夹,访问上述域名时会检索此文件夹下的文件进行访问
root html;
#输入网址(server_name:port)后,默认的访问页面
index index.html index.htm;
}

# oj 项目配置 路径 例如: www.baidu.com/oj/..... 前端路径
location ^~/oj {
alias /usr/share/nginx/html/web/staroj-frontend/dist;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'POST, GET, PUT, OPTIONS, DELETE';
add_header Access-Control-Allow-Headers 'Origin, X-Requested-With, Content-Type,Accept, token';
try_files $uri $uri/ /oj/index.html;
}

# oj 后端配置
location /ojbackend/ {
add_header Access-Control-Allow-Origin "$http_origin" always ;
add_header Access-Control-Allow-Methods 'GET,POST,OPTIONS, DELETE';
add_header Access-Control-Allow-Headers 'token, Accept, Origin, XRequestedWith, Content-Type, LastModified';
add_header Access-Control-Allow-Headers 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild';
client_max_body_size 40m;
proxy_redirect http:// https://;
proxy_pass http://service_oj/api/;
proxy_redirect default;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Origin $http_origin;
# 把host头传过去,后端服务程序将收到your.domain.name, 否则收到的是localhost:8080
# 把cookie中的path部分从/api替换成/
proxy_cookie_path /ojbackend/ /api;
}

# oj-sandbox 后端配置
location /ojSandboxApi/ {
add_header Access-Control-Allow-Origin "$http_origin" always ;
add_header Access-Control-Allow-Methods 'GET,POST,OPTIONS, DELETE';
add_header Access-Control-Allow-Headers 'token, Accept, Origin, XRequestedWith, Content-Type, LastModified';
add_header Access-Control-Allow-Headers 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild';
client_max_body_size 40m;
proxy_redirect http:// https://;
proxy_pass http://47.95.26.11:8124/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Origin $http_origin;
}

# 如果以后有其他配置 就进行复制更改
# location /wiki {
# root html/web/wiki;
# index index.html;
# }

}
}

单环境配置:

1
2
3
4
5
6
7
8
9
10
server {
listen 80;
server_name your_domain; # 将 your_domain 替换为您的域名

location / {
proxy_pass http://127.0.0.1:your_port; # 将 your_port 替换为您的目标端口
proxy_set_header Host $host; # 主要是确保目标服务器知道请求是针对哪个域名的
proxy_set_header X-Real-IP $remote_addr; # 确保服务器记录客户端的真实IP地址
}
}

构建Docker镜像

在包含Dockerfile的目录中运行以下命令构建Docker镜像。

1
2
docker build -t my-image-name .   #  my-imag 镜像名称 通过当前目录下的dockerfile
docker run -d --name my-container-name my-image-name # 运行镜像 当然也可以在后面再跟一些容器配置

优化

这样我们就实现了nginx的部署,但是还是有很多优化的地方

这里我也踩了一些坑,比如想着如果能实现通用,同时知道了dockerfile或者说docker compose 的路径都是基于上下文的不能选择上一层级的路径

路径映射

这个是个错误示范 因为dockerfile 路径都是基于上下文的不能选择上一层级的路径

1
2
3
4
5
6
7
8
9
10
11
12
# 使用Nginx镜像作为基础镜像 最新版本
FROM nginx:latest

# 删除默认Nginx配置 这里不删除也可以
RUN rm /etc/nginx/conf.d/default.conf

# 前端路径映射 这样是不行的
# 做文件路径映射到容器中的Nginx配置目录
VOLUME /code/nginx/config:/etc/nginx/conf.d

# 做文件路径映射到Nginx的webroot目录
VOLUME /code/nginx/web:/usr/share/nginx/html/web

如果更改呢?

解决办法:可以把dockerfile移动到nginx目录下,如下文

1
2
3
4
5
6
7
8
9
10
11
12
# 使用Nginx镜像作为基础镜像 最新版本
FROM nginx:latest

# 删除默认Nginx配置 这里不删除也可以
RUN rm /etc/nginx/conf.d/default.conf

# 前端路径映射
# 做文件路径映射到容器中的Nginx配置目录
VOLUME ./config:/etc/nginx/conf.d

# 做文件路径映射到Nginx的webroot目录
VOLUME./web:/usr/share/nginx/html/web

使用docker compose启动

上文是使用了dockerfile,相比较的话我更喜欢docker compose 启动,dockerfile我感觉就在文件目录下的,个人感觉,同时docker compose 比dockeffile集成的东西比较多一些,当然两者也是相互相成的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
version: '3'
services:
staroj-frontend:
image: nginx:latest
container_name: nginx-frontend # 启动的实例名称
ports:
- "80:80" # 端口映射
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf # 配置映射
- ./html:/usr/share/nginx/html # 前端映射
restart: always # 崩溃后自动重启
privileged: true # 这个必须要,解决nginx的文件调用的权限问题
networks:
- mynetwork

# 网络,不定义的话就是默认网络
networks:
mynetwork:

image-20231015142747532

docker compose 启动命令 :

1
2
3
docker compose -f docker-compose.nginx.yml up -d
-f 是指定文件 如果当前目录只有一个yml 文件是可以省略的
-d 是后台运行

如果修改了nginx配置只需要进行重启容器即可。

前端部署问题

前端实际也有很多坑

  • 资源路径请求问题:nginx分配的是/oj路径,访问可以访问,但是他请求资源的时候会把`/oj给去掉去获取,这样的话就会形成一个前端获取不到js\css… 问题,

    要解决这个问题只需要在

    前端 vue.config.js进行修改

    1
    2
    3
    module.exports = {
    publicPath: process.env.NODE_ENV === "production" ? "/oj/" : "/",
    }

    前端router/index.ts进行修改

    1
    2
    3
    4
    5
    6
    const router = createRouter({
    history: createWebHistory(
    process.env.NODE_ENV === "production" ? "/oj/" : "/"
    ),
    routes,
    });

​ 上面的问题解决了,可是我们也需要启动配置环境变量来进行区分,不然一样会有些问题

​ 1) 创建环境变量文件 .env.dev.env.prod , .env是必须的后面的自定义,一般的话都是这两个

image-20231015144255661

​ 2)编写

1
2
3
// 开发环境 .env.dev
NODE_ENV = development
VUE_APP_BASE_URL = http://localhost:8101/api

1
2
3
//.env.prod 线上环境
NODE_ENV = production
VUE_APP_BASE_URL = http://item.staro.cc/ojbackend

​ 3)编写启动环境配置 pakage.js

image-20231015144620863

前端加载不出css

这是nginx配置的问题

查看nginx配置

1
2
 include mime.types;
default_type application/octet-stream;

请求拦截器问题

如果用的不是openapi-typescript-codegen自定生成代码那么就无须关注这个问题

请求问题官方文档:https://github.com/ferdikoomen/openapi-typescript-codegen/blob/master/docs/custom-request-file.md

如果需要请求头设置token: https://github.com/ferdikoomen/openapi-typescript-codegen/blob/master/docs/authorization.md

自定义APIOpen信息:https://github.com/ferdikoomen/openapi-typescript-codegen/blob/master/docs/openapi-object.md

这个自定义APIOpen信息可以解决每次更新覆盖的问题的

token之前测了一下没有发送,不知道为什么,感兴趣的可以去尝试一下,所以我是去request.ts里面去进行更改,添加token的

如果我们自定义的文档同时希望再次更新的时候不希望进行覆盖:我们可以使用命令 进行排除

npx openapi-typescript-codegen --input ./spec.json --output ./generated --request ./request.ts

request .ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export const sendRequest = async <T>(
config: OpenAPIConfig,
options: ApiRequestOptions,
url: string,
body: any,
formData: FormData | undefined,
headers: Record<string, string>,
onCancel: OnCancel,
axiosClient: AxiosInstance
): Promise<AxiosResponse<T>> => {
const source = axios.CancelToken.source();

const token = store.state.token;
headers['Authorization'] = "Bearer " + token;
......