文章導讀
- 本文僅代表作者的個人觀點;
- 本文的内容僅限于技術探讨,不能作為指導生産環境的素材;
- 本文素材是紅帽公司産品技術和手冊;
一、什麼是建構?
建構是:
- 将輸入參數轉換為結果對象的過程
- 用于将源代碼轉換為可運作容器映像的建構
- 建構配置或建構配置檔案的特點是: 建構政策、至少有一個來源
- 政策決定了過程;源提供輸入
容器中應用的四種建構政策:
4建構政策:
- Source-to-Image (S2I)
- Docker
- Pipeline
- Custom
作為建構輸入提供的六種源類型:
- Git
- Dockerfile
- Binary
- Image
- Input secrets
- External artifacts
二進制源類型建構
- 從本地檔案系統到建構器的二進制格式流内容
- 完全基于oc的起始建構
從二進制源代碼開始建構,使用以下選項之一調用oc start-build:
S2I增量建構重用以前建構的image中的工件 要建立增量建構,請修改BuildConfig政策定義:
- 指定支援增量建構的映像
- Flag控制是否嘗試增量建構
- 如果建構器映像不支援增量建構,則建構仍會成功
- 由于缺少save-artifacts腳本,日志消息表明增量建構不成功
将建構配置設定給特定節點
通過在建構配置的nodeSelector字段中指定标簽,可以将建構目标定位為在特定節點上運作nodeSelector在排程建構窗體時與節點标簽比對的鍵值對的值集:
與建構配置關聯的建構僅在具有region = primary和nodetype = build标簽的節
連結建構:
Build 1生成編譯的工件
Build 2将工件放置在運作工件的單獨image中。
連結建構示例
S2I建構與Docker建構相結合
在單獨的運作時映像中編譯工件和位置
連結建構BuildConfig - 建構1
第一次建構産生包含WAR的圖像,image被推送到工件image stream,輸出工件路徑取決于S2I建構器的彙編腳本
輸出工件/wildfly/standalone/deployments/ROOT.war:
連結建構BuildConfig - 建構2
在第一次建構時使用輸出圖像内的WAR檔案路徑的image stream
内聯Dockerfile将WAR檔案複制到運作時映像中:
from指定Docker建構包括來自工件圖像圖像流的圖像輸出,即先前建構的目标
paths指定目标映像中包含哪些路徑以包含在目前Docker建構中
運作時映像用作Docker建構的源映像
每次第一次建構成功完成時,ImageChange觸發器都會調用第二次建構
使用OpenShift建構Maven Slave圖像
OpenShift Build Configs可用于建構Maven Slave Image
Build Config必須位于将引用image的Jenkins項目中
示例:使用skopeo建構從屬映像
二、實驗展現
登入Gogs上,在CICDLabs組織下,建立一個名為openshift- task- Private的新存儲庫,并確定它被設定為Private。
制作一個openshift任務庫的副本并将其推入Gogs:
注意GOGS儲存庫路徑。
複制OpenSHIFT任務庫并将其推入Gogs:
建立一個指向此存儲庫的新應用程式:
首先建立一個gogs-secret
oc create secret generic gogs-secret --from-literal=username=david --from-literal=password=david
建立應用:
oc new-app --template=eap70-basic-s2i --param APPLICATION_NAME=tasks --param SOURCE_REPOSITORY_URL=http://gogs.xyz-gogs80.svc.cluster.local:3000/CICDLabs/openshift-tasks-private1.git --param SOURCE_REPOSITORY_REF=master --param CONTEXT_DIR=/ --param MAVEN_MIRROR_URL=http://nexus3.xyz-nexus80.svc.cluster.local:8081/repository/maven-all-public
緩存的工件
JBoss EAP S2I builder映像支援在建構之間儲存建構工件,這大大減少了建構時間。建構配置需要反映這一點。
更改建構配置以增量方式建構。将forcePull更改為false。這可以防止OpenShift每次在建構應用程式時都拉拽生成器映像,這将花費很多時間。
使用oc patch編輯bc,在sourceStrategy下添加增量标志,并将forcePull更改為false:
oc patch bc/tasks --patch='{"spec": {"strategy": {"sourceStrategy": {"incremental": true}}}}'
oc patch bc/tasks --patch='{"spec": {"strategy": {"sourceStrategy": {"forcePull": false}}}}'
三、實驗展現:環境介紹實作二進制建構
使用OpenJDK S2I映像示範使用現有Spring引導應用程式進行的二進制建構。
建立Spring啟動應用程式
從https://github.com/wkulhanek/ola.git建立一個新的Java Spring引導應用程式。
使用帶有1.2标簽的redhat-openjdk18-openshift image stream來建構應用程式。
確定在應用程式建立之後為其建立路由:
確定應用在運作:
部署使用二進制建構
使用二進制建構政策建構相同的應用程式,這意味着您首先在本地建構應用程式,然後建立一個二進制建構配置,最後使用本地建構的JAR檔案作為二進制建構的輸入啟動一個二進制建構。
cd $HOME
git clone https://github.com/wkulhanek/ola.git
cd ola
mvn clean package
檢視建構成功的jar:
java -jar $HOME/ola/target/ola.jar
建立一個名為ola-binary的二進制建構,這個建構現在需要本地檔案系統中的二進制部署工件。
啟動一個新的建構,并将編譯後的檔案流到建構中。確定在建構執行時遵循它。
當您執行oc start-build指令時,您将看到建構很快完成。二進制建構複制預建構的工件,并将副本移動到正确的目錄中。在本例中,它複制ola。jar檔案放入S2I映像,然後将其移動到/deployments。
建構完成後,從新建立的映像部署應用程式。
将應用程式公開為ola-binary route。
oc new-app ola-binary
oc expose svc/ola-binary --port=8080
四、實驗展現:實作連結建構
連結建構,首先使用build image建構應用程式。然後将建構的工件部署到第二次運作時映像中。這隻對Java或Go這樣的編譯語言有意義。
第一步,通過S2I建構應用鏡像
在這個步驟中,我們就是上對go進行了編譯。
go應用的源碼:
https://github.com/tonykay/ose-chained-builds/blob/master/go-scratch/hello_world/main.go
package main
import (
"fmt"
"net/http"
)
const (
port = ":8080"
)
var calls = 0
func HelloWorld(w http.ResponseWriter, r *http.Request) {
calls++
fmt.Fprintf(w, "Hello, world! You have called me %d times.\n", calls)
fmt.Fprintf(w, "You have successfully finished this lab.\n")
}
func init() {
fmt.Printf("Started server at http://localhost%v.\n", port)
http.HandleFunc("/", HelloWorld)
http.ListenAndServe(port, nil)
}
func main() {}
然後,使用S2I - Go作為builder image,編譯go源碼。
首先,從DockerHub導入jorgemoralespou/ S2I - Go映像作為您的S2I Go映像。
建立一個新的建構來編譯示例Go應用程式。
要使用的上下文目錄是/go-scratch/hello_world。
oc new-build s2i-go~https://github.com/tonykay/ose-chained-builds \
--context-dir=/go-scratch/hello_world --name=builder
遵循建構日志,等待Go應用程式編譯,并等待映像完成建構,然後繼續下一步。
我們檢視go編譯的日志:
[xiwei-redhat.com@bastion 0 ~]$ oc logs builder-1-build
===> Build started at Wed Aug 29 05:55:55 UTC 2018
---> Preparing source...
---> Downloading dependencies...
main
---> Building application source...
runtime/internal/sys
runtime/internal/atomic
runtime
errors
internal/race
sync/atomic
math
unicode/utf8
unicode
sort
container/list
crypto/subtle
sync
io
syscall
internal/singleflight
hash
crypto/cipher
hash/crc32
crypto/hmac
bytes
strings
bufio
path
strconv
math/rand
time
internal/syscall/unix
reflect
crypto
crypto/aes
crypto/rc4
encoding/base64
crypto/sha512
crypto/md5
crypto/sha1
crypto/sha256
encoding/pem
os
path/filepath
net
fmt
encoding/binary
crypto/des
io/ioutil
compress/flate
math/big
encoding/hex
log
internal/golang.org/x/net/http2/hpack
mime
mime/quotedprintable
net/http/internal
net/url
compress/gzip
crypto/elliptic
crypto/dsa
crypto/rand
encoding/asn1
crypto/rsa
net/textproto
crypto/ecdsa
crypto/x509/pkix
crypto/x509
mime/multipart
crypto/tls
net/http
main
===> Build completed at Wed Aug 29 05:56:37 UTC 2018
Binary at /opt/app-root/src/go/src/main
===> Elapsed time: 42 seconds
Pushing image docker-registry.default.svc:5000/xyz-builds80/builder:latest ...
Pushed 0/7 layers, 1% complete
Pushed 1/7 layers, 19% complete
Pushed 2/7 layers, 32% complete
Pushed 3/7 layers, 48% complete
Pushed 4/7 layers, 62% complete
Pushed 5/7 layers, 95% complete
Pushed 6/7 layers, 97% complete
Pushed 7/7 layers, 100% complete
Push successful
從上面标黃的部分可以看到,go建構成功以後的二進制檔案,放到了/opt/app-root/src/go/src/main目錄下。
當image建構成功以後,我們用将其部署成pod,也可以看到建構成功的檔案:
而/opt/app-root/src/go/src/main/main是個可運作的二進制檔案:
接下來,我們檢查生成的建構程式imagestream:
建立第二個(連結的)建構,它擷取建構的工件(/opt/app-root/src/go/src/main/main)并将其部署到一個小的運作時映像scratch中。而scratch實際上是一個空檔案。
步驟是:使用scratch Docker映像作為基礎映像,然後,将/opt/app-root/src/go/src/main/main拷貝到/main目錄下,然後使用docker build完成
oc new-build --name=runtime \
--source-image=builder \
--source-image-path=/opt/app-root/src/go/src/main/main:. \
--dockerfile=$'FROM scratch\nCOPY main /main\nEXPOSE 8080\nENTRYPOINT ["/main"]'
上面的指令行,相當于建立如下一個docker file,然後在建構的時候,執行docker build
檢視指令輸出結果:
[xiwei-redhat.com@bastion 0 /]$ oc logs -f bc/runtime
Pulling image "docker-registry.default.svc:5000/xyz-builds80/builder@sha256:3a674cf1b914720204509ab8da9af6f8255a51bd6f1709ea98cbeeabd2d6ebea" ...
Step 1/6 : FROM scratch
--->
Step 2/6 : COPY main /main
---> Using cache
---> 5c07c74949ea
Step 3/6 : EXPOSE 8080
---> Using cache
---> 10efcc15fba7
Step 4/6 : ENTRYPOINT /main
---> Using cache
---> e8c2c705d4ed
Step 5/6 : ENV "OPENSHIFT_BUILD_NAME" "runtime-1" "OPENSHIFT_BUILD_NAMESPACE" "xyz-builds80"
---> Running in 4a2467b85f03
---> 42ecaf43ece5
Removing intermediate container 4a2467b85f03
Step 6/6 : LABEL "io.openshift.build.name" "runtime-1" "io.openshift.build.namespace" "xyz-builds80"
---> Running in d6f93173f1a7
---> 06c1644c70e3
Removing intermediate container d6f93173f1a7
Successfully built 06c1644c70e3
Pushing image docker-registry.default.svc:5000/xyz-builds80/runtime:latest ...
Push successful
oc new-app runtime --name=my-application
oc expose svc/my-application