(项目实战)如何结合k8s和pipeline的流水线(2),Java面试问题汇总

FROM 基础镜像地址
RUN mkdir xxxxx
COPY *.jar /usr/app/app.jar
ENTRYPOINT java -jar app.jar


**优化后的**

FROM 基础镜像地址


优化后的`Dockerfile`就这一行就完了。。。。。 下面简单介绍下这个`ONBUILD`
ONBUILD 可以这样理解,就比如我们这里使用的镜像,是基于 java 语言做的一个镜像,这个镜像有两部分,一个是包含 JDK 的基础镜像 A,另一个是包含 jar 包的镜像 B,关系是先有 A 再有 B,也就是说 B 依赖于 A。
假设一个完整的基于 Java 的 CICD 场景,我们需要拉代码,编译,打镜像,推镜像,更新 pod 这一系列的步骤,而在打镜像这个过程中,我们需要把编译后的产物 jar 包 COPY 到基础镜像中,这就造成了,我们还得写一个 Dockerfile,用来 COPY jar 包,就像下面这个样子:

FROM jdk基础镜像
COPY xxx.jar /usr/bin/app.jar
ENTRYPOINT java -jar app.jar


这样看起来也还好,基本上三行就解决了,但是能用一行就解决为什么要用三行呢?

FROM jdk基础镜像
ONBUILD COPY target/*.jar /usr/bin/app.jar
CMD ["/start.sh"]


打成一个镜像,比如镜像名是:`java-service:jdk1.8`,在打镜像的时候,`ONBUILD`后面的在本地打镜像的过程中不会执行,而是在下次引用时执行的

FROM java-service:jdk1.8


只需要这一行就可以了,并且这样看起来更加简洁,`pipeline`看起来也很规范,这样的话,我们每一个 java 的服务都可以使用这一行 Dockerfile 了。

### 使用凭据

有时候使用 docker 进行 push 镜像时需要进行认证,如果我们直接在 pipeline 里写的话不太安全,所以得进行脱敏,这样的话我们就需要用到凭据了,添加凭据也是非常简单,由于我们只是保存我们的用户名和密码,所以用`Username with password`类型的凭据就可以了,如下所示

![](https://upload-images.jianshu.io/upload_images/24195226-eea3c3c14759eb5c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


比如说:拉取 git 仓库的代码需要用到,然后这里就添加一个凭据,对应与 pipeline 里的下面这段内容:

stage(‘Pull server code’) {
steps {
script {
checkout(
[
c l a s s : ′ G i t S C M ′ , b r a n c h e s : [ [ n a m e : ′ class: 'GitSCM', branches: [[name: ' class:GitSCM,branches:[[name:{Branch}’]],
userRemoteConfigs: [[credentialsId: “ g i t a u t h " , u r l : " {git_auth}", url: " gitauth",url:"{git_addr}”]]
]
)
}
}
}


这里的变量`${git_auth}`就是添加凭据时设置的`ID`,如果不设置`ID`会随机生成一个`ID`

然后`docker push`时会需要进行认证,也需要添加凭据,添加方式和上面是一样的,不过我们可以用 pipeline 的语法来生成一个,方式如下: 点击`Pipeline Syntax`
![](https://upload-images.jianshu.io/upload_images/24195226-b3ee0fb35c0de2cc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


选择`withCredentials: Bind credentials to variables`

![](https://upload-images.jianshu.io/upload_images/24195226-1015d86880c18216.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


然后和之前添加的凭据进行绑定,这里选择类型为:`Username and password (separated)`

![](https://upload-images.jianshu.io/upload_images/24195226-1026125bac6382d4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


设置用户名和密码的变量名,然后选择刚才添加好的凭据

![](https://upload-images.jianshu.io/upload_images/24195226-57edcf8a3adf9d8d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


点击生成即可,就是上面 pipeline 里的下面这段:

withCredentials([usernamePassword(credentialsId: ‘faabc5e8-9587-4679-8c7e-54713ab5cd51’, passwordVariable: ‘img_pwd’, usernameVariable: ‘img_user’)]) {
sh “”"
docker login -u ${img_user} -p ${img_pwd} ${img_domain}
docker build -t i m g a d d r : {img_addr}: imgaddr:{date_time}_${git_cm_id} .
docker push ${whole_img_addr}
“”"
}


`credentialsId`: 这个 ID 就是随机生成的 ID

### 执行脚本进行更新镜像

这里是使用 python 写了一个小脚本,来调用 kubernetes 的接口做了一个`patch`的操作完成的。先来看下此脚本的目录结构

![](https://upload-images.jianshu.io/upload_images/24195226-f1014ae9bfc09673.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


核心代码:`deploy.py`
核心文件:`config.yaml` 存放的是 kubeconfig 文件,用于和 kubernetes 的认证

下面贴一下`deploy.py`的脚本内容,可以参考下:

import os
import argparse
from kubernetes import client, config

class deployServer:
def init(self, kubeconfig):
self.kubeconfig = kubeconfig
config.kube_config.load_kube_config(config_file=self.kubeconfig)
self._AppsV1Api = client.AppsV1Api()
self._CoreV1Api = client.CoreV1Api()
self._ExtensionsV1beta1Api = client.ExtensionsV1beta1Api()

def deploy_deploy(self, deploy_namespace, deploy_name, deploy_img=None, deploy_which=1):
    try:
        old_deploy = self._AppsV1Api.read_namespaced_deployment(
            name=deploy_name,
            namespace=deploy_namespace,
        )
        old_deploy_container = old_deploy.spec.template.spec.containers
        pod_num = len(old_deploy_container)
        if deploy_which == 1:
            pod_name = old_deploy_container[0].name
            old_img = old_deploy_container[0].image
            print("获取上一个版本的信息\n")
            print("当前Deployment有 {} 个pod, 为: {}\n".format(pod_num, pod_name))
            print("上一个版本的镜像地址为: {}\n".format(old_img))
            print("此次构建的镜像地址为: {}\n".format(deploy_img))
            print("正在替换当前服务的镜像地址....\n")
            old_deploy_container[deploy_which - 1].image = deploy_img
        else:
            print("只支持替换一个镜像地址")
            exit(-1)
        new_deploy = self._AppsV1Api.patch_namespaced_deployment(
            name=deploy_name,
            namespace=deploy_namespace,
            body=old_deploy
        )
        print("镜像地址已经替换完成\n")
        return new_deploy
    except Exception as e:
        print(e)

def run():
parser = argparse.ArgumentParser()
parser.add_argument(’-n’, ‘–name’, help=“构建的服务名”)
parser.add_argument(’-s’, ‘–namespace’, help=“要构建的服务所处在的命名空间”)
parser.add_argument(’-i’, ‘–img’, help=“此次构建的镜像地址”)
parser.add_argument(’-c’, ‘–cluster’,
help=“rancher中当前服务所处的集群名称”)
args = parser.parse_args()
if not os.path.exists(’…/config/’ + args.cluster):
print(“当前集群名未设置或名称不正确: {}”.format(args.cluster), ‘red’)
exit(-1)
else:
kubeconfig_file = ‘…/config/’ + args.cluster + ‘/’ + ‘config.yaml’
if os.path.exists(kubeconfig_file):
cli = deployServer(kubeconfig_file)
cli.deploy_deploy(
deploy_namespace=args.namespace,
deploy_name=args.name,
deploy_img=args.img
)
else:
print(“当前集群的kubeconfig不存在,请进行配置,位置为{}下的config.yaml.(注意: config.yaml名称写死,不需要改到)”.format(args.cluster),
‘red’)
exit(-1)

if name == ‘main’:
run()


写的比较简单,没有难懂的地方,关键的地方是:

new_deploy = self._AppsV1Api.patch_namespaced_deployment(
name=deploy_name,
namespace=deploy_namespace,
body=old_deploy
)


这一句是执行的 patch 操作,把替换好新的镜像地址的内容进行 patch。
然后就是执行就可以了。

### 其他

这里有一个需要注意的地方是`pipeline`里加了一个异常捕获,如下所示:

post {
success {
// 如果上面阶段执行成功,将把当前目录删掉
deleteDir()
}
}


生命式的 pipeline 和脚本式的 pipeline 的异常捕获的写法是有区别的,声明式写法是用的`post`来进行判断,比较简单,可以参考下官方文档
另外还有一个地方使用了并行执行,同时拉了服务的代码,和构建脚本的代码,这样可以提高执行整个流水线的速度,如下所示:

parallel {
stage(‘Pull server code’) {
steps {
script {
checkout(
[
c l a s s : ′ G i t S C M ′ , b r a n c h e s : [ [ n a m e : ′ class: 'GitSCM', branches: [[name: ' class:GitSCM,branches:[[name:{Branch}’]],
userRemoteConfigs: [[credentialsId: “ g i t a u t h " , u r l : " {git_auth}", url: " gitauth",url:"{git_addr}”]]
]
)
}
}
}
stage(‘Pull ops code’) {
steps {
script {
checkout(
[
$class: ‘GitSCM’,
branches: [[name: ‘pipeline-0.0.1’]], //拉取的构建脚本的分支

最后总结

搞定算法,面试字节再不怕,有需要文章中分享的这些二叉树、链表、字符串、栈和队列等等各大面试高频知识点及解析,以及算法刷题LeetCode中文版的小伙伴们可以点赞后点击这里即可免费获取!

最后再分享一份终极手撕架构的大礼包(学习笔记):分布式+微服务+开源框架+性能优化

image

本的分支

最后总结

搞定算法,面试字节再不怕,有需要文章中分享的这些二叉树、链表、字符串、栈和队列等等各大面试高频知识点及解析,以及算法刷题LeetCode中文版的小伙伴们可以点赞后点击这里即可免费获取!

最后再分享一份终极手撕架构的大礼包(学习笔记):分布式+微服务+开源框架+性能优化

[外链图片转存中…(img-h89DByCG-1628661937191)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值