本文將帶大家從一臺全新的 CentOS 伺服器開始,部署一套完整的前後端分離專案。操作步驟非常詳細,新手友好型文章~
後端技術棧:SpringCloud 微服務架構 + Redis + RabbitMQ + MySql;
前端技術棧:Vue + ElementUI;
部署工具:後端用 Docker 容器化部署,並把命令封裝成指令碼自動執行;前端用 Nginx 做代理。
一、前期準備
系統版本為:CentOS 7.6 64位。
1.1 連線伺服器
要對遠端伺服器進行操作,首先要連上伺服器才行。開啟命令列工具,輸入以下命令,再輸入伺服器例項的密碼,即可遠端連線到伺服器。
ssh root@xxx.xx.xx.xx
複製程式碼
@
之後是伺服器的公網 ip,假如伺服器 ip 地址為:120.456.78.123,那麼連線伺服器的命令為:
ssh root@120.456.78.123
複製程式碼
敲回車之後會讓輸入密碼,輸入正確的密碼即可。
1.2 安裝 Docker
Docker 容器化部署的優點就不多說了,直接上乾貨如何安裝 Docker。
下面直接把程式碼框裡的命令拷貝到命令列執行就可以。
先移除舊版本(如果有):
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine
複製程式碼
安裝一些必要的工具:
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
複製程式碼
新增軟體源資訊:
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
複製程式碼
更新 yum 快取:
sudo yum makecache fast
複製程式碼
安裝 Docker-ce:
sudo yum -y install docker-ce
複製程式碼
啟動 Docker 後臺服務
sudo systemctl start docker
複製程式碼
測試執行 hello-world(這步可要可不要,目的是驗證身份安裝 Docker 成功,如果成功會列印出 Hello World)
docker run hello-world
複製程式碼
1.3 安裝 mysql
拉取 mysql5.7 版本的映象
docker pull mysql:5.7
複製程式碼
執行 MySql
docker run -p 3306:3306 --name mysql -v $PWD/conf:/etc/mysql/conf.d -v $PWD/logs:/logs -v $PWD/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
複製程式碼
命令說明:
- -p 3306:3306:將容器的 3306 埠對映到主機的 3306 埠。
- -v $PWD/conf:/etc/mysql/conf.d:將主機當前目錄下的 conf/my.cnf 掛載到容器的 /etc/mysql/my.cnf。
- -v $PWD/logs:/logs:將主機當前目錄下的 logs 目錄掛載到容器的 /logs。
- -v $PWD/data:/var/lib/mysql :將主機當前目錄下的data目錄掛載到容器的 /var/lib/mysql 。
- **-e MYSQL_ROOT_PASSWORD=123456:**初始化 root 使用者的密碼。
注意在執行之前切換到合適的目錄,因為 MySql 容器對映到本機的目錄是對映的當前目錄的相對目錄。比如當前目錄為 /root/abc
,那執行完上面的命令後,會在 /root/abc
下建立 MySql 掛載出來的目錄和檔案。
1.4 安裝 redis
也可以直接執行執行命令,如果系統檢測到沒有安裝此映象,則會拉取安裝,再執行。
下載並執行 redis:4.0.8
:
docker run -p 6379:6379 -t -dit redis:4.0.8
複製程式碼
1.5 安裝 RabbitMQ
跟上面一樣也是直接執行執行命令安裝並執行 rabbitmq:3.7.7
:
docker run -d --hostname my-rabbit -p 5672:5672 -p 15672:15672 rabbitmq:3.7.7-management
複製程式碼
到此部署微服務後端專案的前期環境準備工具已經做完。如果要部署前端還需要安裝 Nginx,這個在前端部署的章節再講。
二、後端部署
部署後端需要做的工作有兩個,一個是修改每個微服務模組的配置檔案 application.yml
,另一個是編寫 Dockerfile
。
先看目錄結構:
一共有 5 個模組,其中 common
是純 java 程式碼用於各模組公共程式碼的提取,剩下四個每個是一個獨立的微服務模組,所以我們要部署 eureka
、user
、education
、gateway
四個模組,也就是最後會執行四個獨立的 docker 容器。
具體的業務邏輯就不做過多說明了,本文只講部署。
2.1 配置檔案 application.yml
為了本地除錯和伺服器部署互不影響,我們把原來的 application.yml
拆分為三個檔案:
application.yml
:總配置,指定應該用下面哪個配置application-dev.yml
:開發環境配置application-pro.yml
:生成環境配置
另外為了方便,把 Dockerfile 也放到同級目錄下。如圖:
下面是三個配置檔案的程式碼:
application.yml
spring:
profiles:
active: pro
複製程式碼
application-dev.yml
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
server:
port: 8899
spring:
application:
name: education
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://127.0.0.1/edu?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
jpa:
show-sql: true
# 如果欄位值為null則不返回
jackson:
default-property-inclusion: non_null
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
redis:
port: 6379
database: 0
host: 127.0.0.1
password:
jedis:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 0
timeout: 5000ms
複製程式碼
application-pro.yml
eureka:
client:
service-url:
defaultZone: ${SPRING-CLOUD-EUREKA-ZONE}
instance:
prefer-ip-address: true
server:
port: 8899
spring:
application:
name: education
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://${SPRING-CLOUD-MYSQL-HOST}/${SPRING-CLOUD-DB-NAME}?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
jpa:
show-sql: true
# 如果欄位值為null則不返回
jackson:
default-property-inclusion: non_null
rabbitmq:
host: ${SPRING-CLOUD-RABBIT-MQ-HOST}
port: 5672
username: guest
password: guest
redis:
port: 6379
database: 0
host: ${SPRING-CLOUD-REDIS-HOST}
password:
jedis:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 0
timeout: 5000ms
複製程式碼
這個專案配置比較全,redis、rabbitMQ、mysql、jpa 都有配置。
dev 跟 pro 的配置差不多,只是把 dev 中的 localhost
、127.0.0.1
這兩個本地的地址,換成了諸如 ${SPRING-CLOUD-EUREKA-ZONE}
、${SPRING-CLOUD-RABBIT-MQ-HOST}
等變數。
那這些變數是在哪設定的呢?待會兒編寫 Dockerfile 的時候就可以看到,會在 Dockerfile 裡設定這幾個變數為環境變數,當啟動 Docker 容器的時候,程式就會讀取到 Dockerfile 中設定的值並應用到專案中。
2.2 編寫Dockerfile
下面是 education
模組的 Dockerfile
FROM java:8
VOLUME /tmp
ADD education.jar app.jar
RUN bash -c 'touch /app.jar'
ENV SPRING-CLOUD-EUREKA-ZONE http://123.456.789.10:8761/eureka/
ENV SPRING-CLOUD-MYSQL-HOST 123.456.789.10
ENV SPRING-CLOUD-DB-NAME edu
ENV SPRING-CLOUD-RABBIT-MQ-HOST 123.456.789.10
ENV SPRING-CLOUD-REDIS-HOST 123.456.789.10
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
EXPOSE 8899
複製程式碼
簡單的解釋下每句話的作用
FROM java:8
: 指定基礎映象,必須為第一個命令
VOLUME /tmp
: 用於指定持久化目錄
ADD education.jar app.jar
: 將本地檔案education.jar
新增到容器中並命名為app.jar
。注意這裡的education.jar
要換成你自己專案打包出來的 jar 包名字,如果你打的包名字叫abc.jar
,那應該這麼寫:ADD abc.jar app.jar
。
RUN bash -c 'touch /app.jar'
: 在映象容器中執行的命令,執行 jar 包。
ENV ***
: 這幾行以 ENV 開頭的是設定環境變數,還記得上面application-pro.yml
檔案裡的那幾個${}
變數嗎?就是在這裡設定的。把該填地址的地方都換成這臺伺服器的公網 ip 地址,本配置假設你伺服器的地址是123.456.789.10
,用的時候把這個地址換成你自己伺服器地址即可。
ENTRYPOINT ***
: 配置容器,使其可執行化。
EXPOSE 8899
: 對外暴露 8899 埠。這個埠要和專案的配置檔案中server.port
設定的埠一致。
總結一下,Dockerfile 檔案你要改的,只有三個地方:
- 第三行 education.jar 換成你打包出來的 jar 包名字
- ENV 開頭的環境變數自己根據
application-pro.yml
的配置進行設定 - 最後一行
EXPOSE 8899
改成你專案的埠號
再貼一個模組的 Dockerfile 作對比:
FROM java:8
VOLUME /tmp
ADD gateway.jar app.jar
RUN bash -c 'touch /app.jar'
ENV SPRING-CLOUD-EUREKA-ZONE http://123.456.789.10:8761/eureka/
ENV SPRING-CLOUD-REDIS-HOST 123.456.789.10
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
EXPOSE 8888
複製程式碼
按照這種方法,把每個需要打包的微服務專案的 Dockerfile 寫好。
2.3 打包
配置好三個 applicaiton.yml
和 Dockerfile(其實打包這一步用不到 Dockerfile),在專案的根目錄下執行以下命令打包:
mvn clean package -Dmaven.test.skip=true
複製程式碼
看到控制檯輸出 SUCCESS 則打包成功
打完的包在 專案目錄/target
裡,如圖:
檢查一下 jar 包的大小,如果是好幾十 M 就沒啥問題,如果是幾百 K 那就是打包配置有問題,檢查 pom.xml
檔案的 <build>
標籤配置是否正確。
附 <build>
配置:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<finalName>education</finalName>
</build>
複製程式碼
2.4 編寫自動化指令碼
寫完 Dockerfile 檔案還要執行命令打包成 image 映象,還需要執行起容器,兩行程式碼雖然不多但每次寫還是麻煩,把它封裝成一個 sh
指令碼,每次直接執行指令碼省時省力。
新建 education_deploy.sh
檔案,把兩行程式碼放進去:
docker build -t education .
docker run -p 8899:8899 -t -dit --restart=always education
複製程式碼
注意第一行最後有個點 .
,如果你想把打出來的映象名叫 abc
,對外暴露的埠是 6666
,則應該這樣寫:
docker build -t abc .
docker run -p 6666:6666 -t -dit --restart=always abc
複製程式碼
2.4 上傳到伺服器
新建一個資料夾,併為每個微服務模組新建一個資料夾用於存放 jar 包、Dockerfile 和自動化部署檔案,目錄結構如圖:
把 back_end 這個資料夾整體壓縮,壓縮命令為:
tar -cvf back_end.tar ./back_end
複製程式碼
執行完後會在目錄下看到 back_end.tar
壓縮檔案。
使用 ssh 命令登入到伺服器,根目錄下新建一個 edu
資料夾,進入這個資料夾,檢視當前目錄,記住這個目錄
//新建資料夾 edu
mkdir edu
//進入到 edu 資料夾內
cd edu
//檢視當前目錄,會輸出:/root/edu
pwd
複製程式碼
記住你要傳到伺服器的位置:/root/edu
,再回到本機剛才壓縮 back_end.tar
檔案的目錄,執行以下命令把 back_end.tar
傳送到伺服器的 /root/edu
目錄下:
scp back_end.tar root@123.456.789.10:/root/edu
複製程式碼
上傳完之後,在伺服器解壓
tar -xvf back_end.tar
複製程式碼
然後依次進入到各個模組的資料夾內,執行 sh 指令碼
sh ./education_deploy.sh
複製程式碼
都執行完之後後端微服務就部署完啦!
2.5 常用 Docker 命令
部署完還要檢驗是否部署正確,先從 Docker 開始檢查,最後在瀏覽器輸入介面地址看能否調通。
下面的命令都在 CentOS 伺服器上執行。
檢視當前執行的容器,看 mysql、redis、rabbitMQ 和你自己的專案是否執行
docker ps
複製程式碼
檢視日誌
想進入到容器中檢視日誌:
docker logs 容器id
複製程式碼
比如想檢視容器id為 378af204f7bc 的容器日誌,應該執行:
docker logs 378af204f7bc
複製程式碼
如果容器執行了很長時間,將會產生非常多的日誌,直接使用 docker logs
會把所有日誌都列印出來,可不可以只列印最後多少行或者從某個時間之後的日誌呢?當然可以。
檢視指定時間後的日誌,只顯示最後100行:
docker logs -f -t --since="2019-10-24" --tail=100 CONTAINER_ID
複製程式碼
只列印最後50行日誌:
docker logs --tail=50 容器id
複製程式碼
檢視最近30分鐘的日誌:
docker logs --since 30m 容器id
複製程式碼
檢視某時間之後的日誌:
docker logs -t --since="2019-10-24T13:23:37" CONTAINER_ID
複製程式碼
檢視某時間段日誌:
docker logs -t --since="2019-10-24T13:23:37" --until "2019-10-25T12:23:37" CONTAINER_ID
複製程式碼
停止和啟動
停止容器
docker stop 容器id
複製程式碼
檢視所有容器(包括已經停止的)
docker ps -a
複製程式碼
重新啟動容器(容器被停止了,但還未被刪除)
docker start 容器id
複製程式碼
刪除容器和映象
如果專案有改動,最好把之前的容器、映象都刪掉,再執行新的容器。
先停止容器
docker stop 容器id
複製程式碼
再刪除容器
docker rm 容器id
複製程式碼
檢視 image 映象
docker images
複製程式碼
刪除映象
docker rmi 映象id
複製程式碼
三、前端部署
先把前端專案打包,壓縮為 tar 檔案,傳送到伺服器上,在伺服器解壓。
要用 nginx 做代理需要先安裝 nginx
3.1 安裝 nginx
先下載安裝基礎庫
yum -y install gcc gcc-c++ autoconf pcre pcre-devel make automake
yum -y install wget httpd-tools vim
複製程式碼
安裝 nginx
sudo yum install nginx
複製程式碼
3.2 配置 nginx
nginx 的配置檔案目錄
nginx主配置檔案
/etc/nginx/nginx.conf
/etc/nginx
/etc/nginx/conf.d
/etc/nginx/conf.d/default.conf
複製程式碼
我們來看 nginx.conf
預設的配置是什麼樣
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2 default_server;
# listen [::]:443 ssl http2 default_server;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# location / {
# }
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }
}
複製程式碼
修改 nginx.conf
的 server 節點,我們依然監聽 80埠,改 server_name
為你的域名,然後修改 location
,root
為前端檔案所在目錄,index
為入口檔案。
location / {
root /root/edu/front_end/;
index index.html index.htm;
}
複製程式碼
只改這兩處即可,別的地方不要動。
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name www.abc.cn abc.cn;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
root /root/edu/front_end/;
index index.html index.htm;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
複製程式碼
改完儲存成功之後,檢查 nginx 配置,結果出現 successful 表示配置檔案沒有語法錯誤
nginx -t -c /etc/nginx/nginx.conf
複製程式碼
重新載入配置
nginx -s reload -c /etc/nginx/nginx.conf
複製程式碼
3.3 nginx 報錯整理
[error] open() "/var/run/nginx.pid" failed
重新載入配置時有時會報錯:nginx: [error] open() "/var/run/nginx.pid" failed (2: No such file or directory)
解決方法:依次執行下面兩行程式碼
sudo nginx -c /etc/nginx/nginx.conf
nginx -s reload
複製程式碼
瀏覽器訪問報 403
用瀏覽器訪問域名,報 403 錯誤,要具體看到底是哪裡出錯了可以檢視 nginx 錯誤日誌,錯誤日誌在哪放著呢? nginx.conf
檔案裡指明瞭:error_log /var/log/nginx/error.log;
用 cat 命令檢視檔案內容
cat /var/log/nginx/error.log
複製程式碼
如果報了 Permission denied,有很大可能是當前登入使用者跟 nginx.conf
檔案第一行宣告的使用者不匹配。
connect() to 127.0.0.1:8000 failed (13: Permission denied)....
複製程式碼
將 user nginx;
改為 user root;
再次重新載入配置一般就可以解決。
以上就是部署前後端的全部內容,大佬們有問題可以在評論區交流。