官术网_书友最值得收藏!

4.2.6 S2I實現應用容器化

1.OpenShift S2I的介紹

Source-to-Image(S2I)是紅帽OpenShift開發的一個功能組件。目前可以獨立于OpenShift運行。在社區里,被稱為Java S2I,GitHub的地址為https://github.com/openshift/source-to-image/blob/master/README.md

Java S2I容器鏡像使開發人員能夠通過指定應用程序源代碼或已編譯的Java二進制文件的位置,在OpenShift容器平臺中按需自動構建、部署和運行Java應用程序。此外,S2I還支持Spring Boot、Eclipse Vert.x和WildFly Swarm。使用S2I的優勢在于:

·簡單而靈活:Java S2I鏡像可以處理復雜的構建結構,但默認情況下它會假定在成功構建后/target目錄中將運行要運行的JAR。我們也可以使用環境變量ARTIFACT_DIR指定要運行的JAR。此外,如果構建生成多個JAR文件,則可以使用環境變量JAVA_APP_JAR指定要運行的JAR文件。但是,在大多數情況下,我們所要做的就是直接指向源存儲庫,Java S2I容器鏡像將自動完成配置。

·自動JVM內存配置:在OpenShift中通過Quota做資源限制。如果存在此類限制,Java S2I鏡像將自動采用JVM內存設置,避免JVM過量使用內存。

·控制鏡像大小:為了使鏡像保持最小化,可以在構建最終容器鏡像之前在S2I腳本中刪除Maven本地倉庫的數據。將環境變量MAVEN_CLEAR_REPO設置為true,則會在構建過程中刪除Maven本地倉庫。

2.OpenShift S2I原理解析

OpenShift可以直接基于Git存儲庫中存儲的源代碼來創建應用。oc new-app指定Git的URL后OpenShift會自動檢測應用所用的編程語言,并選擇合適的Builder鏡像。當然,我們也可以手工指定Builder鏡像。

那么,S2I應該如何識別Git上的內容來自動檢測編程語言呢?它會檢測Git上的特征文件,然后按照表4-1的方式選擇構建方式。

例如,如果Git上有pom.xml文件,S2I將會因為需要使用jee的構建語言,所以查找jee的Image Stream。

表4-1 S2I特征文件與構建方式

OpenShift會采用多步算法來確定URL是否指向源代碼存儲庫,如果是,則還會采用該算法來確定應由哪個Builder鏡像來執行構建。以下是該算法的大致執行過程:

1)如果S2I能夠成功訪問指定源碼地址的URL,則需S2I開始進行下一步。

2)OpenShift檢索Git存儲庫,搜索名為Dockerfile的文件。如果找到了Dockerfile,則會觸發容器鏡像構建。如果沒找到Dockerfile,則進行第3步。

3)OpenShift按照表4-1的方式判斷源碼的類型匹配構建語言,自動查找Image Stream。搜索到的第一個匹配的Image Stream會成為S2I Builder鏡像。

4)如果沒有匹配的構建語言,OpenShift會搜索名稱與構建語言名稱相匹配的Image Stream。搜索到的第一個匹配項會成為S2I Builder鏡像。

S2I構建過程涉及三個基本組件:應用程序的源代碼、S2I腳本、S2I Builder鏡像。它們組合在一起構建成最終的應用鏡像,實現應用容器化。

S2I的本質是按照一定的規則執行構建過程,依賴于一些固定名稱的S2I腳本,這些腳本在各個階段執行構建工作流程。它們的名稱和作用分別如下:

·assemble:負責將已經下載到本地的外部代碼進行編譯打包,然后將打包好的應用包拷貝到鏡像對應的運行目錄中。

·run:負責啟動運行assemble編譯、拷貝好的應用。

·usage:告訴使用者如何使用該鏡像。

·save-artifacts:腳本負責將構建所需要的所有依賴包收集到一個tar文件中。save-artifacts的好處是可以加速構建的過程。

·test/run:通過test/run腳本,可以創建簡單的流程來驗證鏡像是否正常工作。

在上面的五個腳本中,assemble和run是必須有的,其他三個腳本是可選的。這些腳本可以由多種方式提供,默認使用存放在鏡像/usr/local/s2i目錄下的腳本文件,也可以由源代碼倉庫或HTTP Server提供這些腳本。

有了這五個S2I腳本之后,就可以按照如下構建流程構建應用鏡像了。

·啟動構建之后,啟動builder容器,首先實例化基于S2I Builder的容器。從Git上獲取應用源代碼,創建一個包含S2I腳本(如果Git上沒有,則使用Builder鏡像中的腳本)和應用源碼的tar文件,將tar文件傳入S2I Builder實例化的容器中。

·tar文件被解壓縮到S2I builder容器中io.openshift.s2i.destination標簽指定的目錄位置,默認是/tmp。

·如果是增量構建,assemble腳本會先恢復被save-artifacts腳本保存的build artifacts。

·assemble腳本從源代碼構建應用程序,并將生成的二進制文件放入應用運行的目錄。

·如果是增量構建,執行save-artifacts腳本并保存所有構建以來的artifacts到tar文件。

·完成assemble腳本執行以后生成最終應用鏡像。

·builder容器調用podman命令,將構建好的應用鏡像推送到內部鏡像倉庫。

·應用鏡像推送到內部鏡像倉庫之后,觸發DeploymentConfig中的Image Stream觸發器自動部署應用鏡像。

·應用鏡像運行,并執行RUN腳本配置應用參數以及啟動應用。

在介紹了S2I的原理后,接下來通過分析一個紅帽的Builder鏡像,進一步加深對S2I的理解。

3.紅帽Builder鏡像分析

目前紅帽的官網提供24個Builder鏡像(https://access.redhat.com/containers/#/explore),如圖4-9所示。

圖4-9 官方鏡像類型

官方提供的Builder鏡像包含了大部分開發語言,如圖4-10所示。

圖4-10 官方Builder鏡像

紅帽Builder鏡像包含了紅帽研發的大量心血,其腳本的書寫判斷條件十分全面。我們以webserver31-tomcat8-openshift這個Builder鏡像為例來體會一下。

首先在OpenShift項目下,通過對應的Image Stream導入webserver31-tomcat8-openshift鏡像。


# oc import-image jboss-webserver31-tomcat8-openshift --from=registry.redhat.io/
    jboss-webserver-3/webserver31-tomcat8-openshift --confirm
imagestream.image.openshift.io/webserver31-tomcat8-openshift imported

接下來,使用導入成功的Image Stream部署Pod,如圖4-11所示。

圖4-11 選擇Image Stream和版本

在OpenShift中選擇Image Stream和Tag,使用Tag 1.4。部署完成后,等待Pod正常運行,如圖4-12所示。

圖4-12 Pod正常運行

我們查看Pod的名稱。


# oc get pods
NAME                                 READY     STATUS             RESTARTS   AGE
jboss-webserver31-tomcat8-openshift-597c7f995-wtqrf   1/1   Running    0     25s

登錄到Pod,切換到/usr/local/s2i目錄中,查看鏡像中的S2I腳本文件。


sh-4.2$ cd /usr/local/s2i; ls
assemble  common.sh  run  save-artifacts  scl-enable-maven

查看assemble腳本。


sh-4.2$ cat assemble
#!/bin/sh
set -e
source "${JBOSS_CONTAINER_UTIL_LOGGING_MODULE}/logging.sh"
source "${JBOSS_CONTAINER_MAVEN_S2I_MODULE}/maven-s2i"
source "${JBOSS_CONTAINER_JWS_S2I_MODULE}/s2i-core-hooks"
maven_s2i_build

在上面腳本中的核心功能是執行maven_s2i_build這個函數。接下來,我們通過分析這個函數來體會Builder鏡像設計的精妙所在。

maven_s2i_build函數在/opt/jboss/container/maven/s2i/maven-s2i文件中進行了定義。

查看/opt/jboss/container/maven/s2i/maven-s2i中maven_s2i_build的函數的描述。


sh-4.2$ cat /opt/jboss/container/maven/s2i/maven-s2i
……
# main entry point, perform the build
function maven_s2i_build() {
  maven_s2i_init
  if [ -f "${S2I_SOURCE_DIR}/pom.xml" ]; then
    # maven build
    maven_s2i_maven_build
  else
    # binary build
    maven_s2i_binary_build
  fi
  s2i_core_copy_artifacts "${S2I_SOURCE_DIR}"
  s2i_core_process_image_mounts
  s2i_core_cleanup
  rm -rf /tmp/hsperfdata_jboss
}
……

上面的函數是一個判斷,當{S2I_SOURCE_DIR}中有pom.xml文件時調用maven_s2i_maven_build函數,否則調用maven_s2i_binary_build函數。在判斷體之外,調用s2i_core_copy_artifacts等函數。

由于篇幅有限,我們接下來只分析maven_s2i_maven_build和s2i_core_copy_artifacts兩個函數。

接下來查看本文件內maven_s2i_maven_build函數的描述。


# perform a maven build, i.e.  mvn ...
# internal method
function maven_s2i_maven_build() {
  maven_build "${S2I_SOURCE_DIR}" "${MAVEN_S2I_GOALS}"
  maven_s2i_deploy_artifacts
  maven_cleanup

也就是說,maven_s2i_maven_build函數調用了maven_build。而maven_build的定義在/opt/jboss/container/maven/default/maven.sh中,內容如下。


function maven_build() {
  local build_dir=${1:-$(cwd)}
  local goals=${2:-package}
  log_info "Performing Maven build in $build_dir"
  pushd $build_dir &> /dev/null
  log_info "Using MAVEN_OPTS ${MAVEN_OPTS}"
  log_info "Using $(mvn $MAVEN_ARGS --version)"
  log_info "Running 'mvn $MAVEN_ARGS $goals'"
  # Execute the actual build
  mvn $MAVEN_ARGS $goals
  popd &> /dev/null
}

也就是說maven_build最終調用的是mvn命令,對源碼進行構建。

整個調用鏈條是:S2I=>assemble腳本=>maven_s2i_build=>maven_s2i_maven_build=>maven_build=>mvn。

我們回到maven_s2i_build,當maven_s2i_maven_build構建成功以后,調用s2i_core_copy_artifacts函數。

我們查看s2i_core_copy_artifacts的定義(/opt/jboss/container/s2i/core/s2i-core文件中)。


# main entry point for copying artifacts from the build to the target
# $1 - the base directory
function s2i_core_copy_artifacts() {
  s2i_core_copy_configuration $*
  s2i_core_copy_data $*
  s2i_core_copy_deployments $*
  s2i_core_copy_artifacts_hook $*
}

也就是說,s2i_core_copy_artifacts又會包含4個函數。由于篇幅有限,我們僅以s2i_core_copy_data為例進行分析。

在同文件(/opt/jboss/container/s2i/core/s2i-core文件)中的代碼對s2i_core_copy_data進行了定義,內容如下。


# copy data files
# $1 - the base directory to which $S2I_SOURCE_DATA_DIR is appended
function s2i_core_copy_data() {
  if [ -d "${1}/${S2I_SOURCE_DATA_DIR}" ]; then
    if [ -z "${S2I_TARGET_DATA_DIR}" ]; then
      log_warning "Unable to copy data files.  No target directory specified for 
          S2I_TARGET_DATA_DIR"
    else
      if [ ! -d "${S2I_TARGET_DATA_DIR}" ]; then
        log_info "S2I_TARGET_DATA_DIR does not exist, creating ${S2I_TARGET_DATA_DIR}"
        mkdir -pm 775 "${S2I_TARGET_DATA_DIR}"
      fi
      log_info "Copying app data from $(realpath --relative-to ${S2I_SOURCE_DIR} 
          ${1}/${S2I_SOURCE_DATA_DIR}) to ${S2I_TARGET_DATA_DIR}..."
      rsync -rl --out-format='%n' "${1}/${S2I_SOURCE_DATA_DIR}"/ "${S2I_TARGET_
          DATA_DIR}"

代碼會進行一系列判斷,如果源目錄和目標目錄都同時存在,函數會調用rsync命令將源目錄的內容拷貝到目標目錄。

整個調用的鏈條是:S2I=>assemble腳本=>maven_s2i_build=>s2i_core_copy_artifacts=>s2i_core_copy_data=>rsync。

最后,我們查看S2I的run腳本。


sh-4.2$ cat /usr/local/s2i/run
#!/bin/sh
exec $JWS_HOME/bin/launch.sh

run腳本調用了launch.sh腳本。查看launch.sh腳本的部分內容。


sh-4.2$ cat /opt/webserver/bin/launch.sh
#!/bin/sh
CATALINA_OPTS="${CATALINA_OPTS} ${JAVA_PROXY_OPTIONS}"
escape_catalina_opts
log_info "Running $JBOSS_IMAGE_NAME image, version $JBOSS_IMAGE_VERSION"
exec $JWS_HOME/bin/catalina.sh run

launch.sh最終調用了catalina.sh腳本來啟動webserver。而$JWS_HOME的參數是讀取的Pod環境變量。


sh-4.2$ env |grep -i JWS
JBOSS_CONTAINER_JWS_S2I_MODULE=/opt/jboss/container/jws/s2i
JWS_HOME=/opt/webserver

整個調用的鏈條是:S2I=>run腳本=>launch.sh腳本=>catalina.sh腳本。

也就是說,應用的源碼被mvn構建以后,拷貝到Tomcat的部署目錄中,然后catalina.sh腳本啟動webserver,從而啟動應用。

在上文我們只是分析了Builder鏡像中S2I腳本的冰山一角,而紅帽提供Builer鏡像的完備性、功能強大性可想而知,官方提供的Builder鏡像也能夠滿足絕大多數S2I的需求。

4.手工定制Builder鏡像

那么有沒有我們的需求超過紅帽官方提供的Builder鏡像,需要我們定制化的時候呢?

答案是肯定的。我們僅需要滿足S2I的規范就可以自行構建一個支持S2I的Builder鏡像,其流程如圖4-13所示。

圖4-13 定制S2I的流程

構建Builder鏡像的步驟如下:

·首先使用S2I命令行創建目錄結構,目錄中將會包含S2I的腳本、Dockerfile等。

·基礎鏡像通常使用紅帽官網提供的鏡像,我們編寫新的Dockerfile引用基礎鏡像。在構建子鏡像時也可以用新的S2I腳本覆蓋父鏡像的腳本。

·Builder鏡像構建成功以后,可以接收外部Git的代碼注入,對源碼進行編譯打包,最終形成應用鏡像。

·應用鏡像會被部署到OpenShift集群中,并創建Service和Router對象用于應用訪問。

定制化Builder鏡像的第一步就是選擇基礎鏡像,基礎鏡像的選擇決定了工作量和難易程度。通常有兩種選擇:

·選擇使用紅帽已經提供的Builder鏡像進行修改。直接以官方提供的Builder鏡像作為基礎鏡像,書寫Dockerfile進行任何想要的定制化,我們稱生成新的Builder鏡像為子Builder鏡像,官方提供的Builder鏡像為父Builder鏡像。

·使用最底層基礎鏡像(如openjdk或rhel)進行制作。根據社區或紅帽提供的最底層鏡像(如openjdk或rhel)自行書寫Dockerfile、S2I的相關腳本,生成子Builder鏡像。然后基于子Builder鏡像進行S2I,生成應用鏡像,實現應用容器化。

第一種方法的優點是書寫Dockerfile較為簡便(建立在紅帽提供的Builder鏡像的Dockerfile基礎上),缺點是生成的鏡像較大,生成的鏡像需要經過壓縮處理。

第二種方法的優點是生成的鏡像較小,缺點是需要技術人員很熟悉紅帽制作鏡像規范以及OpenShift對鏡像的要求,否則做出來的鏡像有些功能會不工作。

根據經驗,我們建議選擇第一種方法,即選擇使用紅帽已經提供的Builder鏡像進行修改,具體操作通常有三種方法:

·使用已有的紅帽Builder鏡像,在構建應用的時候采用覆蓋默認父鏡像S2I腳本的方法,不構建子Builder鏡像,直接生成應用鏡像,實現應用容器化。

·使用已有的紅帽基礎鏡像或Builder鏡像書寫新的Dockerfile,不覆蓋父鏡像S2I腳本,構建子Builder鏡像。然后基于子Builder鏡像進行S2I,生成應用鏡像,實現應用容器化。

·使用已有的紅帽基礎鏡像或Builder鏡像書寫新的Dockerfile,覆蓋父鏡像S2I腳本,構建子Builder鏡像。然后基于子Builder鏡像進行S2I,生成應用鏡像,實現應用容器化。

在上述三種方法中,定制的復雜度逐級提升。第一種和第三種使用較多,并且比較有代表性,我們將介紹這兩種方法。

(1)采用覆蓋默認父鏡像S2I腳本的方法生成應用鏡像

我們以紅帽提供的rhscl/httpd-24-rhel7 Builder鏡像為例。展示如何通過覆蓋父鏡像S2I腳本的方法生成應用鏡像。

首先導入rhscl/httpd-24-rhel7的Image Stream。


# oc import-image rhscl/httpd-24-rhel7 --from=registry.access.redhat.com/rhscl/
    httpd-24-rhel7 --confirm
imagestream.image.openshift.io/httpd-24-rhel7 imported

通過docker/podman run運行鏡像。


# podman run --name test -it rhscl/httpd-24-rhel7 bash

查看Builder鏡像的assemble腳本。


bash-4.2$ cd /usr/libexec/s2i/
bash-4.2$ cat assemble
#!/bin/bash
set -e
source ${HTTPD_CONTAINER_SCRIPTS_PATH}/common.sh
echo "---> Enabling s2i support in httpd24 image"
config_s2i
echo "---> Installing application source"
cp -Rf /tmp/src/. ./
process_extending_files ${HTTPD_APP_ROOT}/src/httpd-post-assemble/ ${HTTPD_
    CONTAINER_SCRIPTS_PATH}/post-assemble/
# Fix source directory permissions
fix-permissions ./

查看run腳本內容。


bash-4.2$ cat run
#!/bin/bash
source ${HTTPD_CONTAINER_SCRIPTS_PATH}/common.sh
export HTTPD_RUN_BY_S2I=1
exec run-httpd $@

接下來,我們創建S2I的腳本(assemble和run)和源碼文件(index.html)。其目錄結構如下,需要注意的是s2i必須是隱藏目錄。


# tree -a
└── s2i-scripts
    ├── index.html
    └── .s2i
        └── bin
            ├── assemble
            └── run

我們查看源碼index.html內容。


# cat /root/david/s2i-scripts/index.html
This is David Wei test for S2I!!!

編寫新的assemble腳本,我們可以看到,這和rhscl/httpd-24-rhel7中的assemble腳本內容的區別。新assemble腳本主要完成如下事情:

·執行腳本的時候輸出DavidWei S2I test!!!。

·將/tmp/src/.目錄下的內容拷貝到./,由于后面GIT倉庫地址包含的源碼是index.html,因此拷貝的是該文件。

·將如下內容重定向到./info.html文件中。


Page built on $DATE
DavidWei test: Proudly served by Apache HTTP Server version $HTTPD_VERSION

查看腳本內容。


# cat /root/david/s2i-scripts/.s2i/bin/assemble
#!/bin/bash
set -e
source ${HTTPD_CONTAINER_SCRIPTS_PATH}/common.sh
echo "---> DavidWei S2I test!!!"
config_s2i
echo "---> Installing application source"
cp -Rf /tmp/src/. ./
process_extending_files ${HTTPD_APP_ROOT}/src/httpd-post-assemble/ ${HTTPD_
    CONTAINER_SCRIPTS_PATH}/post-assemble/
# Fix source directory permissions
fix-permissions ./
DATE=`date "+%b %d, %Y @ %H:%M %p"`
echo "---> Creating info page"
echo "Page built on $DATE" >> ./info.html
echo "DavidWei test:Proudly served by Apache HTTP Server version $HTTPD_VERSION" 
    >> ./info.html

查看run腳本內容,是打開debug模式。


# cat /root/david/s2i-scripts/.s2i/bin/run
# Make Apache show 'debug' level logs during startup
run-httpd -e debug $@

接下來,將/root/david/s2i-scripts目錄的內容(S2I腳本和index.html)提交到GitHub。


# git init
# git add /root/david/s2i-scripts/*
# git add /root/david/s2i-scripts/.s2i/*
# git remote add origin https://github.com/ocp-msa-devops/s2itest.git
# git commit -m "s2i scripts"
# git push -u origin master -f

提交成功以后,使用rhscl/httpd-24-rhel7和剛上傳的源碼地址進行S2I。將應用的名稱設置為weixinyu。


# oc new-app --name weixinyu httpd-24-rhel7~https://github.com/ocp-msa-devops/s2itest
--> Found image 0f1cb8c (6 weeks old) in image stream "openwhisk/httpd-24-rhel7" 
    under tag "latest" for "httpd-24-rhel7"

查看Builder Pod的日志,我們可以看到:

·構建是使用rhscl/httpd-24-rhel7指向的Docker鏡像。

·輸出DavidWei S2I test!!!,說明執行了新的assemble腳本。

具體內容如下。


# oc logs -f weixinyu-1-build
Using registry.access.redhat.com/rhscl/httpd-24-rhel7@sha256:684590af705d72af64b
    88ade55c31ce6884bff3c1da7cbf8c11aaa0a4908f63f as the s2i Builder Image
---> DavidWei S2I test!!!
AllowOverride All
---> Installing application source
=> sourcing 20-copy-config.sh ...
=> sourcing 40-ssl-certs.sh ...
---> Creating info page
Pushing image docker-registry.default.svc:5000/openwhisk/weixinyu:latest ...
Push successful

接下來,我們為部署好的Pod創建路由。


# oc expose svc weixinyu --port 8080
route.route.openshift.io/weixinyu exposed
# oc get route
weixinyu     weixinyu-openwhisk.apps.example.com     weixinyu      8080   None

通過curl訪問路由,得出的結果正是我們在index.html中定義的內容。


# curl http://weixinyu-openwhisk.apps.example.com
This is David Wei test for S2I!!!

通過curl訪問路由,增加info.html URI,得到的返回信息正是我們在新assemble腳本中定義的內容。


# curl http://weixinyu-openwhisk.apps.example.com/info.html
Page built on Jun 06, 2019 @ 14:35 PM
DavidWei test: Proudly served by Apache HTTP Server version 2.4

也就是說,在S2I過程中指定GitHub地址上的新S2I腳本替換了父鏡像中的S2I腳本。

至此,我們實現了使用已有的Builder鏡像,采用覆蓋默認父鏡像S2I腳本的方法,不重新構建子Builder鏡像,直接生成應用鏡像,也就是實現了應用的容器化。

(2)書寫新的Dockerfile,覆蓋父鏡像S2I腳本,生成子Builder鏡像

接下來,我們看另外一類需求。在前文中,我們分析了Tomcat的Builder鏡像。我們查看鏡像的標簽,我們使用的是latest,如圖4-14所示。

圖4-14 Tomcat鏡像標簽

我們查看1.4-7 tag對應的Dockerfile,它使用的是Tomcat 8:3.1.6,Maven是3.5,如圖4-15所示。

如果客戶需要的S2I builder的Tomcat版本必須是8.5,并且必須包含Maven 3.6.1,此外還必須支持SVN(S2I默認僅支持Git),我們應該怎么做呢?這時需要利用紅帽提供的Builder鏡像自行定制子Builder鏡像。

圖4-15 Tomcat的Dockerfile內容

使用s2i create命令來創建所需的模板文件,以創建新的S2I Builder鏡像。

首先安裝s2i命令行。


# subscription-manager repos  --enable="rhel-server-rhscl-7-rpms"
Repository 'rhel-server-rhscl-7-rpms' is enabled for this system.
# yum -y install source-to-image

創建鏡像和對應的目錄。


# s2i create s2i_tomcat8.5_maven3.6.1  s2i_tomcat8.5_maven3.6.1

查看目錄結構。


# tree s2i_tomcat8.5_maven3.6.1
s2i_tomcat8.5_maven3.6.1
├── Dockerfile
├── Makefile
├── README.md
├── s2i
│   └── bin
│       ├── assemble
│       ├── run
│       ├── save-artifacts
│       └── usage
└── test
    ├── run
    └── test-app
        └── index.html

使用新的Dockerfile,針對官網提供的webserver31-tomcat8-openshift。

·用本地的apache-tomcat-8.5.24覆蓋到/opt/webserver下。

·用本地的Maven3.6.1覆蓋父Builder鏡像中的Maven3.5。

從互聯網下載Tomcat 8.5.24和Maven3.6.1的安裝包,如圖4-16所示。

放到我們上一步創建的目錄中解壓縮,如圖4-17所示。

圖4-16 Tomcat和Maven安裝包

圖4-17 解壓安裝包

編寫新的Dockerfile,內容如下。


# tomcat8.5
FROM registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift
RUN rm -fr /opt/webserver/*
COPY ./apache-tomcat-8.5.24/ /opt/webserver
RUN ln -s /deployments /opt/webserver/webapps
USER root
RUN rm -fr /opt/rh/rh-maven35/root/usr/share/maven/*
COPY ./maven3.6.1/ /opt/rh/rh-maven35/root/usr/share/maven
COPY ./maven3.6.1/bin/ /opt/rh/rh-maven35/root/bin

RUN chown -R jboss:root /opt/webserver && \
    chmod -R a+w /opt/webserver && \
    chmod -R 777 /opt/webserver/bin && \
    chmod -R 777 /opt/webserver && \
    chmod -R 777 /opt/rh/rh-maven35/root/usr/share/maven && \
    chmod -R 777 /opt/rh/rh-maven35/root/bin
USER 1002

由于S2I默認僅支持Git,如果我們要用SVN,就需要在assemble腳本中進行相關設置,也就是在執行assemble腳本時觸發命令從SVN_URI參數設置的地址獲取源代碼,即通過svn的方式獲取代碼,然后使用mvn進行編譯。最后將編譯好的War包拷貝到Webserver的webapps的目錄中,Tomcat會自動解壓和部署應用。


if [[ "$1" == "-h" ]]; then
        exec /usr/libexec/s2i/usage
fi
# Restore artifacts from the previous build (if they exist).
#
if [ "$(ls /tmp/artifacts/ 2>/dev/null)" ]; then
  echo "---> Restoring build artifacts..."
  mv /tmp/artifacts/. ./
fi
echo "---> Installing application source..."
cp -Rf /tmp/src/. ./
ls -l ./ 
ls -l /tmp/src/
WORK_DIR=/tmp/src;
cd $WORK_DIR;
if [ ! -z ${SVN_URI} ] ; then
  echo "Fetching source from Subversion repository ${SVN_URI}"
  svn co ${SVN_URI} --username  ${SVN_USER} --password ${SVN_PWD} --no-auth-cache
  export SRC_DIR=`basename $SVN_URI`
  echo "Finished fetching source from Subversion repository ${SVN_URI}"
else
  echo "SVN_URI not set, skip Subverion source download";
fi
echo "---> Building application from source..."
cd $WORK_DIR/$SRC_DIR/
${BUILD_CMD}
echo "---> Build application successfully."
find /tmp/src/ -name '*.war'|xargs -i cp -v {} /opt/webserver/webapps/

由于紅帽提供的run腳本最終調用catalina.sh是使用的$JWS_HOME,因此更替版本不會使執行路徑發生變化,run腳本使用父鏡像的腳本即可,或直接使用如下內容啟動Webserver。


exec /opt/webserver/bin/catalina.sh run

所有準備工作完成之后就可以手工構建鏡像,輸出內容如下。


Sending build context to Docker daemon 19.66 MB
Step 1/9 : FROM registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-
    openshift
 ---> c303ee1e1273
Step 2/9 : RUN rm -fr /opt/webserver/*
 ---> Running in aa5cab28ecc2

 ---> 0eaa859906d7
Removing intermediate container aa5cab28ecc2
Step 3/9 : COPY ./apache-tomcat-8.5.24/ /opt/webserver
 ---> 132fd21440c3
Removing intermediate container ea09b46d8a1a
Step 4/9 : RUN ln -s /deployments /opt/webserver/webapps
 ---> Running in e9c43075f480

 ---> 56faa88135d3
Removing intermediate container e9c43075f480
Step 5/9 : USER root
 ---> Running in e96b4ef66a20
 ---> 2fc5139ee082
Removing intermediate container e96b4ef66a20
Step 6/9 : RUN rm -fr /opt/rh/rh-maven35/root/usr/share/maven/*
 ---> Running in 89d19c564fdd

 ---> 38e364d3ab50
Removing intermediate container 89d19c564fdd
Step 7/9 : COPY ./maven3.6.1/ /opt/rh/rh-maven35/root/usr/share/maven
 ---> 2ec060686ce4
Removing intermediate container 047930b49000
Step 8/9 : RUN chown -R jboss:root /opt/webserver &&     chmod -R a+w /opt/
    webserver &&     chmod -R 777 /opt/webserver/bin &&     chmod -R 777 /
    opt/webserver &&     chmod -R 777 /opt/rh/rh-maven35/root/usr/share/maven &&     
    chmod -R 777 /opt/rh/rh-maven35/root/bin
 ---> Running in dbda875ca5f0

 ---> 02bb0fa0eadb
Removing intermediate container dbda875ca5f0
Step 9/9 : USER 1002
 ---> Running in 4fd3ac609041
 ---> 703e3a4d58c2
Removing intermediate container 4fd3ac609041
Successfully built 703e3a4d58c2

查看構建成功的子Builder鏡像。


# podman images | grep -i s2i
s2i_tomcat8.5_maven3.6.1    latest    703e3a4d58c2    6 minutes ago    585 MB

我們可以將構建成功的子Builder鏡像推送到自己的鏡像倉庫。至此,我們完成了定制化Builder鏡像。

為了方便后續使用,通常會創建OpenShift的模板來實現構建和部署應用,模板的具體配置方法,我們將在第7章中進行詳細介紹,模板創建成功后,如圖4-18所示。

圖4-18 模板參數

關于構建Builder鏡像采用的基礎鏡像,當然也可以采用更為基礎的基礎鏡像。例如我們可以使用openjdk8作為基礎鏡像來生成s2i_tomcat8.5_maven3.6.1,只不過與使用已有的Builder鏡像:webserver31-tomcat8-openshift相比,這種方式的步驟會多很多。

如果使用openjdk,Dockerfile的部分內容參考如圖4-19所示。

在介紹完應用容器化的方法以后,我們接下來介紹開發人員如何在OpenShift上快速部署應用。

圖4-19 從openjdk構建鏡像的Dockerfile

主站蜘蛛池模板: 德昌县| 新巴尔虎右旗| 灵川县| 绿春县| 新丰县| 南靖县| 上虞市| 康乐县| 鹤壁市| 天峻县| 霍邱县| 龙川县| 苗栗市| 嘉荫县| 曲靖市| 策勒县| 石嘴山市| 吐鲁番市| 德惠市| 衡阳县| 大理市| 周至县| 岫岩| 海原县| 武清区| 新宾| 普兰县| 北碚区| 武汉市| 固镇县| 邹城市| 白城市| 邮箱| 乐昌市| 吉安县| 财经| 江安县| 曲沃县| 德江县| 石城县| 香港 |