《OpenShift 4.x HOL教程汇总》
说明:本文已经在OpenShift 4.12环境中验证
文章目录
DevSecOps Workshop 说明
本Workshop参考了“RedHatGov/devsecops-workshop-dashboard”,使用 Jenins 作为 CI/CD 的引擎实现如下 DevSecOps 的应用发布流程:
- 代码从Gogs克隆到Jenkins的执行器节点上。
- 代码由Jenkins使用Maven构建。
- 针对源代码执行JUnit测试。
- 通过SonarQube分析源代码的漏洞、错误和不良模式。
- 将WAR工件推送到Nexus存储库管理器。
- 将基于JBossEAP上的任务应用于WAR工件,建立一个容器镜像(tasks:latest)。
- 将容器镜像部署在DEV项目的一个新容器中。
- 在STAGE项目中,DEV镜像被标记为应用程序版本(tasks:7.x)。
- 镜像被部署在STAGE项目的一个新容器中。
安装 DevSecOps Workshop 基本环境
参照以下文档安装Jenkins、Nexus、SonarQube、Gogs等Workshop需要的组件。
《Hands-on Lab (8) - 基于Gogs+Nexus+Sonarqube的Jenkins CI/CD Pipeline》
安装配置 Registry 环境
- 如果需要 Quay 对镜像进行安全扫描,可参照《安装 ODF 并部署红帽 Quay (1 Worker)》或《安装 ODF 并部署红帽 Quay (3 Worker)》在 OpenShift 上安装 Quay,或注册一个 Quay.io 账号。
- 如果需要 Quay 对镜像进行安全扫描,还需执行以下命令,允许从 Jenkins 访问 OpenShift 自带的 Image Registry。
$ oc patch configs.imageregistry.operator.openshift.io/cluster --patch '{"spec":{"defaultRoute":true}}' --type=merge
Jenkins Pipeline 操作步骤
完成上面的 《Hands-on Lab (8) - 基于Gogs+Nexus+Sonarqube的Jenkins CI/CD Pipeline》 安装过程后就已经有了一个完整的 Jenkins Pipeline 过程。如果需要还可参照以下一个教程从零开始实现一个完成的 Jenkins Pipeline 过程。
- http://redhatgov.io/workshops/secure_software_factory
- https://github.com/liuxiaoyu-git/devsecops-workshop-dashboard/tree/develop/jenkins/workshop/content
注意:Hands-on Lab (8) 中自带的 Jenkins Pipeline 配置和以上 2 个定制文档的 Jenkins Pipeline 的配置稍有差别。以下 “最终 Jenkins Pipeline 配置” 使用的是定制文档中的 Jenkins Pipeline。
最终 Jenkins Pipeline 配置
最终 Jenkins Pipeline 的配置可参见以下或 https://github.com/liuxiaoyu-git/OpenShift-HOL/blob/master/devsecops-jenkins.yaml
注意:以下是包含本地 Quay 操作的 BuildConfig 配置。请修改其中的 namespace、oc_user、oc_pass、ocp_api、ocp_registry、quay_user、quay_pass、quay_server、user1-dev、user1-stage 的配置。
kind: BuildConfig
apiVersion: build.openshift.io/v1
metadata:
name: tasks-pipeline
namespace: user1-cicd
spec:
successfulBuildsHistoryLimit: 5
failedBuildsHistoryLimit: 5
strategy:
type: JenkinsPipeline
jenkinsPipelineStrategy:
jenkinsfile: >-
def version, mvnCmd = "mvn -s configuration/cicd-settings-nexus3.xml"
def oc_user = "opentlc-mgr"
def oc_pass = "r3dh4t1!"
def ocp_api = "api.cluster-6d16.6d16.sandbox1717.opentlc.com:6443"
def ocp_registry = "default-route-openshift-image-registry.apps.cluster-6d16.6d16.sandbox1717.opentlc.com"
def quay_user = "user1"
def quay_pass = "openshift"
def quay_repo = "jboss-eap70-openshift"
def quay_server="quay.apps.cluster-6d16.6d16.sandbox1717.opentlc.com"
pipeline {
agent {
label 'maven'
}
stages {
stage('Build App') {
steps {
git branch: 'eap-7', url: 'http://gogs:3000/gogs/openshift-tasks.git'
script {
def pom = readMavenPom file: 'pom.xml'
version = pom.version
}
sh "${mvnCmd} install -DskipTests=true"
}
}
stage('Test') {
steps {
sh "${mvnCmd} test"
step([$class: 'JUnitResultArchiver', testResults: '**/target/surefire-reports/TEST-*.xml'])
}
}
stage('Code Analysis') {
steps {
script {
sh "${mvnCmd} sonar:sonar -Dsonar.host.url=http://sonarqube:9000 -DskipTests=true"
}
}
}
stage('Archive App') {
steps {
sh "${mvnCmd} deploy -DskipTests=true -P nexus3"
}
}
stage('Create Image Builder') {
when {
expression {
openshift.withCluster() {
openshift.withProject(env.DEV_PROJECT) {
return !openshift.selector("bc", "tasks").exists();
}
}
}
}
steps {
script {
openshift.withCluster() {
openshift.withProject(env.DEV_PROJECT) {
openshift.newBuild("--name=tasks", "--image-stream=jboss-eap70-openshift:1.5", "--binary=true")
}
}
}
}
}
stage('Build Image') {
steps {
sh "rm -rf oc-build && mkdir -p oc-build/deployments"
sh "cp target/openshift-tasks.war oc-build/deployments/ROOT.war"
script {
openshift.withCluster() {
openshift.withProject(env.DEV_PROJECT) {
openshift.selector("bc", "tasks").startBuild("--from-dir=oc-build", "--wait=true")
}
}
}
}
}
stage('Create DEV') {
when {
expression {
openshift.withCluster() {
openshift.withProject(env.DEV_PROJECT) {
return !openshift.selector('dc', 'tasks').exists()
}
}
}
}
steps {
script {
openshift.withCluster() {
openshift.withProject(env.DEV_PROJECT) {
def app = openshift.newApp("tasks:latest")
app.narrow("svc").expose();
def dc = openshift.selector("dc", "tasks")
while (dc.object().spec.replicas != dc.object().status.availableReplicas) {
sleep 10
}
openshift.set("triggers", "dc/tasks", "--manual")
}
}
}
}
}
stage('Deploy DEV') {
steps {
script {
openshift.withCluster() {
openshift.withProject(env.DEV_PROJECT) {
openshift.selector("dc", "tasks").rollout().latest();
}
}
}
}
}
stage('Promote to STAGE?') {
steps {
timeout(time:15, unit:'MINUTES') {
input message: "Promote to STAGE?", ok: "Promote"
}
script {
openshift.withCluster() {
openshift.tag("${env.DEV_PROJECT}/tasks:latest", "${env.STAGE_PROJECT}/tasks:${version}")
}
}
}
}
stage('Deploy STAGE') {
steps {
script {
openshift.withCluster() {
openshift.withProject(env.STAGE_PROJECT) {
if (openshift.selector('dc', 'tasks').exists()) {
openshift.selector('dc', 'tasks').delete()
openshift.selector('svc', 'tasks').delete()
openshift.selector('route', 'tasks').delete()
}
openshift.newApp("tasks:${version}").narrow("svc").expose()
}
}
}
}
}
stage('Clair Container Vulnerability Scan') {
agent {
label 'skopeo'
}
steps {
script {
sh "oc login -u $oc_user -p $oc_pass --insecure-skip-tls-verify https://$ocp_api 2>&1"
sh 'skopeo copy --src-creds="$(oc whoami):$(oc whoami -t)"' + " --src-tls-verify=false --dest-creds=$quay_user:$quay_pass --dest-tls-verify=false docker://$ocp_registry/${env.DEV_PROJECT}/tasks:latest docker://$quay_server/$quay_user/tasks:stage"
}
}
}
}
}
env:
- name: DEV_PROJECT
value: user1-dev
- name: STAGE_PROJECT
value: user1-stage
- name: ENABLE_QUAY
value: 'true'
postCommit: {}
source:
type: None
triggers:
- type: GitHub
github:
secret: 3QY1TYdk
- type: Generic
generic:
secret: 3QY1TYdk
runPolicy: Serial
参考
http://redhatgov.io/workshops/secure_software_factory