熱部署(Hot Deploy):
熱部署針對的是容器或者是整個應(yīng)用,部署了新的資源或者修改了一些代碼,需要在不停機的情況下的重新加載整個應(yīng)用。
熱加載(Hot Swap):
熱加載針對的是單個字節(jié)碼]文件,指的是重新編譯后,不需要停機,應(yīng)用程序就可以加載使用新的class文件。
springBoot熱部署原理是:當我們使用編譯器啟動項目后,在編譯器上修改了代碼后,編譯器會將最新的代碼編譯成新的.class文件放到classpath下;而引入的spring-boot-devtools插件,插件會監(jiān)控classpath下的資源,當classpath下的資源改變后,插件會觸發(fā)重啟;
而重啟為什么速度快于我們自己啟動呢?
我們自己啟動的時候,是加載項目中所有的文件(自己編寫的文件 + 所有項目依賴的jar)
而加入了spring-boot-devtools插件依賴后,我們自己編寫的文件的類加載器為org.springframework.boot.devtools.restart.classloader.RestartClassLoader,是這個工具包自定義的類加載器, 項目依賴的jar使用的是JDK中的類加載器(AppClassLoader\ExtClassLoader\引導(dǎo)類加載器)
在插件觸發(fā)的重啟中,只會使用RestartClassLoader來進行加載(即:只加載我們自己編寫的文件部分)
這是SpringBoot提供的熱部署工具,添加依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
實現(xiàn)資源修改后的自動重啟等功能。啟動應(yīng)用程序時,DevTools會自動配置熱部署,并在保存文件時重新啟動應(yīng)用程序。DevTools還提供了其他功能,如自動重新啟動、自動刷新頁面等,以提高開發(fā)效率。
Spring LoadedSpring的熱部署程序,實現(xiàn)修改類后的自動重載。實現(xiàn)原理是使用自定義ClassLoader,可以實現(xiàn)代碼熱替換。具體實現(xiàn)如下:
(1)在pom.xml文件中添加Spring Loaded的依賴:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.8.RELEASE</version>
</dependency>
(2)在IDE或編譯器中配置項目的自動構(gòu)建功能。確保在保存文件時自動重新構(gòu)建項目
(3)啟動應(yīng)用程序時,添加以下JVM參數(shù):
-javaagent:/path/to/springloaded.jar -noverify
其中/path/to/springloaded.jar是Spring Loaded JAR文件的路徑,根據(jù)你的實際情況進行相應(yīng)的修改。
(4)啟動應(yīng)用程序并進行開發(fā)
每當保存文件時,Spring Loaded會自動檢測到更改并重新加載修改后的類,使得你的更改能夠立即生效。
需要注意的是,Spring Loaded是一個第三方庫,使用它可能會有一些限制和不穩(wěn)定性。Spring官方已經(jīng)不再維護Spring Loaded
JRebel收費的熱部署軟件,需要添加JRebel插件,可以實現(xiàn)代碼熱部署。效果非常好,但是需要付費使用。
可以監(jiān)控代碼變動,自動重啟應(yīng)用。
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
(1)在IntelliJ IDEA中打開你的Spring Boot項目。
(2)確保已經(jīng)安裝了Spring Boot DevTools插件。可以通過 File -> Settings -> Plugins 進入插件管理頁面,搜索并安裝Spring Boot DevTools插件。
(3)在IntelliJ IDEA的頂部菜單欄中,選擇 Run -> Edit Configurations。
(4)在彈出的Run/Debug Configurations對話框中,選擇左側(cè)的 Spring Boot。
(5)在右側(cè)的 Spring Boot 配置窗口中,將 On-frame deactivation 和 On-update action 選項設(shè)置為 Update classes and resources。
這樣設(shè)置后,當你切換到其他窗口時,應(yīng)用程序會在后臺重新啟動,同時當檢測到文件更改時,應(yīng)用程序會更新相關(guān)的類和資源。
(6)點擊 Apply 或 OK 按鈕保存配置。
(7)點擊IntelliJ IDEA的頂部菜單欄中的 Build -> Build Project 來構(gòu)建你的項目。
(8)在構(gòu)建完成后,點擊工具欄上的綠色箭頭圖標或使用快捷鍵 Shift + F10 來運行你的Spring Boot應(yīng)用程序。
現(xiàn)在,當你修改代碼并保存文件時,IntelliJ IDEA會自動將更改的類和資源重新加載到運行的應(yīng)用程序中,實現(xiàn)熱部署。
請注意,熱部署只適用于開發(fā)環(huán)境,并且對于某些修改,可能需要重啟應(yīng)用程序才能生效。因此,在生產(chǎn)環(huán)境中不建議使用熱部署。
傳統(tǒng)的Web應(yīng)用進行打包部署,通常會打成war包形式,然后將War包部署到Tomcat等服務(wù)器中。
在Spring Boot項目在開發(fā)完成后,確實既支持打包成JAR文件也支持打包成WAR文件。然而,官方通常推薦將Spring Boot項目打包成JAR文件,這是因為Spring Boot內(nèi)置了一個嵌入式的Tomcat服務(wù)器,使得應(yīng)用能夠作為一個獨立的可執(zhí)行JAR文件運行,無需部署到外部的Servlet容器中。
雖然Spring Boot也支持打包成WAR文件并部署到外部的Servlet容器中,但這種方式通常不是首選,因為它增加了額外的部署復(fù)雜性,并且可能無法充分利用Spring Boot提供的一些自動配置和簡化功能。
(1)插件完整配置,在pom.xml文件中添加配置
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version><!-- 配置中的版本號 -->
<configuration>
<source>1.8</source><!-- 設(shè)置源代碼的JDK版本 -->
<target>1.8</target><!-- 設(shè)置目標代碼的JDK版本 -->
<encoding>UTF-8</encoding><!-- 設(shè)置編碼方式 -->
</configuration>
</plugin>
<!--maven 打包插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.example.demo.DemoApplication</mainClass><!-- 配置啟動類 -->
<skip>false</skip><!--是否忽略啟動類-->
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
maven-compiler-plugin是Maven的一個插件,主要用于代碼編譯,并提供了很多可配置的選項來優(yōu)化編譯過程。主要作用:
(2)然后在命令行或IDE中執(zhí)行打包命令:
mvn clean package
這將清理舊的構(gòu)建產(chǎn)物,編譯項目,執(zhí)行測試(如果有),并最終打包成一個可執(zhí)行的JAR文件。生成的JAR通常位于target目錄下,文件名格式為your-project-name-<version>.jar。
這將完成同樣的清理、編譯、測試和打包過程,生成的JAR文件同樣位于build/libs目錄下,文件名類似your-project-name-<version>.jar。
(3)部署JAR文件
要運行打包好的JAR文件,只需在命令行中使用java -jar命令:
java -jar target/your-project-name-<version>.jar
根據(jù)需要,可以指定各種運行參數(shù)、環(huán)境變量或配置文件位置。例如:
java -Dserver.port=8081 -jar your-project-name.jar --spring.config.location=file:/path/to/application.properties
(4)打包本地jar包
引入本地jar
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
配置Maven插件:為了確保本地JAR包在打包時能夠被正確識別和包含,需要配置spring-boot-maven-plugin插件。在pom.xml中添加以下配置:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
這段配置中的<includeSystemScope>元素設(shè)置為true,以確保在依賴項解析過程中包括system作用域的依賴項。
或者更改 pom.xml 中的 <build> 新增或修改 <resources> 標簽
<resources>
<resource>
<!-- 因為新增或修改,會覆蓋原有配置,需要配置上默認的 resources 目錄 -->
<directory>src/main/resources</directory>
</resource>
<resource>
<!-- 上面創(chuàng)建的用于放置第三方 jar 包的文件夾名稱 -->
<directory>libs</directory>
<!-- 指定在最終的 jar 包中所在的目錄 -->
<targetPath>BOOT-INF/lib</targetPath>
<!-- 需要打包的文件 -->
<includes>
<include>**/*.jar</include>
</includes>
</resource>
</resources>
maven clean package 然后在 target 目錄中找到打包好的 jar 包文件,解壓可查看已經(jīng)打包進去第三方 jar 包。
Linux將Spring Boot項目的Jar包注冊為開機自啟動系統(tǒng)服務(wù)的操作方法
1)目錄結(jié)構(gòu)
以下是目錄結(jié)構(gòu),jar文件是從maven package打包出來的,config/application.yml是原先在項目的resources文件夾里,外置出來方便適配開發(fā)環(huán)境和正式環(huán)境。static目錄用來存放靜態(tài)資源,比如vue前端或者上傳目錄。所有的.sh文件都是本文后續(xù)要寫的。
/data
/start.sh // 啟動腳本
/stop.sh // 關(guān)閉腳本
/serviceStart.sh // 服務(wù)啟動腳本
/serviceStop.sh // 服務(wù)關(guān)閉腳本
/YumeisoftDemo-0.0.1-SNAPSHOT.jar // 打包的項目Jar包
/config // 配置文件目錄
/application.yml // 項目配置文件
/jdk // jdk目錄
/static // 靜態(tài)資源目錄
2)編寫Service調(diào)用的腳本
配置腳本/data/config.sh,如果改包名,直接改這個文件即可
#!/bin/sh
# 配置JAR文件名,把它改成你的Jar文件名
SPRING_JARFILE=YumeisoftDemo-0.0.1-SNAPSHOT.jar
# 日志文件位置
LOG_FILE=system.log
# 獲取.sh所在路徑
INSTALL_DIR=$(cd $(dirname $0);pwd)
# 配置JDK路徑
JAVA_HOME=$INSTALL_DIR/jdk
# 設(shè)定PATH,不設(shè)會無法使用java命令
PATH=$JAVA_HOME/bin:$PATH
手動啟動服務(wù)腳本/data/start.sh,其中system.log是日志文件名
#!/bin/sh
# 讀取config.sh定義的內(nèi)容
source $INSTALL_DIR/config.sh
# 后臺方式運行jar包
nohup java -jar $INSTALL_DIR/$SPRING_JARFILE > $INSTALL_DIR/$LOG_FILE 2>&1 &
# 顯示日志
tail -f $INSTALL_DIR/$LOG_FILE
手動關(guān)閉服務(wù)腳本/data/stop.sh
#!/bin/sh
# 讀取config.sh定義的內(nèi)容
source $INSTALL_DIR/config.sh
# 獲取當前項目運行的進程ID
PID=$(ps -ef | grep "java -jar $INSTALL_DIR/$SPRING_JARFILE" | grep -v grep | awk '{print $2}')
if [ -z "$PID" ]; then
# 如果沒找到則提示未運行
echo "Spring Boot應(yīng)用未在運行中."
else
# 如果找到了,正常終止進程
kill $PID
# 顯示日志
tail -f $INSTALL_DIR/$LOG_FILE
echo "Spring Boot應(yīng)用已停止."
fi
服務(wù)啟動腳本/data/serviceStart.sh
#!/bin/sh
# 讀取config.sh定義的內(nèi)容
source $INSTALL_DIR/config.sh
# 后臺方式運行jar包
nohup java -jar $INSTALL_DIR/$SPRING_JARFILE > $INSTALL_DIR/$LOG_FILE 2>&1 &
服務(wù)關(guān)閉腳本/data/serviceStop.sh
#!/bin/sh
# 讀取config.sh定義的內(nèi)容
source $INSTALL_DIR/config.sh
# 獲取當前項目運行的進程ID
PID=$(ps -ef | grep "java -jar $INSTALL_DIR/$SPRING_JARFILE" | grep -v grep | awk '{print $2}')
if [ -z "$PID" ]; then
# 如果沒找到則提示未運行
echo "Spring Boot應(yīng)用未在運行中."
else
# 如果找到了,正常終止進程
kill $PID
echo "Spring Boot應(yīng)用已停止."
fi
3)賦權(quán)
不賦權(quán)是無法運行的,所以我們要執(zhí)行以下命令:
chmod a+x /data/*.sh
4)創(chuàng)建一個Service
接下來我們把這個項目注冊為系統(tǒng)服務(wù),myService改成你要改成的服務(wù)名:
vim /etc/systemd/system/myService.service
因為之前沒有這個系統(tǒng)服務(wù),會創(chuàng)建一個新文件,這個文件就是系統(tǒng)服務(wù)的啟停配置文件,按一下a進入編輯模式,把下面的代碼粘貼上去,然后按下Esc、冒號、輸入wq、回車。
[Unit]
Description=MyService
After=network.target
[Service]
Type=forking
ExecStart=/data/serviceStart.sh
ExecStop=/data/serviceStop.sh
PrivateTmp=true
[Install]
WantedBy=multi-user.target
這里面的ExecStart和ExecStop都是服務(wù)啟動和服務(wù)停止腳本的絕對路徑。Description是指服務(wù)的描述信息,這里可以填中文,其他的不要改動。
5)啟用并使用Service
做完以上步驟你就可以在服務(wù)器里執(zhí)行systemctl enable myService命令,即可啟用myService服務(wù),然后使用systemctl start myService即可啟動服務(wù),systemctl stop myService即可關(guān)停服務(wù),system status myService命令可以看到服務(wù)的狀態(tài)。
startup.bat
@echo off
title Spring Boot Demo
java -jar spring-boot-demo.jar --server.config=application.yml
@pause
shutdown.bat
@echo off
set port=8090
for /f "tokens=1-5" %%i in ('netstat -ano^|findstr ":%port%"') do (
echo kill the process %%m who use the port %port%
taskkill /pid %%m -t -f
)
restart.bat
@echo off
call ./shutdown.bat
call ./startup.bat
@pause
或
@echo off
set port=8090
for /f "tokens=1-5" %%i in ('netstat -ano^|findstr ":%port%"') do (
echo kill the process %%m who use the port
taskkill /pid %%m -t -f
goto start
)
cd %~dp0
start java -jar spring-boot-demo.jar --server.config=application.yml
exit
:start
start java -jar spring-boot-demo.jar --server.config=application.yml
exit
@pause
startup.sh
startTime=`date +'%Y-%m-%d %H:%M:%S'`
#jar包文件路徑
APP_PATH=/home/demo
#jar包文件名稱
APP_NAME=$APP_PATH/spring-boot-demo.jar
#日志文件名稱
LOG_FILE=$APP_PATH/spring-boot-demo_out.log
rm -rf $LOG_FILE
echo "開始停止服務(wù)"
#查詢進程,并殺掉當前jar/java程序
pid=`ps -ef|grep $APP_NAME | grep -v grep | awk '{print $2}'`
if [ $pid ];then
echo "pid: $pid"
kill -9 $pid
echo "服務(wù)停止成功"
fi
sleep 2
#判斷jar包文件是否存在,如果存在啟動jar包,并實時查看啟動日志
if test -e $APP_NAME;then
echo '文件存在,開始啟動服務(wù)'
#啟動jar包,指向日志文件,2>&1 & 表示打開或指向同一個日志文件
nohup java -jar -Duser.timezone=GMT+08 $APP_NAME --server.config=application.yml > spring-boot-demo_out.log 2>&1 &
echo "服務(wù)啟動中"
sleep 10s
#通過檢測日志來判斷
while [ -f $LOG_FILE ]
do
success=`grep "Started SpringBootDemoApplication in " $LOG_FILE`
if [[ "$success" !="" ]]
then
break
else
sleep 1s
fi
#開始檢測啟動失敗標記
fail=`grep "Fail" $LOG_FILE`
if [[ "$fail" !="" ]]
then
echo "服務(wù)啟動失敗"
tail -f $LOG_FILE
break
else
sleep 1s
fi
done
echo "服務(wù)啟動成功"
endTime=`date +'%Y-%m-%d %H:%M:%S'`
startSecond=$(date --date="$startTime" +%s);
endSecond=$(date --date="$endTime" +%s);
total=$((endSecond-startSecond))
echo "運行時間:"$total"s"
echo "當前時間:"$endTime
else
echo $APP_NAME ' 文件不存在'
fi
shutdown.sh
#jar包文件名稱
APP_NAME=/data/demo/spring-boot-demo.jar
echo "開始停止服務(wù)"
#查詢進程,并殺掉當前jar/java程序
pid=`ps -ef|grep $APP_NAME | grep -v grep | awk '{print $2}'`
echo "pid: $pid "
if [ $pid ];then
echo "pid: $pid"
kill -9 $pid
echo "服務(wù)停止成功"
else
echo "未找到對應(yīng)服務(wù)"
fi
正常情況下,我們開發(fā) SpringBoot 項目,由于內(nèi)置了Tomcat,所以項目可以直接啟動,部署到服務(wù)器的時候,直接打成 jar 包,就可以運行了。
有時我們會需要打包成 war 包,放入外置的 Tomcat 中進行運行,或者使用工具idea直接啟動,便于開發(fā)調(diào)試。
(1)將pom文件打包方式更改為 war
<packaging>war</packaging>
(2)排除內(nèi)置 Tomcat
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 排除內(nèi)置的tomcat -->
<exclusions>
<exclusion>
<artifactId>org.springframework.boot</artifactId>
<groupId>spring-boot-starter-tomcat</groupId>
</exclusion>
</exclusions>
</dependency>
(3)添加tomcat依賴,需要用到 servlet-api 的相關(guān) jar 包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<!-- tomcat范圍改成provided,否則后面就會出問題,tomcat無法解析jsp -->
<scope>provided</scope>
</dependency>
(4)繼承 SpringBootServletInitializer 并重寫 configure 方法
新建文件文件名隨意,或者直接修改啟動類繼承 SpringBootServletInitializer 并重寫 configure 方法,也是一樣的。
package com.test;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/**
* 注意,使用war方式部署,需要開啟此類
*
*/
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(ApplicationMain.class);
}
}
(1)使用外部tomcat啟動
1)利用maven命令打包
2)將打的war包,復(fù)制粘貼到tomcat的webapps目錄下(不用解壓,啟動tomcat自動解壓)
3)啟動tomcat
在tomcat安裝目錄下的bin目錄下面找到startup.bat命令,啟動tomcat
4)啟動結(jié)果
war包自動解壓了
5)測試結(jié)果,訪問swagger頁面:
訪問路徑這里需要注意,原來我們在application.properties配置的訪問路徑已經(jīng)不生效了。
這是原來訪問路徑:http://localhost:8080/testservice/swagger-ui.html
#已經(jīng)不生效了 server.servlet.context-path=/testservice
現(xiàn)在的訪問路徑:
http://localhost:[端口號]/[打包項目名]/
(2)方式二:使用工具idea直接啟動
1)配置web.xml文件
點擊File->Project Structure
創(chuàng)建src/main/webapp和web.xml
此時項目結(jié)構(gòu)圖如下:
2)配置artifacts
配置完后,tomcat啟動才能找到這個war包,會生成out目錄輸出文件。
當然你也可以選擇target下面已經(jīng)打包好的war包,但是這樣有個缺點,就是每次改文件你都需要用maven重新打包,輸出到target目錄下,不方便開發(fā)。
3)配置tomcat
在IDEA右上角的項目運行列表中選中 Edit Configurations
進入新的窗口點擊"+",找到Toncat Server中的Local進行點擊,配置Tomcat路徑
4)tomcat 選擇啟動的war包
這里注意選擇exploded結(jié)尾的,才是out目錄輸出的
Application context上下文配置訪問路徑
訪問路徑這里需要注意,原來我們在application.properties配置的訪問路徑已經(jīng)不生效了。
#已經(jīng)不生效了
server.servlet.context-path=/testservice
現(xiàn)在的訪問路徑:
http://localhost:8080/testservice/swagger-ui.html
testservice是我Application context上下文配置的訪問路徑 ,這個可以改的。
5)配置tomcat啟動默認打開的頁面
6)啟動結(jié)果
點擊啟動
Dockerfile是一個組合映像命令的文本;可以使用在命令行中調(diào)用任何命令;Docker通過dockerfile中的指令自動生成鏡像。
通過docker build -t repository:tag ./ 即可構(gòu)建,要求:./下存在Dockerfile文件
之前我們聊的鏡像分層,這個層怎么分的,就是由Dockerfile中的每一條指令構(gòu)成
FROM:基礎(chǔ)鏡像
FROM <image>:<tag> [as other_name] # tag可選;不寫默認是latest版
LABEL:鏡像描述信息
LABEL author="zp wang <test@qq.com>"
LABEL describe="test image"
# 或
LABEL author="zp wang <test@qq.com>" describe="test image"
# 或
LABEL author="zp wang <test@qq.com>" \
describe="test image"
MAINTAINER:添加作者信息
MAINTAINER zp wang <test@163.com>
COPY:從構(gòu)建主機復(fù)制文件到鏡像中
COPY <src> <dest>
COPY ["<src>", "<src>", ... "<dest>"]
# 拷貝一個文件
COPY testFile /opt/
# 拷貝一個目錄
COPY testDir /opt/testDir
testDir下所有文件和目錄都會被遞歸復(fù)制
目標路徑要寫testDir,否則會復(fù)制到/opt下
ADD:從構(gòu)建宿主機復(fù)制文件到鏡像中
類似于COPY指令,但ADD支持tar文件還讓URL路徑
ADD <src> <dest>
ADD ["<src>","<src>"... "<dest>"]
WORKDIR:設(shè)置工作目錄
類似于cd命令,為了改變當前的目錄域
此后RUN、CMD、ENTRYPOINT、COPY、ADD等命令都在此目錄下作為當前工作目錄
WORKDIR /opt
ENV:設(shè)置鏡像中的環(huán)境變量
# 一次設(shè)置一個
ENV <key> <value>
# 一次設(shè)置多個
ENV <key>=<value> <key1>=<value1> <key2>=<value2> .....
使用環(huán)境變量的方式
$varname
${varname}
${varname:-default value} # 設(shè)置一個默認值,如果varname未被設(shè)置,值為默認值
${varname:+default value} # 設(shè)置默認值;不管值存不存在都使用默認值
USER:設(shè)置啟動容器的用戶
# 使用用戶名
USER testuser
# 使用用戶的UID
USER UID
RUN:鏡像構(gòu)建時執(zhí)行的命令
# 語法1,shell 形式
RUN command1 && command2
# 語法2,exec 形式
RUN ["executable","param1","[aram2]"]
# 示例
RUN echo 1 && echo 2
RUN echo 1 && echo 2 \
echo 3 && echo 4
RUN ["/bin/bash","-c","echo hello world"]
EXPOSE:為容器打開指定的監(jiān)聽端口以實現(xiàn)與外部通信
EXPOSE <port>/<protocol>
EXPOSE 80
EXPOSE 80/http
EXPOSE 2379/tcp
VOLUME:實現(xiàn)掛載功能,將宿主機目錄掛載到容器中
VOLUME ["/data"] # [“/data”]可以是一個JsonArray ,也可以是多個值
VOLUME /var/log
VOLUME /var/log /opt
CMD:為容器設(shè)置默認啟動命令或參數(shù)
# 語法1,shell形式
CMD command param1 param2 ...
# 語法2,exec形式
CMD ["executable","param1","param2"]
# 語法3,還是exec形式,不過僅設(shè)置參數(shù)
CMD ["param1","param2"]
ENTRYPOINT:用于為容器指定默認運行程序或命令
與CMD類似,但存在區(qū)別,主要用于指定啟動的父進程,PID=1
# 語法1,shell形式
ENTRYPOINT command
# 語法2,exec形式
ENTRYPOINT ["/bin/bash","param1","param2"]
CMD和ENTRYPOINT組合情況說明
具體情況比較多,如表格所示
No ENTRYPOINT | ENTRYPOINT exec_entry p1_entry | ENTRYPOINT ["exec_entry","p1_entry"] | |
No CMD | error,not allowed | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry |
CMD ["exec_cmd","p1_cmd"] | exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry exec_cmd p1_cmd |
CMD ["p1_cmd","p2_cmd"] | p1_cmd p2_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry p1_cmd p2_cmd |
CMD exec_cmd p1_cmd | exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd |
ARG:指定環(huán)境變量用于構(gòu)建過程
ARG name[=default value]
ARG test_name
ARG nother_name=wzp
ONBUILD:為鏡像添加觸發(fā)器
ONBUILD可以為鏡像添加一個觸發(fā)器,其參數(shù)可以是任意一個Dockerfile指令。
ONBUILD <dockerfile_exec> <param1> <param2>
ONBUILD RUN mkdir mydir
STOPSINGAL:設(shè)置停止時要發(fā)送給PID=1進程的信號
主要的目的是為了讓容器內(nèi)的應(yīng)用程序在接收到signal之后可以先做一些事情,實現(xiàn)容器的平滑退出,如果不做任何處理,容器將在一段時間之后強制退出,會造成業(yè)務(wù)的強制中斷,這個時間默認是10s。
STOPSIGNAL signal
HEALTHCHECK:指定容器健康檢查命令
當在一個鏡像指定了 HEALTHCHECK 指令后,用其啟動容器,初始狀態(tài)會為 starting,在 HEALTHCHECK 指令檢查成功后變?yōu)?healthy,如果連續(xù)一定次數(shù)失敗,則會變?yōu)?unhealthy
HEALTHCHECK [OPTIONS] CMD command
# 示例
HEALTHCHECK --interval=5s --timeout=3s \
CMD curl -fs http://localhost/ || exit 1 # 如果執(zhí)行不成功返回1
SHELL:指定shell形式的默認值
SHELL 指令可以指定 RUN、ENTRYPOINT、CMD 指令的 shell,Linux 中默認為["/bin/sh", "-c"] ,Windows默認["CMD","/S","/C"]
通常用于構(gòu)建Windows用的鏡像
SHELL ["/bin/bash","-c"]
SHELL ["powershell", "-command"]
# 示例,比如在Windows時,默認shell是["CMD","/S","/C"]
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
# docker調(diào)用的是cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]
# 這樣雖然沒有調(diào)用cmd.exe 但寫起來比較麻煩,所以可以通過SHELL ["powershell", "-command"]
FROM openjdk:8u312
MAINTAINER zhangt
ADD spring-boot-docker-1.0.jar zhangt.jar
EXPOSE 8520
ENTRYPOINT ["java","-jar","zhangt.jar"]
Dockerfile的內(nèi)容解釋:
FROM openjdk:8u312 這一行指定了基礎(chǔ)鏡像,從openjdk:8u312鏡像構(gòu)建。它使用了OpenJDK 8的版本號為312的鏡像作為基礎(chǔ)。這是一個包含Java運行時環(huán)境的基礎(chǔ)鏡像。
MAINTAINER zhangt 這一行設(shè)置了維護者信息,盡管在較新版本的Docker中,MAINTAINER已不再建議使用,而可以使用LABEL來添加類似的元數(shù)據(jù)信息。
ADD spring-boot-docker-1.0.jar zhangt.jar 這一行使用ADD指令將本地的spring-boot-docker-1.0.jar文件復(fù)制到鏡像中,并重命名為zhangt.jar。這個JAR文件包含了Spring Boot應(yīng)用程序的可執(zhí)行代碼。
EXPOSE 8520 這一行使用EXPOSE指令聲明容器將監(jiān)聽的端口號,這里指定為8520。請注意,這只是一個元數(shù)據(jù)聲明,它不會自動將端口映射到主機上。
ENTRYPOINT ["java","-jar","zhangt.jar"] 這一行設(shè)置了容器啟動時要執(zhí)行的命令。在這種情況下,容器將以java -jar zhangt.jar命令啟動,這會運行Spring Boot應(yīng)用程序。java命令會啟動Java虛擬機(JVM),并執(zhí)行zhangt.jar中的可執(zhí)行代碼。
這Dockerfile的作用是基于OpenJDK 8u312鏡像構(gòu)建一個包含Spring Boot應(yīng)用程序的Docker鏡像。一旦構(gòu)建完成,可以使用這個鏡像來運行Spring Boot應(yīng)用程序的容器,容器將監(jiān)聽8520端口,可以通過適當?shù)亩丝谟成鋪碜屚獠吭L問應(yīng)用程序。
docker build -t zhangt .
注意最后的 . 表示Dockerfile在當前文件目錄下。zhangt表示構(gòu)建的鏡像,構(gòu)建成功后可以使用docker images命令查看鏡像。 -t 選項用于指定鏡像的名稱和標簽,你可以將zhangt替換為你想要的名稱和標簽。
docker run -d --restart=always --name zhangt -p 8520:8520 zhangt
各個參數(shù)的含義:
docker run: 用于啟動 Docker 容器的命令。
-d: 這是一個選項,表示在后臺(守護進程模式)運行容器。容器將在后臺運行,不會占據(jù)終端。
--restart=always: 這是另一個選項,表示容器在退出時總是重新啟動。即使容器因為錯誤或其他原因而停止,Docker 也會嘗試自動重新啟動容器。
--name zhangt: 這是用于給容器指定一個名稱的選項。容器的名稱被設(shè)置為 "zhangt"。
-p 8520:8520: 這是用于將主機端口與容器端口進行映射的選項。這個選項將主機的 8520 端口映射到容器的 8520 端口。這樣,外部可以通過訪問主機的 8520 端口來訪問容器內(nèi)運行的應(yīng)用程序。
zhangt: 這是容器的名稱或鏡像名稱,表示要運行的容器是基于名為 "zhangt" 的 Docker 鏡像創(chuàng)建的。如果 "zhangt" 是一個鏡像名稱,Docker 將查找該鏡像并在容器中運行它。
這個命令的目的是在后臺運行一個 Docker 容器,該容器使用 "zhangt" 鏡像創(chuàng)建,并將主機的 8520 端口映射到容器的 8520 端口。容器的名稱設(shè)置為 "zhangt-p",并且如果容器在任何情況下退出,Docker 會自動重新啟動它。這通常用于部署應(yīng)用程序,以確保應(yīng)用程序在意外情況下能夠自動恢復(fù)。
啟動容器后可以使用 **docker ps**命令查看啟動的容器
docker logs -f --tail 1000 容器id ,可以查看服務(wù)的日志。
如果想更新jar包,只需要使用 docker cp spring-boot-docker-1.0.jar 容器ID:/zhangt.jar,就可以將spring-boot-docker-1.0.jar拷貝進容器并重命名,然后 docker restart 容器ID 重啟容器。
docker pull openjdk:8u181
cd /home/ mkdir www/spring-boot-docker
#!/bin/bash
echo -e "\n################ build service start #########################"
# delete docker container
echo -e "\n1, delete docker container [developer-platform-basic-dev] start ......"
sudo docker rm -f spring-boot-docker-1.0
# docker run # docker run developer-platform-basic-1.0.0
echo -e "\n2, docker run build container [spring-boot-docker-1.0] start ......"
sudo docker run --name spring-boot-docker-1.0 -d -p 8741:8741 \
-v /home/www/spring-boot-docker:/jar openjdk:8u181 \
java -jar /jar/spring-boot-docker-1.0.jar --spring.profiles.active=dev
echo -e "\n3, docker ps container [spring-boot-docker-1.0] start ...."
sudo docker ps -a | grep spring-boot-docker-1.0
echo -e "\n4, docker logs container [spring-boot-docker-1.0] start ...."
sudo docker logs -f -t spring-boot-docker-1.0 > ./logs/log_$(date +%Y%m%d).out 2>&1 &
echo -e "\n################ build service end #########################"
核心腳本解釋:
1.sudo docker run 這是用于在Docker中運行容器的命令。通常需要使用sudo權(quán)限來執(zhí)行Docker命令,以確保具有足夠的權(quán)限來管理容器。
--name spring-boot-docker-1.0: 這是為Docker容器指定的名稱,容器的名稱被設(shè)置為"spring-boot-docker-1.0"。
-d: 這是一個選項,表示在后臺運行容器(即以守護進程模式運行),而不是在前臺交互模式下運行。
-p 8741:8741: 這個選項用于將主機的端口與容器的端口進行映射。具體來說,將主機的8741端口映射到容器的8741端口,這樣外部可以通過主機的8741端口訪問容器中的應(yīng)用程序。
-v /home/www/spring-boot-docker:/jar: 這個選項用于將主機的文件系統(tǒng)目錄與容器內(nèi)的目錄進行掛載。在這種情況下,將主機上的/home/www/spring-boot-docker目錄掛載到容器內(nèi)的/jar目錄。這通常用于將應(yīng)用程序的代碼和資源文件從主機復(fù)制到容器中,以便在容器內(nèi)運行應(yīng)用程序。
openjdk:8u181: 這是要在容器中使用的Docker鏡像的名稱和標簽。在這里,使用的是一個基于OpenJDK 8u181的Java鏡像,該鏡像包含了Java運行時環(huán)境。
java -jar /jar/spring-boot-docker-1.0.jar --spring.profiles.active=dev: 這是在容器內(nèi)運行的命令。它啟動了Java虛擬機(JVM),并在JVM內(nèi)運行了一個Spring Boot應(yīng)用程序。具體來說,它運行了/jar/spring-boot-docker-1.0.jar這個JAR文件,并通過--spring.profiles.active=dev指定了一個Spring配置文件的激活配置。
這個腳本的作用是創(chuàng)建一個名為"spring-boot-docker-1.0"的Docker容器,該容器運行一個基于Spring Boot的Java應(yīng)用程序,該應(yīng)用程序監(jiān)聽8741端口,并將主機上的/home/www/spring-boot-docker目錄掛載到容器內(nèi)的/jar目錄,以供應(yīng)用程序使用。這樣,可以通過主機的8741端口訪問運行在容器中的Spring Boot應(yīng)用程序。
Controller層可以進行單元測試、集成測試(@WebMvcTest)和端到端測試。
Service層可以進行單元測試和集成測試。
Repository層可以進行集成測試(@DataJpaTest)。
工具類可以進行單元測試。
選擇測試類型
選擇適當?shù)臏y試類型,根據(jù)需要選擇單元測試、集成測試、端到端測試。
確定測試目標
明確你需要測試的具體功能或方法,理解其預(yù)期的行為。
準備測試環(huán)境和數(shù)據(jù)
根據(jù)測試需求設(shè)置適當?shù)臏y試環(huán)境。
編寫測試用例
根據(jù)測試目標編寫對應(yīng)的測試用例,包括正常場景、邊界條件和異常場景。
執(zhí)行測試和結(jié)果驗證
測試報告分析
評估測試結(jié)果,如果測試失敗,進行bug修復(fù),重新測試,直到所有測試用例都通過。
重構(gòu)和優(yōu)化
根據(jù)測試結(jié)果,進行代碼的重構(gòu)和優(yōu)化,提高代碼質(zhì)量。
測試代碼的維護
確保測試代碼的可讀性和可維護性,同時保證在項目構(gòu)建過程中能夠自動執(zhí)行測試。
單元測試用于驗證單個類的功能是否正確。
其特點是獨立于其他類、數(shù)據(jù)庫、網(wǎng)絡(luò)或其他外部資源。
在實際工作中,通常對Spring Boot中的Controller、Service等類進行單元測試。
JUnit是Java中最流行的單元測試框架,用于編寫和執(zhí)行單元測試。
基本注解
基本測試
@Test
public void testCount() {
// 測試代碼
}
異常測試
有時候需要測試代碼是否能正確地拋出異常,可以使用@Test的expected屬性:
@Test(expected=SomeException.class)
public void testException() {
// 測試代碼,期望拋出SomeException異常
}
超時測試
有時候需要測試某個操作是否能在規(guī)定時間內(nèi)完成,可以使用@Test的timeout屬性:
@Test(timeout=1000)
public void testTimeout() {
// 測試代碼,期望在1000毫秒內(nèi)執(zhí)行完畢
}
忽略測試
有時候暫時不想執(zhí)行某個測試方法,可以使用@Ignore注解:
@Ignore("暫時忽略這個測試")
@Test
public void testIgnore() {
// 測試代碼
}
Mockito庫用于模擬對象,隔離被測類與其他類的依賴關(guān)系。
基本概念
常用注解
常用方法
Mockito 提供了一系列方法,用于在單元測試中創(chuàng)建和設(shè)置模擬對象的行為:
Mockito 還提供了一系列的方法,用于驗證模擬對象的行為:
示例代碼
@RunWith(MockitoJUnitRunner.class)
public class TeacherApiTest {
@Mock
private TeacherService teacherService;
@InjectMocks
private TeacherApi teacherApi;
@Test
public void testCount() {
when(teacherService.countByName("張三")).thenReturn(1);
TeacherCount result=teacherApi.count("張三");
verify(teacherService).countByName("張三"); // 驗證方法是否被調(diào)用
assertEquals(1, result.getCount()); // 驗證返回值是否符合預(yù)期
}
}
AssertJ庫提供了豐富的斷言方法,可以更簡潔地編寫測試代碼。
常用斷言
JSONAssert庫用于測試JSON字符串是否符合預(yù)期。
常用方法
示例代碼
@Test
public void testJsonAssert() throws JSONException {
String expected="{\"id\":1,\"name\":\"張三\"}";
String actual="{\"id\":1,\"name\":\"張三\"}";
// 使用非嚴格模式進行比較
JSONAssert.assertEquals(expected, actual, false);
// 使用嚴格模式進行比較,預(yù)期字符串與實際字符串必須嚴格匹配
JSONAssert.assertEquals(expected, actual, true);
// 驗證實際的JSON值是否不等于預(yù)期的JSON值
String unexpected="{\"id\":2,\"name\":\"李四\"}";
JSONAssert.assertNotEquals(unexpected, actual, false);
// 使用自定義的JSONComparator進行比較
JSONAssert.assertJSONEquals(expected, actual, JSONCompareMode.LENIENT);
}
SpringBoot的@JsonTest注解用于測試JSON序列化和反序列化。
示例代碼
@JsonTest
public class TeacherJsonTest {
@Autowired
private JacksonTester<Teacher> json;
String content="{\"id\":1,\"name\":\"張三\"}";
@Test
public void testSerialize() throws Exception {
Teacher teacher=new Teacher();
teacher.id=1L;
teacher.name="張三";
assertThat(json.write(teacher)).isEqualToJson(content);
}
@Test
public void testDeserialize() throws Exception {
Teacher teacher=new Teacher();
teacher.id=1L;
teacher.name="張三";
Teacher teacher1=json.parseObject(content);
assertThat(teacher1.id).isEqualTo(teacher.id);
assertThat(teacher1.name).isEqualTo(teacher.name);
}
}
集成測試驗證Spring Boot應(yīng)用內(nèi)各組件(Controller、Service、Repository等)之間的交互和協(xié)作。
其特點是需要啟動Spring上下文環(huán)境(不一定需要啟動Web服務(wù)器),以便在測試代碼中直接使用 @Autowired 等注解。
在實際工作中,通常對Spring Boot項目的各個組件進行集成測試,包括但不限于:
@SpringBootTest 注解在測試開始前創(chuàng)建一個完整的Spring應(yīng)用程序上下文。
示例代碼
@SpringBootTest
@ActiveProfiles("test") // 指定運行環(huán)境
public class TeacherServiceIntegrationTest {
@Autowired
private TeacherService teacherService; // 注入TeacherService
@Test
public void testCount() {
int result=teacherService.countByName("張三"); // 調(diào)用Service的方法
assertEquals(1, result); // 斷言結(jié)果
}
}
@WebMvcTest 注解在測試開始前啟動一個針對Spring MVC的測試環(huán)境。
僅加載指定的Controller,而不會加載應(yīng)用程序的其他組件。如果測試中需要這些其他組件,使用 @MockBean 來模擬這些組件的行為。
使用 MockMvc 對象模擬發(fā)送HTTP請求,并驗證控制器的響應(yīng)。
示例代碼
@WebMvcTest(TeacherApi.class) // 指定需要測試的Controller
@ActiveProfiles("test") // 指定運行環(huán)境
public class TeacherApiWebMvcTest {
@Autowired
private MockMvc mockMvc; // 注入MockMvc
@MockBean
private TeacherService teacherService; // Mock掉Service層的接口
@Test
public void testCount() throws Exception {
when(teacherService.countByName("張三")).thenReturn(1); // Mock掉Service的方法,指定返回值
mockMvc.perform(MockMvcRequestBuilders.get("/api/teacher/count").param("name", "張三")) // 執(zhí)行一個GET請求
.andExpect(MockMvcResultMatchers.status().isOk()) // 驗證響應(yīng)狀態(tài)碼為200
.andExpect(MockMvcResultMatchers.jsonPath("$.count").value(1)); // 斷言響應(yīng)結(jié)果中JSON屬性"count"的值為1
}
}
MockMvc的常用方法
jsonPath的常用表達式
@DataJpaTest注解在測試開始前啟動一個Spring上下文環(huán)境,只加載JPA相關(guān)的組件,如實體、倉庫等。
配置一個內(nèi)存數(shù)據(jù)庫,以避免對真實數(shù)據(jù)庫的影響,并提高測試的速度。
默認開啟事務(wù),并在測試完成后回滾事務(wù)。
示例代碼
@DataJpaTest
@ActiveProfiles("test") // 指定運行環(huán)境
public class TeacherDaoTest {
@Autowired
private TeacherDao teacherDao; // 注入Repository
@Test
public void testCount() {
int result=teacherDao.countByName("張三"); // 調(diào)用Repository的方法
assertEquals(1, result); // 斷言結(jié)果
}
}
TestEntityManager
TestEntityManager是Spring提供的一個用于測試的EntityManager,用于在測試中對實體進行增刪改查操作。
@DataJpaTest
@ActiveProfiles("test") // 指定運行環(huán)境
public class TeacherDaoTest {
@Autowired
private TeacherDao teacherDao; // 注入Repository
@Autowired
private TestEntityManager entityManager; // 注入TestEntityManager
@Test
public void testCount() {
// 使用TestEntityManager創(chuàng)建一個Teacher實體
Teacher teacher=new Teacher();
teacher.name="張三";
teacher.age=20;
entityManager.persist(teacher);
// 調(diào)用Repository的方法
int result=teacherDao.countByName("張三");
// 斷言結(jié)果
assertEquals(1, result);
}
}
集成測試通常需要使用數(shù)據(jù)庫。
如果使用真實的數(shù)據(jù)庫,每次測試都會對數(shù)據(jù)庫進行讀寫操作,這樣會導(dǎo)致測試變得緩慢,而且會對數(shù)據(jù)庫造成影響。
為了解決這個問題,可以使用內(nèi)存數(shù)據(jù)庫。內(nèi)存數(shù)據(jù)庫是一種特殊的數(shù)據(jù)庫,它將數(shù)據(jù)存儲在內(nèi)存中,而不是磁盤上,因此它的讀寫速度非常快,適合用于測試。
配置
在Spring Boot項目中使用H2數(shù)據(jù)庫,需要在pom.xml中添加以下依賴:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
使用
在application-test.properties中添加以下配置:
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.username=sa
spring.datasource.password=spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.datasource.schema=classpath:test-schema.sql
spring.datasource.data=classpath:test-data.sql
在application-test.properties中,指定了H2數(shù)據(jù)庫的連接信息。
還指定了初始化腳本test-schema.sql和test-data.sql,用于初始化數(shù)據(jù)庫的表結(jié)構(gòu)和數(shù)據(jù)。
test-schema.sql
CREATE TABLE teacher (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
age INT NOT NULL
);
test-data.sql
INSERT INTO teacher (name, age) VALUES ('張三', 20);
INSERT INTO teacher (name, age) VALUES ('李四', 30);
端到端測試驗證整個程序的功能是否按照預(yù)期工作。
其特點是需要啟動完整的應(yīng)用程序上下文,并模擬客戶端與HTTP接口進行交互。
在實際工作中,我們通常對使用SpringBoot開發(fā)的整個應(yīng)用程序進行端到端測試。
端到端測試需要啟動完整的應(yīng)用程序上下文。
使用@SpringBootTest注解的webEnvironment屬性,將應(yīng)用程序上下文設(shè)置為隨機端口啟動。
TestRestTemplate是Spring提供的類,用于發(fā)送HTTP請求并驗證接口的響應(yīng)是否符合預(yù)期。
示例代碼
@SpringBootTest(webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT) // 將應(yīng)用上下文設(shè)置為隨機端口啟動
@ActiveProfiles("test")
public class TeacherApiEndToEndTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testSearchTeacher() {
// 發(fā)送GET請求,訪問"/teachers?name=John"
ResponseEntity<TeacherCount> response=restTemplate.getForEntity("/teachers?name=John", TeacherCount.class);
// 驗證響應(yīng)狀態(tài)碼是否為200(HttpStatus.OK)
Assertions.assertEquals(HttpStatus.OK, response.getStatusCode());
// 驗證響應(yīng)中JSON屬性"count"的值是否為2
Assertions.assertEquals(2, response.getBody().getCount());
}
}
Jsoup庫用于HTML解析。
基本使用
以下是一些Jsoup的基本使用方法:
String html="<html><head><title>測試頁面</title></head>"
+ "<body><p>這是一個測試頁面</p></body></html>";
Document doc=Jsoup.parse(html);
Element titleElement=doc.select("title").first();
String titleText=titleElement.text();
Element linkElement=doc.select("a").first();
String href=linkElement.attr("href");
測試網(wǎng)頁
以下是一個使用Jsoup測試網(wǎng)頁的例子:
@Test
public void testHtmlPage() {
// 測試HTML頁面的標題
Document doc=Jsoup.connect("http://www.example.com").get();
String title=doc.title();
assertThat(title).isEqualTo("Example Domain");
}
Selenium用于模擬瀏覽器行為。
通過Selenium,程序可以自動化地操作瀏覽器,模擬用戶在瀏覽器中的交互行為。
核心類
WebDriver的常用方法
測試網(wǎng)頁
以下是一個使用Selenium測試網(wǎng)頁的例子:
public class TeacherSearchFrontendTest {
@Test
public void testSearchTeacher() {
// 設(shè)置ChromeDriver的路徑(注意根據(jù)實際情況修改路徑)
System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
// 創(chuàng)建Chrome瀏覽器的WebDriver
WebDriver driver=new ChromeDriver();
// 打開目標網(wǎng)頁
driver.get("http://localhost:8080");
// 找到搜索框并輸入教師姓名
WebElement searchInput=driver.findElement(By.id("search-input"));
searchInput.sendKeys("John");
// 找到搜索按鈕并點擊
WebElement searchButton=driver.findElement(By.id("search-button"));
searchButton.click();
// 驗證搜索結(jié)果數(shù)量是否符合預(yù)期
WebElement resultCount=driver.findElement(By.id("result-count"));
Assertions.assertEquals("Found 2 teachers", resultCount.getText());
// 關(guān)閉瀏覽器
driver.quit();
}
}
Docker 是一種開源的容器化平臺,用于構(gòu)建、發(fā)布和運行應(yīng)用程序。
它可以將應(yīng)用程序及其依賴項打包到一個獨立的、可移植的容器中,從而實現(xiàn)了應(yīng)用程序在不同環(huán)境中的一致性和可移植性。
如果本地搭建 docker,我們開發(fā)人員就可以快速構(gòu)建、部署和擴展應(yīng)用程序了,而無需擔心環(huán)境差異或依賴項沖突的問題。
硬件:
安裝 Docker Desktop 需要啟用 Hyper-V 和 Windows 容器功能。
【控制面板】-> 【所有控制面板項】-> 【程序和功能】
打開【啟用或關(guān)閉 Windows 功能】窗口,勾選:
安裝完成需要重啟才會生效,先不重啟,稍后再重啟。
docker 官網(wǎng) windows 版下載地址:https://hub.docker.com/editions/community/docker-ce-desktop-windows
下載完成后是一個exe文件【Docker for Windows Installer.exe】
雙擊安裝文件進行安裝,等待一小段時間,安裝完成后會出現(xiàn)下面的窗口:
這時候點擊【close and log out】會重啟電腦。
啟動【Docker for Windows】,啟動命令窗口,輸入命令【docker version】可查看 docker 版本,如:
1.以管理員身份啟動命令窗口,輸入命令【docker search mssql】:
2.輸入命令【docker pull microsoft/mssql-server-linux】下載鏡像:
3.創(chuàng)建并運行容器
輸入命令【docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Password01!" -p 1445:1433 --name MSSQL_loan -d microsoft/mssql-server-linux】
4.登錄容器
輸入命令【docker exec -it MSSQL_loan /bin/bash】:
5.連接到 sqlcmd
輸入命令【/opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P 'Password01!'】:
6.創(chuàng)建數(shù)據(jù)庫并進行測試
輸入命令【CREATE DATABASE TestDB】創(chuàng)建一個數(shù)據(jù)庫:
1> CREATE DATABASE TestDB
2> go
輸入命令【select name,database_id,create_date from sys.Databases】查看已存在的數(shù)據(jù)庫:
7.使用客戶端 mssms 連接創(chuàng)建的 sqlserver
服務(wù)器名稱就是你的本地【IP,端口】,如本次前面設(shè)置的是1445,
1.在容器內(nèi)創(chuàng)建一個目錄
如果是繼續(xù)上面的步驟,則先退出【quit】到容器管理中:
如果沒有登錄容器,則先登錄容器【docker exec -it MSSQL_loan /bin/bash】。
使用命令【mkdir /var/opt/mssql/backup】創(chuàng)建一個目錄,然后再退出容器:
3.將數(shù)據(jù)庫備份文件(.bak文件)復(fù)制到容器中
使用命令【docker cp E:/job/techTest/docker/sqlserver/Loan.bak MSSQL_loan:/var/opt/mssql/backup】進行復(fù)制:
4.還原數(shù)據(jù)庫
先登錄容器【docker exec -it MSSQL_loan /bin/bash】,列出備份數(shù)據(jù)文件的邏輯名,使用命令【/opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P 'Password01!' -Q 'RESTORE FILELISTONLY FROM DISK="/var/opt/mssql/backup/Loan.bak"' | tr -s ' ' | cut -d ' ' -f 1-2】:
還原數(shù)據(jù)庫,使用命令【/opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P 'Password01!' -Q 'RESTORE DATABASE Loan FROM DISK="/var/opt/mssql/backup/Loan.bak" WITH MOVE "Loan" TO "/var/opt/mssql/data/Loan.mdf" , MOVE "Loan_log" TO "/var/opt/mssql/data/Loan.ldf"'】:
注:個人不是很推薦在windows中安裝 docker,日常使用 docker 還是建議安裝在 linux 上的,當然沒有 Linux 服務(wù)器的情況下,windows 安裝 docker 也是不錯的選擇。