1. 背景
在該實戰中,我們將探討如何使用Docker Compose協同部署Nginx、Java、Mysql和Redis服務,實現一個視頻上傳與展示的應用。具體需求如下:
- Java應用負責上傳視頻和圖片資源到Nginx目錄下,作為資源服務器。
- Nginx服務作為靜態資源服務器,通過URL訪問已上傳的視頻和圖片資源。
- Java服務通過讀取數據卷掛載的
/data/init.properties
文件獲取服務器的IP地址,用于拼接資源的訪問URL。
2. 實現步驟
2.1 配置Java應用讀取服務器IP
我們使用Spring的@Profile
注解和InitConfig
類,讀取部署時掛載的/data/init.properties
文件,獲取服務器IP。
拓展
:優化,可以在項目所部署的服務器上,寫一個獲取服務器IP的腳本(Centos系統Docker獲取宿主機IP地址,MAC地址,磁盤序列號和CPU序列號的shell腳本),然后java通過運行該腳本獲取服務器IP,如果買了域名,那更好了,直接省掉拼接服務器IP的步驟。
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@Profile({"pro", "docker"})
@Component
@Data
public class InitConfig {private String serverIp;@Beanpublic Map<String, String> loadLinuxConfig() {Properties prop = new Properties();try (InputStream in = new BufferedInputStream(Files.newInputStream(Paths.get("/data/init.properties")))) {prop.load(new InputStreamReader(in, StandardCharsets.UTF_8));} catch (IOException e) {log.error("Failed to load local configuration file InitConfig.properties", e);}Set<String> keySet = prop.stringPropertyNames();Map<String, String> configMap = new HashMap<>();for (String key : keySet) {String value = prop.getProperty(key);log.info("Configuration loaded: key={}, value={}", key, value);configMap.put(key, value);}serverIp = configMap.get("data.serverIp");return configMap;}
}
2.2編寫init.properties文件
data.serverIp
該key根據自己需求隨意取名。
data.serverIp=192.168.xx.xx
2.3調整Java資源列表展示接口
返回列表給前端的時候,將獲取到的服務器IP
拼接到資源的Url
中。
@Autowiredprivate VideoInfoMapper videoInfoMapper;@Autowiredprivate InitConfig initConfig;/*** 獲取資源視頻列表** @return {@link ResponseResult }* @param type 視頻類型* @param search 搜索關鍵詞* @author yangz*/@Overridepublic ResponseResult<List<VideoInfo>> getVideoList(String type, String search) {List<VideoInfo> videoList = videoInfoMapper.selectByTypeAndSearch(type, search);for (VideoInfo videoInfo : videoList) {// 構建相對路徑String relativePath = videoInfo.getFileName();// 構建完整的 URL,拼接 Nginx 的部署路徑videoInfo.setUrl( "http://"+initConfig.getServerIp()+":yourPort/static/" + relativePath);// 同樣處理 imageUrlString relativeImagePath = videoInfo.getImageName();videoInfo.setImageUrl("http://"+initConfig.getServerIp()+":yourPort/static/" + relativeImagePath);}return new ResponseResult<>(videoList);}
2.4 編寫Docker Compose 文件
這里volumes_from
屬性將Nginx容器的數據卷掛載到Java容器中,實現了兩個容器之間數據卷的共享。
這是因為Nginx容器中的/usr/share/nginx/static
目錄包含了Java上傳的靜態資源,而volumes_from
確保了Java容器可以訪問這個目錄。這樣,Nginx就能夠正確地服務Java上傳的資源了。
version: '3'
services:# Nginxnginx:image: nginx:1.22.0container_name: nginx_educationrestart: alwaysports:- "yourPort:8868"- "83:80"volumes:- ./nginx/html:/usr/share/nginx/html- ./nginx/static:/usr/share/nginx/static- ./nginx/nginx.conf:/etc/nginx/nginx.confprivileged: true# MySQLmysql:image: mysql:5.7ports:- "yourPort:3306"container_name: mysql_educationrestart: alwaysenvironment:MYSQL_ROOT_PASSWORD: yourPasswordvolumes:- ./mysql:/var/lib/mysql- ./init/:/docker-entrypoint-initdb.d/# Redisredis:image: redis:5.0.3container_name: redis_educationcommand: "/usr/local/bin/redis-server /usr/local/etc/redis/redis.conf --appendonly yes"restart: alwaysports:- "yourPort:6379"volumes:- ./redis:/data- ./redis.conf:/usr/local/etc/redis/redis.conf- ./logs/redis:/logs# Javajava:image: java:8container_name: educationports:- "yourPort:jarPort"environment:- TZ=Asia/Shanghai- LANG=en_US.UTF-8volumes:# 映射Java應用程序jar文件- ./xxx-education-xxx-0.0.1-SNAPSHOT.jar:/data/xxx-education-xxx-0.0.1-SNAPSHOT.jar# 映射Java應用程序的初始化配置文件- ./init/init.properties:/data/init.properties# 映射Java應用程序的日志目錄- ./logs:/logs# 使用volumes_from屬性,掛載Nginx容器的數據卷到Java容器volumes_from:- nginx# Java應用程序的入口命令entrypoint: nohup java -jar /data/xxx-education-xxx-0.0.1-SNAPSHOT.jar --spring.profiles.active=docker > nohup.out &depends_on:- redis- mysqlrestart: on-failure
networks:default:external:name: my-education
2.5 Nginx配置
在Nginx的配置中,我們配置了/static/
路徑的訪問規則,通過rewrite ^/(.+)/$ /$1 permanent;
將URI結尾的斜杠去掉,并使用alias
指定靜態資源的路徑。
注意
:172.17.0.1
是Docker在部署docker-compose
時創建的默認網關地址。在容器網絡中,這個地址充當了容器之間直接通信的網關。通過配置Nginx時使用這個地址,使得即使服務器IP變化,也不需要修改Nginx的代理配置。這樣一來,容器之間的通信可以通過網關地址和端口進行,實現了更加靈活和方便的部署方式。
server {listen yourPort;location / {root /usr/share/nginx/html/dist;index index.html index.htm;try_files $uri $uri/ /index.html;}# 配置靜態資源訪問的路徑location /static/ {rewrite ^/(.+)/$ /$1 permanent;alias /usr/share/nginx/static/;}location /prod-api/ {client_max_body_size 1000m;proxy_pass http://172.17.0.1:jarPort/;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $remote_addr;}error_page 500 502 503 504 /50x.html;location = /50x.html {root /usr/share/nginx/html;}
}
3. 部署與訪問
-
使用
docker-compose up -d
命令啟動所有服務。 -
訪問Java容器中的日志文件,查看Java應用啟動時是否正確加載了服務器IP。
-
通過瀏覽器訪問
http://serverIP:Port/static/
,驗證Nginx是否正確訪問了Java上傳的資源。
4. 結語
通過這個實戰,我們成功搭建了一個多服務協同部署的環境,其中Nginx作為靜態資源服務器,Java負責業務邏輯。利用Docker Compose,我們實現了服務的快速部署和環境一致性,為開發和測試提供了便利。