devops

k8s中的command和docker的entrypoint区别

Docker Entrypoint & Cmd
先回顾下CMD指令的含义,CMD指令可以指定容器启动时要执行的命令,但它可以被docker run命令的参数覆盖掉。

ENTRYPOINT 指令和CMD类似,它也可用户指定容器启动时要执行的命令,但如果dockerfile中也有CMD指令,CMD中的参数会被附加到ENTRYPOINT 指令的后面。 如果这时docker run命令带了参数,这个参数会覆盖掉CMD指令的参数,并也会附加到ENTRYPOINT 指令的后面。这样当容器启动后,会执行ENTRYPOINT 指令的参数部分。

可以看出,相对来说ENTRYPOINT指令优先级更高。我们来看个例子,下面是Dockerfile的内容:

### test
FROM ubuntu
MAINTAINER hello
RUN echo hello1 > test1.txt
RUN echo hello2 > /test2.txt
EXPOSE 80
ENTRYPOINT [“echo”]
CMD [“defaultvalue”]

假设通过该Dockerfile构建的镜像名为 myimage。

当运行 docker run myimage 输出的内容是 defaultvalue,可以看出CMD指令的参数得确是被添加到ENTRYPOINT指令的后面,然后被执行。
当运行docker run myimage hello world 输出的内容是 hello world ,可以看出docker run命令的参数得确是被添加到ENTRYPOINT指令的后面,然后被执行,这时CMD指令被覆盖了。
另外我们可以在docker run命令中通过 –entrypoint 覆盖dockerfile文件中的ENTRYPOINT设置,如:
docker run –entrypoint=”echo” myimage good 结果输出good
注意,不管是哪种方式,创建容器后,通过 docker ps –no-trunc查看容器信息时,COMMAND列会显示最终生效的启动命令。

此外,很多的数据库软件的docker镜像,一般在entrypoint的位置会设置一个docker-entrypoint.sh文件,此文件位于/usr/local/bin位置,用于在容器初次启动的时候进行数据库的初始化操作。
Kubernetes Command & args
下表总结了Docker和Kubernetes使用的字段名称:

当你覆盖默认的Entrypoint和Cmd时,将应用以下规则:

如果不为容器提供command或args参数,则使用Docker镜像中定义的默认值。
如果提供command但没有提供args参数,则仅使用提供的command。Docker镜像中定义的默认EntryPoint和默认Cmd将被忽略。
如果仅为容器提供args,则Docker镜像中定义的默认Entrypoint将与您提供的args一起运行。
如果提供command和args,则将忽略Docker镜像中定义的默认Entrypoint和默认Cmd。 您的command与 args一起运行。
可以看到,k8s利用了Dockerfile的覆盖机制,使用command和args参数有选择性的覆盖了Docker镜像中的Entrypoint和Cmd启动参数,下面是一些例子:

 

使用command和args的例子:

apiVersion: v1
kind: Pod
metadata:
name: command-demo
labels:
purpose: demonstrate-command
spec:
containers:
– name: command-demo-container
image: debian
command: [“printenv”]
args: [“HOSTNAME”, “KUBERNETES_PORT”]
restartPolicy: OnFailure
参考资料:
https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/

Docker 时区问题

一、问题描述
遇到docker时间不一致,大多是因为默认时区没有设置导致,一般在宿主机上使用 date 命令看到的是 CTS 时间,进入docker后使用 date 命令查看的是 UTC 时间。
CTS: China Standard Time,UTC+8:00 中国沿海时间(北京时间)
UTC: Universal Time Coordinated 世界协调时间

所以我们需要修改 docker 容器的时区,针对不同场景修改的方式也不一样,大家可以参考一下选择最适合自己的修改方式

二、修改 Dockerfile 文件方式更改时区
适用场景:如果我们是用 Dockerfile 方式构建的镜像,那么我们可以修改 Dockerfile 让构建的镜像直接为东八区

在 Dockerfile 文件中 添加

ENV TZ=Asia/Shanghai

重新构建镜像,查看时间,发现已经是东八区,成功。

三、新增 run 参数更改时区
适用场景:不想重新构建镜像,删除容器重新部署对程序本身没有影响

删除 容器

docker rm -f tomcat
run 的时候加上参数

-e TZ=”Asia/Shanghai”
例如

docker run -e TZ=”Asia/Shanghai” -p 8090:8090 -d –name ch ch/ch
-e 时区改为东八区,默认时区为0区

-p 暴露端口 前面的端口(docker tomcat 容器端口) 后面的端口(宿主机器端口,我们要在浏览器访问的端口)

-d 后台运行(不会在控制台输出日志)

完成后 查看时间,已经是东八区,成功

四、修改 tomcat 配置文件更改时区
适用场景:tomcat 容器运行的程序,不想重新构建镜像容器

注意:交付的Docker映像已修剪到最低限度-因此,拉取的容器未安装任何编辑器,所以无法 进入到容器编辑配置文件。

所以得将配置文件 copy 一份到本地

docker cp tomcat:/usr/local/tomcat/bin/catalina.sh .

修改 catalina.sh 配置文件

找到 JAVA_OPTS=”$JAVA_OPTS -Djava.protocol.handler.pkgs=org.apache.catalina.webresources” 这一行 行尾添加 Duser.timezone=GMT+08

JAVA_OPTS=”$JAVA_OPTS -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Duser.timezone=GMT+08″
然后将修改后的配置文件,覆盖掉容器内的

docker cp .\catalina.sh tomcat:/usr/local/tomcat/bin/catalina.sh
最后重启容器

docker restart tomcat
发现时区已经改为 东八区 ,成功。
————————————————
版权声明:本文为CSDN博主「码农农码一生」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/chenhao_c_h/article/details/110041401

jenkins BlueOcean修复Pipeline不支持中文的问题

问题

在Jenkins的BlueOcean中,修改Pipeline,结果发现,如果编写过程中,凡是能导致jenkinsFile有中文信息的,点击 save and run之后 Console 中出现错误,无法保存。

分析

根据错误信息,定位到问题来源jenkins-js-extension.js,该问题和 js的btoa和atob 不支持unicode有关。

解决

  1. 将jenkins的./webapps/plugins/blueocean-pipeline-editor/WEB-INF/lib/blueocean-pipeline-editor.jar下载到本地,
  2. 解压出jenkins-js-extension.js,搜索btoa,有两处一样的代码,搜索atob也是一样的,成对出现。
  3. 修改代码,将两处encode和decode修改为以下结果:
  4. 将修改之后的jenkins-js-extension.js拖入blueocean-pipeline-editor.jar。
  5. 将修改之后的blueocean-pipeline-editor.jar上传到Jenkins的原处:./webapps/plugins/blueocean-pipeline-editor/WEB-INF/lib/blueocean-pipeline-editor.jar
var Base64 = {
    encode: function encode(data) {
        return btoa(unescape(encodeURIComponent(data)));
    },
    decode: function decode(str) {
        return decodeURIComponent(escape(atob(str)));
    }
};

An error occurred during installation: No such plugin: cloudbees-folder

在启动jenkins时候报错

An error occurred during installation: No such plugin: cloudbees-folder
1
字面意思是没有找到cloudbees-folder这个插件。有一些文章说下载这个插件到本地就好了。

然而jenkins启动的时候不仅仅有这一个插件。

https://github.com/jenkinsci/docker/issues/424 github issues里有一些讨论。似乎重启jenkins就可以了

# 访问这个地址就是重启
http://yourhost:8080/restart
1
2
然后我这里看来并不管用。

最后无意中发现我拉取的镜像是jenkins…并非jenkins/jenkins。我用的是docker…

当尝试拉取后者并启动之后,就没有这个报错了。

k8s创建Deployment报错:no matches for kind “Deployment“ in version “extensions/v1beta1“

报错类型:

[root@master ~]# kubectl create -f lzb-test.yaml
error: unable to recognize “lzb-test.yaml”: no matches for kind “Deployment” in version “extensions/v1beta1”
解决:

修改yaml文件:


apiVersion: extensions/v1beta1
kind: Deployment
metadata:
修改如下:


apiVersion: apps/v1
kind: Deployment
这个主要是由于版本升级的原因

我的 k8s 版本是 1.18.5

在这个版本中 Deployment 已经启用extensions/v1beta1

DaemonSet, Deployment, StatefulSet, and ReplicaSet resources will no longer be served from extensions/v1beta1, apps/v1beta1, or apps/v1beta2 by default in v1.16.

【ChatOps系列】ChatOps简介

要说 ChatOps 就不得不说 DevOps,DevOps 是来源于 Development 和 Operations 的一个组合词,顾名思义,是一系列过程、方法与系统的统称,旨在促进开发、测试和运维人员之间的沟通与协作。简单来说,是通过引入一系列的「工具」,通过三种不同角色的开发成员间的「协作」而实现的一种「自动化」的工作模式。这种工作方式带来的好处显而易见:

  • 实现持续快速交付
  • 能够降低人力成本

但很大程度上,DevOps 更多是指开发群体之间的一种协作模式(通常也在开发人员中实施),随着全行业的发展和人力成本的攀升,在团队所有角色间贯通的升级版「DevOps」逐渐登场,也就是我们将要重点介绍的 ChatOps。

devops

ChatOps介绍

ChatOps 的历史相对短暂,2013 年 GitHub 内部最早开始推行 ChatOps,希望能以聊天的方式更容易更快速的去完成 DevOps 承载的工作。

ChatOps 以聊天室,即沟通平台为中心,通过一系列的机器人去对接后台的各种服务,工作人员只需要在聊天窗口中与机器人对话,即可与后台服务进行交互,整个工作的展开就像是使唤一个智能助手那样简单自然。

chatops_devops

ChatOps 站在巨人的肩膀上发展,也为工作带来了显而易见的好处:

  • 公开透明。所有的工作消息都在同一个聊天平台中沉淀并公开给所有相关成员,消除沟通壁垒,工作历史有迹可循,团队合作更加顺畅。
  • 上下文共享。减少因工作台切换等对消息的截断,保证消息的完整性,让工作承接有序,各角色,各工具都成为完成工作流中的一环,打造真正流畅的工作体验。
  • 移动友好。只需要在前台与预设好的机器人对话即可完成与后台工具、系统的交互,在移动环境下无需再与众多复杂的工具直接对接,大大提升移动办公的可行性。
  • DevOps 文化打造。用与机器人对话这种简单的方式降低 DevOps 的接受门槛,让这种自动化办公的理念更容易的扩展到团队的每一个角落。

chatops

ChatOps 主要由三个部分构成:聊天室(控制中心)、机器人(连接中心)、基础设施,基础设施主要是支撑我们业务运行的各种服务与工具,在构建 ChatOps 时主要需要选择聊天室和机器人,国外早期的工作沟通工具 HipChat,新秀 Slack 都是作为 ChatOps 承载平台的好选择,在中文的环境下,则可以选择 BearyChat(倍洽)等等。

聊天室选择:

  • 功能完备
  • 操作交互友好
  • 多平台支持
  • API 丰富
  • 三方工具支持丰富
  • 机器人支持程度

机器人选择:

  • 功能完备
  • 易扩展(我们可能需要根据基础设施编写大量机器人扩展)
  • 编程语言熟悉(因为我们需要编写扩展)
  • 开源扩展丰富(可以极大减少开发工作量)

聊天室主要有:Slack、HipChat、BearyChat(倍洽)、Rocket.Chat、钉钉(机器人支持程度不够,不太支持)。机器人主要有:Hubot(javascript/CoffeeScript)、Lita(Ruby),Errbot(python)。

机器人我推荐使用 Hubot,后面所有的实验都使用 Hubot 展开。 GitHub 团队内部实现的 ChatOps 与一个叫做 Hubot 的机器人框架密切相关,Hubot 提供很多聊天机器人所需的基础设施,借助 Hubot 框架能比较方便的和自己编写的功能或自己的系统对接。目前,Hubot 已经发展出了较好的生态圈,有很多开源插件可以借用。

chatops

ChatOps实现

本系列专题主要讲两种实现,一种是基于 GitHub+Hubot+Slack 实现,一种基于开源体系的 GitLab + Hubot + Rocket.Chat,它们功能完善且有良好的扩展及丰富的API,只要爱倒腾一定会有意想不到的收获。

GitHub 体系:

  • slack 聊天室
  • Hubot 机器人
  • GitHub 代码管理
  • Travis CI 自动化测试
  • heaven 自动部署
  • hubot-deploy 连接 Hubot 与 heaven

GitLab 体系:

  • Recket.chat 聊天室
  • Hubot 机器人
  • GitLab 代码管理
  • GitLab CI 自动化测试
  • hubot-gitlab-deploy 自动化部署(计划重构中)
  • fabric-deploy-script 基于配置的 fabric 自动部署实现 (计划开源中)

本系列会介绍各种设计服务安装、配置,以及各种服务组件之间连接配置等,同时会涉及到项目配置管理、密钥管理等相关知识。

计划

本系列主要涉及 ChatOps 环境搭建、工具配置,以及项目的持续集成、持续部署的实现,持续部署过程会涉及到密钥管理、配置管理等等。

本系列计划一至两周一篇文章,每篇文章介绍一个点,两种体系都会讲到,大约20~30篇文章,优先讲解开源体系的 GitLab 篇。

在这期间会开发相关机器人脚本及相关服务组件,可以形成项目会发布在 GitHub 上,不能形成项目的会在文章中,最后所有实验相关代码均可在 GitHub 上 chatops_experiment 中获取。

测试中需要自动部署的项目会单独存储在一个账号/组织下面,具体详见每个章节。

salt-api使用

启用salt-api 服务

这里简单的说明下,SaltStack官方支持三种REST API,分别是rest_cherry; rest_tonado和rest_wsgi, 本文选择使用rest_cherry模块来实现SaltStack的HTTP API。

配置salt-API服务

yum -y install salt-api
useradd -M -s /sbin/nologin saltapi
echo "saltapi" | passwd saltapi --stdin
vim /etc/salt/master
external_auth:
  pam:
    saltapi:
      - .*
      - '@wheel'
      - '@runner'

rest_cherrypy:
  port: 8000
  disable_ssl: Ture
  
  systemctl restart salt-master 
  systemctl restart salt-api 

使用CURL测试salt-API接口

第一步登录获得token,后续的命令使用token直接执行。

curl  -sk http://192.168.56.11:8000/login -H 'Accept: application/x-yaml' -d username='saltapi' -d password='saltapi' -d eauth='pam'

return:
- eauth: pam
  expire: 1522883646.381435
  perms:
  - .*
  - '@wheel'
  - '@runner'
  start: 1522840446.381431
  token: 86e323effd30bed7b2cdbcf4e70744048bbc25ca
  user: saltapi

第二步执行如下命令:salt 'linux-node2' test.ping

curl -sk http://192.168.56.11:8000/ -H 'Accept: application/json' -H 'X-Auth-Token: 86e323effd30bed7b2cdbcf4e70744048bbc25ca' -d client='local' -d tgt='linux-node2' -d fun='test.ping'  | python -mjson.tool  
{
    "return": [
        {
            "linux-node2": true
        }
    ]
}

执行带参数的命令:salt 'linux-node2' cmd.run 'free -m'

curl -sk http://192.168.56.11:8000/ -H 'Accept: application/json' -H 'X-Auth-Token: 86e323effd30bed7b2cdbcf4e70744048bbc25ca' -d client='local' -d tgt='linux-node2' -d fun='cmd.run' -d arg='whoami' | python -mjson.tool
{
    "return": [
        {
            "linux-node2": "root"
        }
    ]
}

salt API /run 接口

运行绕过正常会话处理的命令除此之外,该URL与根URL(/)相同。

curl -sk http://192.168.56.11:8000/run \
    -H 'Accept: application/x-yaml' \
    -H 'Content-type: application/json' \
    -d '[{
        "client": "local",
        "tgt": "linux-node2",
        "fun": "test.ping",
        "username": "saltapi",
        "password": "saltapi",
        "eauth": "pam"
    }]' 
return:
- linux-node2: true

使用python 实现如下命令

salt 'linux-node2' cmd.run 'free -m'
import requests

url='http://192.168.56.11:8000/login'
username = 'saltapi'
password = 'saltapi'

data = {'username': username,'password': password,'eauth': 'pam'}
headers = {'Accept': 'application/json','Content-Type': 'application/x-www-form-urlencoded'}
login_req = requests.post(url=url, headers=headers, data=data)
js = login_req.json()
token = js['return'][0].get('token')
print(token)


cmd_headers = {'Accept': 'application/json','Content-type': 'application/x-www-form-urlencoded', 'X-Auth-Token': token}
cmd_data = {'client': 'local', 'tgt': 'linux-node2', 'fun': 'cmd.run', 'arg': 'free -m '}
urls = 'http://192.168.56.11:8000'
req = requests.post(urls,headers=cmd_headers,data=cmd_data)
print(req.status_code)

if req.status_code == 200:
	print(req.json())

执行结果如下:

ab5d9ea0f428367c79f8eaf3dc62d39b1c45b4c9
200
{'return': [{'linux-node2': '              total        used        free      shared  buff/cache   available\nMem:            979         607          76          49         295         172\nSwap:             0           0           0'}]}

使用python编写过程中遇到的问题:

  • curl 请求时,默认会增加Content-type': 'application/x-www-form-urlencoded 的头部,所以在request请求头中也需要加入。

Jenkins教程 安装BlueOcean与Maven构建

前言

本文旨在使用BlueOcean实现构建可视化与使用Maven构建上一节Jenkins教程(三)添加凭据与流水线拉取Git代码拉下来的代码

什么是Blue Ocean

Blue Ocean 重新思考Jenkins的用户体验,从头开始设计Jenkins Pipeline, 但仍然与自由式作业兼容,Blue Ocean减少了混乱而且进一步明确了团队中每个成员 Blue Ocean 的主要特性包括:

  • 持续交付(CD)Pipeline的 复杂可视化 ,可以让您快速直观地理解管道状态。
  • Pipeline 编辑器 – 引导用户通过直观的、可视化的过程来创建Pipeline,从而使Pipeline的创建变得平易近人。
  • 个性化 以适应团队中每个成员不同角色的需求。
  • 在需要干预和/或出现问题时 精确定位 。 Blue Ocean 展示 Pipeline中需要关注的地方, 简化异常处理,提高生产力
  • 本地集成分支和合并请求, 在与GitHub 和 Bitbucket中的其他人协作编码时实现最大程度的开发人员生产力。

简言之:简化复杂可视化,提供更个性直观的界面,可以精准定位构建失败的位置

安装Blue Ocean

  • 准备条件:是管理员用户,或拥有安装插件的权限

Manage Jenkins > Manage Plugins

过滤输入Blue Ocean> 勾选第一个Blue Ocean > 直接安装 > 安装完成返回首页

这里提示有很多Blue Ocean的插件,我们是无需手动安装的,通过安装Blue Ocean会自动安装官方推荐的其它组件

此时我们可以使用 <host>:<port>/blue进行访问到Blue Ocean的页面

这里先不讲,配置好Maven后,我们再来使用它来构建一次

使用Maven构建工具

这里使用docker的maven镜像来进行构建工程,以减少多个构建工程使用同一构建工具时的冲突问题

另一方面是演示下agent的使用😆

准备条件:

  • 安装Docker
  • 添加Jenkins到Docker用户组sudo usermod -aG docker jenkins && newgrp docker
  • 重启Jenkins

创建自定义maven的配置文件/home/jenkins/mvnrepo/settings.xml,使用了阿里的镜像源,本地仓库这个不用改,这里会被容器映射到容器内/root/.m2

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      https://maven.apache.org/xsd/settings-1.0.0.xsd">
  <mirrors>
    <mirror>
        <id>nexus-aliyun</id>
        <mirrorOf>*</mirrorOf>
        <name>Nexus aliyun</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </mirror>
  </mirrors>
</settings>

在Github的仓库中我创建了chapter2分支,里面的Jenkinsfile如下

pipeline {
    agent { //这里使用docker镜像来启动maven,这样有个好处就是多个工程同时构建时不会出现冲突而失败
        docker {
            image 'maven:3.6-alpine' 
            args '-u root -v /home/jenkins/mvnrepo:/root/.m2'  //持载到本地,减少重复下载量,使用ali源
        }
    }
    stages {
        stage('Pull Git Demo') {
            steps{
                //拉取代码
            	git 'https://github.com/hellxz/springboot-demo1.git'
            }
        }
        stage('Build') { 
            steps {
                //执行构建命令
                sh 'mvn -B -DskipTests clean package' 
            }
        }
    }
}

持载的那个位置下的settings.xml会被maven容器使用,从而修改镜像源,另外在settings.xml中指不指定本地仓库都没区别,亲测

创建流水线

指定Jenkinsfile所在的版本控制与分支,这里我使用的是https://github.com/hellxz/JenkinsfileTutorials.git

分支是chapter2,检出到chapter2目录下,Jenkinsfile直接就在仓库的根目录内

启动测试

输入http://<host>:<port>/blue, 点击刚才创建的maven build demo项目

点击运行

构建成功,我们查看Build步骤,可以看到构建成功了

由于在公司里我使用的是本地配置的maven,所以查hub.docker.com,对Jenkinsfile中使用maven镜像的部分修改了几次,不然你会看到拉取的jar包都是从阿里源中拉出来的

查看构建目录

本文结束

后记

被maven-docker的文档小坑了一下,文档中提到的自定义settings.xml文件是持载到另一个目录下

还有就是maven容器内使用的用户是非root用户,如果按官方文档中不加-u root,那么容器内的/root/.m2目录是持载不出来的!

当前我们的构建属于脏构建,即上次的构建结果与代码拉取结果都在同一个工作目录中,这样是需要修改的,现在为了简单演示没有添加,可以在拉代码前加一个清理空间的步骤,使用cleanWs()命令

下篇准备写把微服务项目打成Docker镜像,静请期待

引文

saltstack中如何实现多个master来管理minion

背景:

公司有多个部门,有一些机器有本部门的业务,这些机器也有其他部门的业务,所以本部门需要一个master服务器来管理这批机器,其他部门也需要一个master服务器来管理这个机器,所以就需要多个master来进行管理。

实现:

实现方式就是所有的master服务器使用相同的private key,即我们只需要将其中一台已经配置好的master上的private key进行复制,然后拷贝到另一台master服务器上即可,然后在minion端配置好minion id即可,配置完成后需要重启下服务。

示例:

准备了三台机器

机器列表 状态
192.168.235.133 master1
192.168.235.134 minion
192.168.235.135 master2

1)将master2上的private key进行拷贝至master1上

复制代码
[root@localhost master]# ll
总用量 8
-r--------. 1 root root 1679 1月   2 21:19 master.pem    #private key
-rw-r--r--. 1 root root  451 1月   2 21:19 master.pub
drwxr-xr-x. 2 root root   15 1月   2 21:20 minions
drwxr-xr-x. 2 root root    6 1月   2 21:19 minions_autosign
drwxr-xr-x. 2 root root    6 1月   2 21:19 minions_denied
drwxr-xr-x. 2 root root    6 1月   2 21:20 minions_pre
drwxr-xr-x. 2 root root    6 1月   2 21:19 minions_rejected

 private key 所在目录:/etc/salt/pki/master

2)修改minion端的配置文件

 

书写格式一定要写对

3)然后在master1上进行密钥认证

[root@localhost master]# salt-key -L
Accepted Keys:
Denied Keys:
Unaccepted Keys:
m1
Rejected Keys:
[root@localhost master]# salt-key -A
The following keys are going to be accepted:
Unaccepted Keys:
m1
Proceed? [n/Y] Y
Key for minion m1 accepted.

4)重启服务,测试即可

需要注意的是:另一个master不能有其他节点服务器连接

以上操作便实现了多个master共同管理minion节点的需求了