不知道各位有没有配过开发环境和部署生产环境,我觉得但凡是搞过的,都要踩很多坑。
比如,原项目是在linux上开发的,clone下来用windows的npm install或者yarn install后发现不work。
或者在windows上开发好后,在linux上部署的时候一堆坑,比如nginx配置问题了,比如CORS问题了,比如vite打包问题了,node_modules依赖问题,等等。
甚至你跟另一个人在同一个型号同样版本的开发环境下,把你的文件夹给他,他都不一定能直接运行。
但是Docker
能解决上面大部分问题。
什么是Dcoker?
Docker是一个开源的容器化应用平台,它允许开发者打包一个应用以及其依赖库到一个可移植的容器中,然后发布到任何运行docker的机器上,而不需要考虑环境配置。Docker的容器化是基于命名空间(namespace)的,它允许容器拥有独立的系统资源视图,包括进程ID、网络接口、挂载点等。这种隔离确保了容器内的变更不会影响到宿主机或其他容器。所以我们完成可以build很多个docker image(可以理解为源文件打包好的程序),通过docker network将不同image run(可以理解为实际运行的程序)的容器连接起来,实现容器化应用。每个image只需要实现一个单一集成功能(数据库,反向代理)即可。
Docker安装
Docker的安装有很多种,但有时候稍不注意会猜到大坑,这里我介绍在linux上安装docker的方法(deb系)
1 2 3 4 5 6
| sudo apt update sudo apt install apt-transport-https ca-certificates curl software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable" sudo apt update sudo apt install docker-ce
|
注意,如果是新手,不要运行apt install docker
、apt install docker.io
别问我怎么知道的
Docker基本命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 开关服务类 sudo systemctl restart docker sudo systemctl status docker sudo systemctl daemon-reload # 镜像类 docker pull xx docker push docker images docker rmi docker tag # 容器类 docker run docker ps docker stop docker rm docker exec docker logs
|
配置Proxy 极为重要
由于一些原因现在docker镜像的下载上传受限制,而且国内的镜像站也基本都不work了,所以配置好自己的proxy很重要,这里以我的配置经历给参考(可能有多余操作)
1 2 3 4
| sudo vim /etc/resolv.conf #add those lines nameserver 8.8.8.8 nameserver 8.8.4.4
|
1 2
| cd /etc/systemd/system/docker.service.d/ sudo vim http-proxy.conf
|
你大概会看到这几行
1 2 3 4
| [Service] Environment="HTTP_PROXY=http://example.com:8080/" Environment="HTTPS_PROXY=http://example.com:8080/" Environment="NO_PROXY=http://your_example_proxy.com"
|
没有也不要紧,加上以下内容:(如果你用Clash)
1 2 3 4
| Environment="HTTP_PROXY=http://127.0.0.1:7890/" Environment="HTTPS_PROXY=http://127.0.0.1:7890/" #这行是镜像站,随便填一个就好 Environment="NO_PROXY=http://your_example_proxy.com"
|
或者你用V2ray
1 2 3
| Environment="HTTP_PROXY=http://127.0.0.1:10808/" Environment="HTTPS_PROXY=http://127.0.0.1:10808/" Environment="NO_PROXY=http://your_example_proxy.com"
|
Dockerfile
因为对于开发而言,一般都是各种FROM
去拉取一些基础镜像,然后安装各种依赖,然后RUN
各种命令,最后再COPY
各种文件到容器里,最后再CMD
运行项目。所以我先讲一个简单的Dockerfile,然后举一个我实际再跑的项目的比较复杂且规范的Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12
| FROM python:3
COPY ./docker /app
WORKDIR /app
RUN pip install -r requirements.txt
EXPOSE 80
CMD ["python", "app.py"]
|
Docker会根据Dockerfile的描述来一步一步构建能够最终运行程序的镜像
运行命令为:
1
| docker build -t my-app:latest .
|
再来看一个复杂一点的文件来感受一下
先看具体运行的命令
1
| docker compose -f docker-compose.yml up -d
|
我自己的项目总的来说是一个vite打包好的前端vue运行3000端口(需要预先打包),一个后端Springboot运行8080端口,redis中间件占用6379端口,一个mysql数据库占用3306端口,一个nginx反向代理运行80端口。应用vue可以提前打包所以这里只需要运行4个服务即可。需要FROM
引几个基础镜像,然后COPY
一些文件到容器里,然后RUN
一些命令比如mysql的数据导入,最后再CMD
运行项目。
先在项目文件夹执行
在IDEA中,找到target文件夹里的xxx.-SNAPSHOT.jar文件,将这个文件复制到backend文件夹里面(不要按照网上说的用Artifacts导出)
Nginx 配置文件 nginx.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| server { listen 80; server_name localhost; root /usr/share/nginx/html;
location / { index index.html; try_files $uri $uri/ /index.html; }
location /api { proxy_pass http://backend:8080/; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; } }
|
Redis 配置文件 redis.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| # Redis 服务器的端口号(默认:6379) port 6379
# 绑定的 IP 地址,如果设置为 127.0.0.1,则只能本地访问;若设置为 0.0.0.0,则监听所有接口(默认:127.0.0.1) bind 0.0.0.0
# 设置密码,客户端连接时需要提供密码才能进行操作,如果不设置密码,可以注释掉此行(默认:无) # requirepass foobared requirepass 123456
# 设置在客户端闲置一段时间后关闭连接,单位为秒(默认:0,表示禁用) # timeout 0
# 是否以守护进程(daemon)模式运行,默认为 "no",设置为 "yes" 后 Redis 会在后台运行 daemonize no
# 设置日志级别(默认:notice)。可以是 debug、verbose、notice、warning loglevel notice
# 是否启用 AOF 持久化,默认为 "no"。如果设置为 "yes",将在每个写操作执行时将其追加到文件中 appendonly no
|
同时需要在Navicat或者其他软件把你的项目数据库全部导出。
springboot的配置文件application.properties也可以跟上述配置文件放在一起,配置好后在docker network中做更改更方便。
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
| spring.application.name=backend server.port = 8080
spring.aop.auto=true
spring.datasource.url=${SPRING_DATASOURCE_URL} spring.datasource.username=${SPRING_DATASOURCE_USERNAME} spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}
spring.mail.host=smtp.qq.com spring.mail.port=587 spring.mail.username= xx@qq.com #需要更换为自己的邮箱服务 spring.mail.password= xxxx #需要更换为自己的邮箱服务密钥 spring.mail.default-encoding=UTF-8 spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true
spring.data.redis.host=${SPRING_REDIS_HOST} spring.data.redis.port=${SPRING_REDIS_PORT} spring.data.redis.password=${SPRING_REDIS_PASSWORD} spring.data.redis.database=0
mybatis-plus.mapper-locations=classpath:mapper/*.xml mybatis-plus.type-aliases-package=com.mybatis-plus.model spring.servlet.multipart.max-file-size= 10MB spring.servlet.multipart.max-request-size= 100MB spring.web.resources.static-locations=file:./uploads/
|
最后的docker文件
docker-compose.yml
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
| version: '3.8'
services:
nginx: image: nginx:latest container_name: scu_oasystem_nginx ports: - "80:80" volumes: - ../frontend/dist:/usr/share/nginx/html - ./nginx.conf:/etc/nginx/conf.d/default.conf depends_on: - backend networks: - oasystem_network
backend: image: openjdk:21 container_name: scu_oasystem_backend working_dir: /app volumes: - ../backend/backend.jar:/app/backend.jar - ./application.properties:/app/application.properties ports: - "8080:8080" command: java -jar backend.jar --spring.config.location=/app/application.properties environment: - SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/oa_database?useSSL=false&allowPublicKeyRetrieval=true - SPRING_DATASOURCE_USERNAME=root - SPRING_DATASOURCE_PASSWORD=123456 - SPRING_REDIS_HOST=redis - SPRING_REDIS_PORT=6379 - SPRING_REDIS_PASSWORD=123456 depends_on: db: condition: service_started redis: condition: service_started networks: - oasystem_network
redis: image: redis:6.0 container_name: scu_oasystem_redis ports: - "6379:6379" volumes: - ./redis.conf:/etc/redis/redis.conf - ./redis/data:/data - ./redis/logs:/logs command: redis-server /etc/redis/redis.conf depends_on: db: condition: service_started networks: - oasystem_network
db: image: mysql:5.7 container_name: scu_oasystem_db ports: - "3306:3306" environment: - MYSQL_ROOT_PASSWORD=123456 volumes: - /usr/local/mysql/conf:/etc/mysql/conf.d - ./mysql/data:/var/lib/mysql - ./init.sql:/docker-entrypoint-initdb.d/init.sql networks: - oasystem_network
networks: oasystem_network: driver: bridge
|