cat和EOF的组合妙用

有时候,我们可能会使用脚本去生成一个临时文件,然后把该文件作为*终文件放入目录中。这样有几个好处,其中之一就是临时文件不是唯一的,可以通过变量赋值,也可根据不同的判断生成不同的*终文件等等。

1. cat和EOF简介
cat:该文本输出命令用于显示文本的全部内容,并全部打印输出

EOF:文本结束符,即“end of file”,表示文件内容的结束

在shell脚本中将cat与EOF组合使用,可避免使用多行echo ‘xxx’打印命令方式,并实现多行文本输出的结果。常见的使用方式有以下几种:

cat >FileName <<EOF:新建文件并多行导入文件内容,结尾以EOF输入字符为标准输入结束;“<”是重定向,会将你输入的内容输入到目标文本中。
cat <<EOF >FileName,文件追加,实现多行文本的输出,cat的多行内容有$等特殊字符时,须利用转义字符\,其结尾以EOF作为输入结束,可以对已有文件内容进行编辑修改;
cat >FileName :可以对 file 文件内容进行编辑,一旦 file 文件存在,则 file 原来的数据被新输入数据覆盖,并且在输入的时候,光标前方没有 > 提示符(cat > file << EOF 是有的),*后,标记输入文件完成的方式也只有使用 Ctrl + C 或者 Ctrl + D
2. 说明
新建文件,并导入多行文件(新建文件或覆盖文件内容)
这里写一个A.sh脚本如下:

#!/bin/bash

cat > kube.txt <<EOF
OPTS=”–logtostderr=false\
–v=4 \”
EOF

执行#sh A.sh脚本,再cat一下看执行结果:

OPTS=”–logtostderr=false –v=4″

这里,我们修改一下脚本内容,将里边的参数–logtostderr=false,–v=0,再试一下呢:

#!/bin/bash

cat > kube.txt <<EOF
OPTS=”–logtostderr=true\
–v=0 \”
EOF

再cat一下查看下执行结果:

OPTS=”–logtostderr=true –v=0″

这里,可以看到我们cat > FileName <<EOF 可以对 file 文件内容进行编辑,一旦 file 文件存在,则 file 原来的数据被新输入数据覆盖

当然,不通过脚本,我们在终端去手动敲:

# cat > kube-scheduler << EOF
> #文本内容
> EOF

如果使用echo打印输出,则繁琐,必须这样去写:echo -e   “#!/bin/sh \n #文本内容” > kube-scgeduler。-e表示escape。

追加文件方式

cat << EOF > kube.js,内容和上边的雷同

[root@master01 scripts]# cat << EOF > kube.js
> OPTS=”–logtostderr=false\
> –v=4 \”
> EOF

查看一下:

[root@master01 scripts]# cat kube.js
OPTS=”–logtostderr=false–v=4 \”
这时已存在kube.js文件了,我们重新再输入不同内容试一下:

[root@master01 scripts]# cat << EOF > kube.js
> OPTS=”–logtostderr=true\
> –v=0 \”
> EOF

查看一下:

[root@master01 scripts]# cat kube.js
OPTS=”–logtostderr=true –v=0 \”

可以看到,我们以文件追加方式,实现多行文本的输出,cat的多行内容有$等特殊字符时,须利用转义字符\,其结尾以EOF作为输入结束,可以对已有文件内容进行编辑修改。

此时,再思考 cat > file 和 << EOF组合或者 cta << EOF >file组合在一起的行为就不是那么难了。其中 cat > file 负责创建 file 文件,并提示用户输入文件内容,<< EOF 负责显示提示符 >,并且以 EOF 判定文件内容输入结束。

如何将云原生工作负载映射到 Kubernetes 中的控制器

Kubernetes 不仅仅是一个容器管理工具。它是一个平台,旨在处理包装在任意数量的容器和组合中的各种工作负载。Kubernetes内置了多个控制器,可映射到云原生架构的各个层。

DevOps工程师可以将Kubernetes控制器视为指示团队运行的各种工作负载的基础架构需求的手段。他们可以通过声明方法定义所需的配置状态。例如,容器/pod作为ReplicationController的一部分部署保证始终可用。打包为DaemonSet的容器保证在集群的每个节点上运行。声明式的方法使DevOps团队能够利用代码控制基础架构。下面讨论的一些部署模式遵循不可变基础结构的原则,其中每个新的部署都会导致原子部署。

DevOps工程师可以通过声明方法定义所需的配置状态——每个工作负载映射到控制器。

了解云原生用例

Kubernetes的控制平面不断跟踪部署,以确保它们符合DevOps定义的所需配置状态。

Kubernetes的基本部署单位是一个pod。它是Kubernetes的基本构建块,是Kubernetes对象模型中*小和*简单的单元。pod表示集群上正在运行的进程。无论服务是有状态的还是无状态的,它总是打包并部署为pod。

控制器可以在集群中创建和管理多个pod,处理在集群范围内提供自我修复功能的副本。例如,如果节点发生故障,控制器可能会通过在不同节点上安排相同的pod用来自动替换该故障pod。

Kubernetes配有多个控制器,可以处理所需的pod状态。如ReplicationController、Deployment、DaemonSet和StatefulSet控制器。Kubernetes控制器使用提供的pod模板,来创建其负责pod的所需状态。与其他Kubernetes对象一样,Pod在YAML文件中定义并提交给控制平面。

在Kubernetes中运行云原生应用程序时,运维人员需要了解控制器解决的用例,以充分利用平台的特性。这有助于他们定义和维护应用程序的所需配置状态。

上一节中介绍的每种模式都映射到特定的Kubernetes控制器,这些控制器允许对Kubernetes的工作负载进行更精确,细粒度的控制,但是采用自动化方式。

Kubernetes的声明式配置鼓励不可变的基础架构。控制平面跟踪和管理部署,以确保在整个应用程序生命周期中维护所需的配置状态。与基于虚拟机的传统部署相比,DevOps工程师将花费更少的时间来维护工作负载。利用Kubernetes原语和部署模式的有效CI/CD策略使运营商无需执行繁琐的任务。

可扩展层:无状态工作负载

无状态工作负载在Kubernetes中打包并部署为ReplicaSet。ReplicationController构成ReplicaSet的基础,可确保在任何给定时间始终运行指定数量的pod副本。换句话说,ReplicationController确保一个pod或一组同类pod总是可用。

如果有太多pod,ReplicationController可能会终止额外的pod。如果太少,ReplicationController将继续启动其他pod。与手动创建的pod不同,ReplicationController维护的pod在失败,删除或终止时会自动替换。在诸如内核升级之类的破坏性维护之后,在节点上重新创建pod。因此,即使应用程序只需要一个pod,也建议使用ReplicationController。

一个简单的用例是创建一个ReplicationController对象,以无限期地可靠地运行pod的一个实例。更复杂的用例是运行横向扩展服务的几个相同副本,例如Web服务器。在Kubernetes中部署时,DevOps团队和运营商将无状态工作负载打包为ReplicationControllers。

在*近的Kubernetes版本中,ReplicaSets取代了ReplicationControllers。它们都针对相同的场景,但ReplicaSet使用基于 集合的标签选择器 ,这使得可以使用基于注释的复杂查询。此外,Kubernetes中的部署依赖于ReplicaSet。

Deployment是ReplicaSet的抽象。在Deployment对象中声明所需状态时,Deployment控制器会以受控速率将实际状态更改为所需状态。

强烈建议部署管理云原生应用程序的无状态服务。虽然服务可以部署为pod和ReplicaSet,但部署可以更轻松地升级和修补应用程序。DevOps团队可以使用部署来升级pod,而无法使用ReplicaSet完成。这样就可以在*短的停机时间内推出新版本的应用程序。部署为应用程序管理带来了类似于服务(PaaS)的功能。

持久层:有状态的工作量

状态工作负载可以分为两类:需要持久存储的服务(单实例)和需要以高可靠性和可用模式运行的服务(复制的多实例)。需要访问持久存储后端的pod与为关系数据库运行集群的一组pod非常不同。虽然前者需要长期持久的持久性,但后者需要高可用性的工作量。Kubernetes解决了这两种情况。

可以通过将底层存储暴露给服务的卷来支持单个pod。可以将卷映射到调度pod的任意节点。如果在集群的不同节点上调度多个pod并需要共享后端,则在部署应用程序之前手动配置分布式文件系统(如网络文件系统(NFS)或Gluster)。云原生态系统中提供的现代存储驱动程序提供容器本机存储,其中文件系统本身通过容器公开。当pod只需要持久性和持久性时,请使用此配置。

对于预计具有高可用性的场景,Kubernetes提供StatefulSets – 一组专门的pod,可确保pod的排序和唯一性。这在运行主要/辅助(以前称为主/从)数据库集群配置时尤其有用。

与部署类似,StatefulSet管理基于相同容器规范的pod。与Deployment不同,StatefulSet为其每个pod保留唯一标识。这些pod是根据相同的规范创建的,但不可互换:每个pod都有一个持久标识符,它可以在任何重新安排时保留。

StatefulSet对需要以下一项或多项的工作负载非常有用:

  • 稳定,独特的网络标识符。
  • 稳定,持久的存储。
  • 有序,优雅的部署和扩展。
  • 有序,优雅的删除和终止。
  • 有序的自动滚动更新。

Kubernetes对StatefulSets的处理方式与其他控制器不同。当正在使用N个副本调度StatefulSet的pod时,将按顺序创建它们,顺序从0到N-1。当删除StatefulSet的pod时,它们以相反的顺序终止,从N-1到0。在将一个扩展操作应用于pod之前,它的所有前驱必须正在运行并准备就绪。Kubernetes确保在终止pod之前,其所有后继者都完全关闭。

当服务需要运行Cassandra、MongoDB、MySQL、PostgreSQL集群或任何具有高可用性要求的数据库工作负载时,建议使用StatefulSet。

并非每个持久性工作负载都必须是StatefulSet。某些容器依赖于持久存储后端来存储数据。为了向这些类型的应用程序添加持久性,pod可能依赖于由基于主机的存储或容器本机存储后端支持的卷。

可并行化层:批处理

Kubernetes具有用于批处理的内置原语,这对于执行运行到完成作业或预定作业很有用。

运行到完成作业通常用于运行需要执行操作和退出的进程。在处理数据之前运行的大数据工作负载就是这种工作的一个例子。另一个示例是一个处理队列中每条消息的作业,直到队列变空。

作业是一个控制器,可以创建一个或多个pod并确保指定数量的pod成功终止。当pod成功完成后,Job会跟踪成功的完成情况。达到指定数量的成功完成后,作业本身就完成了。删除作业将清理它创建的pod。

Job还可以用于并行运行多个pod,这使其成为机器学习培训工作的理想选择。Job还支持并行处理一组独立但相关的工作项。

当Kubernetes在具有GPU的硬件上运行时,机器学习培训可以利用Job。诸如Kubeflow之类的新兴项目 – 一个致力于在Kubernetes上部署机器学习的简单,可移植和可扩展的项目 – 将把原始资料作为job包装到机器学习培训中。

除了运行并行化作业外,可能还需要运行预定作业。Kubernetes公开了CronJobs,它可以在指定的时间点运行一次,也可以在指定的时间点定期运行。Kubernetes中的CronJob对象类似于Unix中crontab(cron表)文件的一行。它以给定的时间表定期运行,以cron格式编写。

Cron作业对于安排定期作业(如数据库备份或发送电子邮件)特别有用。

事件驱动层:无服务器(Serverless)

无服务器计算(Serverless)是指构建和运行不需要服务器管理的应用程序的概念。它描述了一种更细粒度的部署模型,其中捆绑为一个或多个功能的应用程序上传到平台,然后执行,缩容和计费以响应当前所需的确切需求。

函数即服务(FaaS)在无服务器计算的环境中运行,以提供事件驱动的计算。开发人员使用由事件或HTTP请求触发的功能来运行和管理应用程序代码。开发人员将小型代码单元部署到FaaS,这些代码根据实际需要作为独立组件执行,无需管理服务器或任何其他底层基础架构即可进行扩展。

虽然Kubernetes没有集成的事件驱动原语来响应其他服务引发的警报和事件,但仍有努力引入事件驱动的功能。该云原生计算基金会 ,Kubernetes的托管者,一直专注于这些致力于无服务器的工作组。Apache OpenWhisk 、Fission 、Kubeless 、OpenFaaS 和 Oracle的Fn 等开源项目可以在Kubernetes集群中作为事件驱动的无服务器层运行。

在无服务器环境中部署的代码与打包为pod的代码根本不同。它由自治函数组成,可以连接到可能触发代码的一个或多个事件。

当事件驱动计算——无服务器计算成为Kubernetes不可或缺的一部分时,开发人员将能够部署响应Kubernetes控制平面生成的内部事件以及应用程序服务引发的自定义事件的函数。

遗留层:Headless Service

即使您的组织经常使用微服务架构构建和部署应用程序到云上的容器中,也可能有一些应用程序继续存在于Kubernetes之外。云原生应用程序和服务必须与那些传统的单一应用程序进行交互。

遗留层的存在是为了实现互操作性,以暴露一组指向单体应用程序的Headless Service。Headless Service允许开发人员通自由地以自己的方式进行服务发现来减少与Kubernetes系统的耦合。Kubernetes中的Headless Services与ClusterIP、NodePort和LoadBalancer类型的服务不同。它们没有分配给它们的Internet协议(IP)地址,但具有指向外部端点(如API Server、Web服务器和数据库)的域名系统(DNS)条目。遗留层是一个逻辑互操作性层,它将DNS记录维护到众所周知的外部端点。

微服务应用程序的每一层都可以映射到Kubernetes的一个控制器。根据希望部署的模式,DevOps团队可以进行相应的选择。在下一篇文章中,我们将讨论将云原生应用程序部署到Kubernetes的一些*佳实践。

关于作者

Janakiram MSV是Janakiram&Associates的首席分析师,也是国际信息技术学院的兼职教员。他还是Google认证云开发人员,亚马逊认证解决方案架构师,亚马逊认证开发人员,亚马逊认证SysOps管理员和Microsoft认证Azure专业人员。Janakiram是云原生计算基金会的大使,也是*早的认证Kubernetes管理员和认证Kubernetes应用程序开发人员之一。他之前的经历包括Microsoft、AWS、Gigaom Research和Alcatel-Lucent。

Android系统制作自定义签名

1、简介
应客户要求为了是特殊定制的系统更具安全,系统ROM需要使用自己定义的签名,还有一些特殊的场景也会更改系统的签名比如在过cts认证测试的时候也会修改平台签名才能测试通过关于签名的问题。这是因为平台默认的是test签名.网上大多说签名的都是app签名而非平台签名。test签名这种类型的key只适用于开发阶段,而且这种秘钥是公开的,谁都可以使用。当发布一款android产品,就需要另外给整个系统签个名,防止被别人盗用。这种系统就是release版本的Android系统。这里就简单记录下方法。

2、制作自己的平台release签名
要对Android系统进行签名,需要生成四种类型的key文件。

a) releasekey
b) media
c) shared
d) platform
我们就拿platform 为例简单介绍下生成过程。
1)进入/Android源码根目录/development/tools目录。

%title插图%num
2)使用make_key工具生成签名文件

development/tools$ sh make_key platform
‘/C=CN/ST=ShanXi/L=Xi`an/O=Company/OU=Department/CN=banfeipeng/emailAddress=2333869@qq.com’

%title插图%num
Enter password for ‘shared’ (blank for none; password will be visible): mypassword <——- 设置你的密码
creating shared.pk8 with no password
Generating RSA private key, 2048 bit long modulus
……………………………………..+++
………………+++
e is 65537 (0x10001)

3)make_key的参数介绍

这里要顺便介绍下make_key的参数。*个参数是要生成key的名字,第二个参数是关于你公司的信息。

key的名字很好理解,就是前面提到的4中类型的key,公司信息的参数比较多,它们的含义如下:

C —> Country Name (2 letter code)

ST —> State or Province Name (full name)

L —> Locality Name (eg, city)

O —> Organization Name (eg, company)

OU —> Organizational Unit Name (eg, section)

CN —> Common Name (eg, your name or your server’s hostname)

emailAddress —> Contact email address

4)生成后的结果如下:

%title插图%num
5)pk8是生成的私钥,而*.x509.pem是公钥,生成时两者是成对出现的.

 

3、修改android平台签名为刚才修改的签名文件

1.修改build/core/config.mk将:

ifdef PRODUCT_DEFAULT_DEV_CERTIFICATE
DEFAULT_SYSTEM_DEV_CERTIFICATE := $(PRODUCT_DEFAULT_DEV_CERTIFICATE)
else
DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/testkey
endif
修改为:

ifdef PRODUCT_DEFAULT_DEV_CERTIFICATE
DEFAULT_SYSTEM_DEV_CERTIFICATE := $(PRODUCT_DEFAULT_DEV_CERTIFICATE)
else
DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/XXXreleasekey
endif

2.将上面生成的签名文件放到 build/target/product/security/XXX/目录

%title插图%num

3.修改external/sepolicy/keys.conf

%title插图%num

 

 

戴尔 PowerEdge 2900 服务器上的志强 E5405 CPU 有没有办法调整一下频率

请教各位大侠,这个 E5405 默认频率是 2G,结果肯定是外频的晶振频率偏低,造成了这个 CPU 的实际运行频率只有 1995.020MHz,但是某个程序要求必须 2G 以上的运行频率,检查到低于 2000M 就被 Pass 了,所以想请教一下各位老大有没有这个服务器 CPU 的超频方法。

BIOS 里应该是没有类似的普通 PC 的调整外频的超频设置,我又不可能硬改(某些贴吧里有修改某某电阻的阻值来提高*终作用在 CPU 上的外频),有没有软的方法,哪怕运行一下欺骗一下这个程序的检测也行。

CPU 有两颗,一共 8 核 8 线程。

方案:
1、修改 BIOS 设置;
2、服务器装的是 ESXi,有没有软件方式修改;
3、虚拟机跑的是 CentOS7,有没有类似软件修改的方法;
4、……

不知道还有什么思路,哪怕就提高 5M 到达 2000MHz 就好了,谢谢。

sun1991 1
sun1991 2019-02-15 12:21:40 +08:00
放虚拟机里跑?
ShunYea 2
ShunYea 2019-02-15 12:40:03 +08:00 via Android
@sun1991 这个服务器运行了 ESXi,里面的虚拟机是 centos7,就是说能不能从某个层面上把频率超上去 5m
dazhangpan 3
dazhangpan 2019-02-15 12:41:07 +08:00 via Android
开 turbo?
trepwq 4
trepwq 2019-02-15 12:46:37 +08:00 via iPhone
感觉改改 esxi 虚拟机配置应该可以
ShunYea 5
ShunYea 2019-02-15 14:34:49 +08:00
@dazhangpan
请教怎么个操作法?这个 CPU 没有睿频。
ShunYea 6
ShunYea 2019-02-15 14:35:16 +08:00
@trepwq
好像有点高深,找不到类似的教程唉。
ccav 7
ccav 2019-02-15 15:31:18 +08:00 via iPhone
花几十块换 cpu 5400 系列现在 钥匙扣价。
ShunYea 8
ShunYea 2019-02-15 18:05:47 +08:00
@ccav 主要是服务器拆机没有普通 PC 方便啊,好多的卡扣,太麻烦了。
chinvo 9
chinvo 2019-02-15 18:08:36 +08:00 via iPhone
@ShunYea #8 我怎么感觉服务器更好拆呢
sdijeenx 10
sdijeenx 2019-02-15 18:10:50 +08:00
自己买 CPU 偷偷换成 E5420,等换人维护的时候再偷偷把原 CPU 装回去~

ShunYea 11
ShunYea 2019-02-15 18:12:04 +08:00
@chinvo
@sdijeenx
好吧,两位老铁的建议,我去淘 2 个 CPU 吧。
chinvo 12
chinvo 2019-02-15 18:12:30 +08:00 via iPhone
另外很好奇,什么样的应用才会这么严格地检查 CPU 主频,一般不是写在用户手册上么
ShunYea 13
ShunYea 2019-02-15 21:41:20 +08:00 via Android
@chinvo 做了个服务出租的功能,但是对方软件相当于对性能有要求,然后对方的脚本就是这样判断的,低于 2000m 就 pass,我也觉得可以有个范围,这样界定太不合理。
julyclyde 14
julyclyde 2019-02-17 21:30:53 +08:00
既然晶振低,那程序咋知道自己运行在 1995 的?
QQ2171775959 15
QQ2171775959 2019-02-20 16:09:23 +08:00
超一下频吧。
ShunYea 16
ShunYea 2019-02-21 17:14:47 +08:00 via Android
@julyclyde 程序自己检测 CPU 不是难事吧,检测低于 2000m 就不通过,这个逻辑很好理解嘛
ShunYea 17
ShunYea 2019-02-21 17:15:16 +08:00 via Android
@QQ2171775959 现在就是想咨询超频的方法

做运维,送你7个常用的服务器资源监控工具

摘要:服务器监控工具功能相当强大,无论何时何地,我们都可以了解到服务器的功能以及性能。服务器监控工具的使用,可以让我们清楚的知道用户可以打开我们的网站,且确保网速不慢。这里为你列出了几个常用的服务器监控工具,为你省去寻找方案的麻烦。
以这台鲲鹏服务器为例,先查看自己操作系统的发行版本

%title插图%num

(1)nmon:支持收集一段时间内,整机的CPU、磁盘、网络、内存等各项资源的使用情况。

%title插图%num

(2)perf:Linux kernel自带的系统性能优化工具,获取指定进程内的调用情况、各线程调用的CPU资源消耗情况,并支持生成火焰图。

%title插图%num

火焰图的生成过程是:

先trace系统,获取系统的profiling数据
用脚本来绘制
#脚本获取
git clone https://github.com/brendangregg/FlameGraph
(3)top:监控进程和整机的CPU、内存资源消耗情况,并支持查看每个CPU核的使用情况。

1.负载:时间,登陆用户数,系统平均负载;

2.cpu:用户态,核心态,NICE,空闲,等待IO,中断等;

3.进程:运行,睡眠,停止,僵尸;

4.内存:总量,已用,空闲(系统角度),缓冲,缓存;

5.交换分区:总量,已用,空闲

任务区域默认显示:进程ID,有效用户,进程优先级,NICE值,进程使用的虚拟内存,物理内存和共享内存,进程状态,CPU占用率,内存占用率,累计CPU时间,进程命令行信息。%title插图%num

(4)iostat:监控每块磁盘的读写次数、数据量大小、使用率。

iostat属于sysstat软件包,可以直接安装。

 yum -y install sysstat
%title插图%num

(5)sar:(System Activity Reporter系统活动情况报告)目前LINUX上*为全面的系统性能分析工具之一,监控每张网卡的网络IO读写次数和数据量大小。

先安装deltarpm再安装sar工具(sar也属于sysstat软件包,可以直接安装。)

yum install deltarpm
yum install sysstat

(6)dstat:监控系统整体的性能信息,包括CPU、磁盘、网络、分页等。输出是彩色的,可读性较强

安装dstat

yum install dstat-0.7.2-12.el7 -y

%title插图%num

(7)htop:htop 是Linux系统中的一个互动的进程查看器,可以让用户交互式操作,支持颜色主题,可横向或纵向滚动浏览进程列表,并支持鼠标操作。

安装htop

yum install -y htop

%title插图%num

htop优点:

▪ 在启动上,比top更快。

▪ 可以横向或者纵向滚动浏览进程列表,以便看到所有的进程和完整的命令行。

▪ 杀进程时不需要输入进程号。

▪ htop支持鼠标操作。

什么是shell和shell编程

1.什么是shell?

shell是你(用户)和Linux(或者更准确的说,是你和Linux内核)之间的接口程序。你在提示符下输入的每个命令都由shell先解释然后传给Linux内核。 说到底,Shell是用户与内核进行交互操作的一种接口,目前*流行的Shell称为bash Shell

Shell是解释执行的脚本语言,所谓脚本语言就是不用编译就可以直接执行的语言。在Shell中可以调用Linux系统命令。

shell的*强大的重要特性是它自身就是一个解释型的程序设计语言,shell 程序设计语言支持在高级语言里所能见到的*大多数程序控制结构,比如循环,函数,变量和数组。shell 编程语言很易学,并且一旦掌握后它将成为你的得力工具。任何在提示符下能键入的命令都能放到一个可执行的shell程序里,这意味着用shell语言能简单地重复执行某一任务。

场景:只知道写shell脚本,却不知道什么是shell?那shell是什么呢?找到了之前在腾讯课堂上看的视频,这是课件笔记

你学Linux的话,不懂shell等同于不懂linux
shell是操作系统的*外层,shell可以合并编程语言以控制进程和文件,以及启动和控制其他程序。
简单来说:shell就是一个用户跟操作系统之间交互的命令解释器

感觉像是java和虚拟机的关系一样

在一些复杂的Linux维护工作中,大量重复的输入和交互操作不但费时费力,而且容易出错.
编写脚本的好处:批量的处理,自动化的完成维护,减轻管理员的负担.

不说不知道,一说吓一跳呀,在工作中经常写一些脚本,就是为了方便。

shell独立于内核,它是链接内核和应用程序的桥梁。内核是linux系统的心脏,从开机自检就驻扎在计算机内存中,直到计算机关闭为止。用户的应用程序存储在计算机硬盘上,仅当需要时才被调入内存。shell是一种应用程序,当用户登陆linux系统时,shell就会被调用到内存执行。

不登录怎么执行呢,好像听说过有nologin 的一种模式

linux的shell脚本是一种特殊的应用程序,常见的shell解释器有很多种使用不同的shell时期内部指令命令提示方式方面会存在一些区别,可以通过/etc/shells文件查看

就是不同命令之间有不同的显示和操作

/bin/bash 是大多数linux中默认的shell解释器。

还有chsh不过不经常用,我们一般都是写bash,头文件中添加#!/bin/bash的标志

如何编写*个Shell脚本(shell 就是命令的集合)

其实就是命令的集合,唯一的区别使shell脚本我们可以优化,加入一些for循环,if条件语句。

linux不以后缀名区分文件,为了方便记忆这里我就以.sh为结尾

编写一个shell

1 [support@CMS01 wdq]$ vim first.sh#!/bin/bash
2 #!/bin/bash
3 #auto my frist scripts
4 #by authors cd
5 echo “hello world”
6 mkdir /home/support/tmp/wdq/test
7 free -m

注释:
#!/bin/bash 主要是为了声明,我所写的均为bash语言(我是用的是bash解释器)[定义我的脚本是shell脚本].{固定格式}
#! 称为sha-bang符号,是shell脚本的起始符,他告诉linux系统这个文件的执行需要指定一个解释器。

ll查看是都有权限

1 [support@CMS01 wdq]$ ll
2 total 8
3 -rw-rw-r– 1 support support 1388 May 9 19:51 backupLogs.sh
4 -rw-rw-r– 1 support support 96 Jul 2 17:16 first.sh
5 [support@CMS01 wdq]$ chmod u+x first.sh
6 #赋执行权限

在执行标准/bin/bash/+脚本来执行,这样的就不需要加权限了。
执行权限的不同方式

1 *种使用*对路径执行
2 第二种使用相对路径执行,如./的方式
3 第三种使用 sh命令来执行 格式 sh 脚本名 不需要执行权限
4 第四种使用 . (空格)脚本名称的方式执行 不需要执行权限 . a.sh
5 第五种使用 source 脚本名称 不需要执行权限(主要用于生效配置文件)
6 建议使用后三种,在生产环境中不要轻易的给文件可执行权限;

2.linux中有哪些shell?

一个系统可以存在多个shell,可以通过cat /etc/shells命令查看系统中安装的shell,不同的shell可能支持的命令语法是不相同的,但是*常用的shell还是/bin/bash。下面的演示也基于/bin/bash

1  [robot@hadoop103 ~]$ cat /etc/shells
2  /bin/sh
3  /bin/bash
4  /sbin/nologin
5  /usr/bin/sh
6  /usr/bin/bash
7  /usr/sbin/nologin
8  /bin/tcsh
9  /bin/csh

1  sh(全称 Bourne Shell): 是UNIX*初使用的 shell,而且在每种 UNIX 上都可以使用。
2  Bourne Shell 在 shell 编程方面相当优秀,但在处理与用户的交互方面做得不如其他几种 shell。
3  bash shell(全称 Bourne Again Shell): LinuxOS 默认的,它是 Bourne Shell 的扩展。
4  与 Bourne Shell 完全兼容,并且在 Bourne Shell 的基础上增加了很多特性。可以提供命令补全,命令编辑和命令历史等功能。
5  它还包含了很多 C Shell 和 Korn Shell 中的优点,有灵活和强大的编辑接口,同时又很友好的用户界面。

3.演示一个demo

一个简单的shell实例(用shell脚本语言启动tomcat)
#!/bin/sh
cd /usr/local/apache-tomcat-5.5.23/bin/
./catalina.sh start
文件取名为tomcat
说明
这个脚本只有三行,它的*行指明这个脚本程序由那个程序来解释。
第二行只有一个简单的动作进入某个目录,第三行调用catalina.sh脚本启动tomcat。
执行脚本
执行脚本前先赋予tomcat脚本可执行权限,命令如下:chmod +x tomcat ,
否则会出现如下错误:-bash: ./tomcat: Permission denied #当然如果直接用sh tomcat执行,不需要u+x赋予执行权限
假设tomcat脚本所在目录为为/home/amy/
在/home/amy/目录下执行脚本: ./tomcat
在别的目录下执行脚本: /home/amy/tomcat

4.Shell编程模型

%title插图%num

5.Shell基本的执行方式

1  首先要赋予+x权限,赋予脚本执行权限
2  *种:输入脚本的*对路径或相对路径
3    /root/helloWorld.sh
4    ./helloWorld.sh
5  或者,不用赋予+x权限,而用解释器解释执行u+x
6  第二种:bash或sh +脚本
7    sh /root/helloWorld.sh
8    sh helloWorld.sh
9  第三种:在脚本的路径前再加”. ”
10    . /root/helloWorld.sh
11    . ./helloWorld.sh #注意这里两个点。当然加一个点也可以执行,属于*种
12  区别:*种和第二种会新开一个bash,不同bash中的变量无法共享

Python—random,time,PIL库

Python—random,time,PIL库

文章目录
random库
生成随机数字
列表随机挑选元素
time模块
PIL类
random库
random.seed(a=None, version=2)

设置随机种子,若不想让随机函数,有随机性,可以手动设置种子,以后每次随机出来的数字就会一样了

生成随机数字
random.randrange(stop)

random.randrange(start, stop[, step])

在range()中随机挑选一个数字。

从 range(start, stop, step) 返回一个随机选择的元素。 这相当于 choice(range(start, stop, step)) ,但实际上并没有构建一个 range 对象。

random.randint(a, b)

在[a,b]中随机挑选一个整数

列表随机挑选元素
random.choice(seq)

从非空序列 seq 返回一个随机元素。 如果 seq 为空,则引发 IndexError。

random.choices(population, weights=None, *, cum_weights=None, k=1)

从population中选择替换,返回大小为 k 的元素列表。 如果 population 为空,则引发 IndexError。

如果指定了 weight 序列,则根据相对权重进行选择。 或者,如果给出 cum_weights 序列,则根据累积权重(可能使用 itertools.accumulate() 计算)进行选择。 例如,相对权重[10, 5, 30, 5]相当于累积权重[10, 15, 45, 50]。 在内部,相对权重在进行选择之前会转换为累积权重,因此提供累积权重可以节省工作量。

若即未指定weight也未指定cum_weights,则以相等的概率进行选择,如果提供了权重序列,则它必须与population序列的长度相同。

有放回的随机抽样

random.shuffle(x[, random])

将x序列随机打乱位置。

没有返回值,在原序列上进行修改。

对于样本量大的对象,且不想打乱顺序的,可以打乱对象的索引。random.shuffle(range(len(x)))

random.sample(population, k)

返回从总体序列或者集合中选择的唯一元素的k长度的列表。无重复的随机抽样。

返回一个新列表,保持原始总体不变。

例如:sample(range(10000000), k=60)

random.random()

返回[0.0 , 1.0)范围内的一个随机浮点数。

random.uniform(a, b)

返回一个随机浮点数。范围[小,大]

eval(‘1+3’)它会将1+3字符串的引号去掉,然后计算它的值。

time模块
time.time()时间戳。从1970年1月1日00:00:00到现在的秒数

time.asctime()当地时间,返回一个字符串类型

time.localtime()本地时间,返回一个时间对象的字符串

time.ctime()当地时间,一般使用这个函数获取当地时间

time.strftime(‘%Y-%m-%d %H:%M:%S’)将时间转化为指定格式的字符串。

time.strptime(‘2020-05-29 14:27:21′,’%Y-%m-%d %H:%M:%S’)将指定格式的字符串,转化为时间类型的字符串

time.sleep(2)休眠2秒

PIL类
第三方库
%title插图%num

莱文斯顿距离(python版)

莱文斯顿距离(python版)

莱文斯顿距离(python版)
leetcode No.72
leetcode No.72
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的*少操作数 。

你可以对一个单词进行如下三种操作:

插入一个字符
删除一个字符
替换一个字符
示例:

输入:word1 = “intention”, word2 = “execution”
输出:5
解释:
intention -> inention (删除 ‘t’)
inention -> enention (将 ‘i’ 替换为 ‘e’)
enention -> exention (将 ‘n’ 替换为 ‘x’)
exention -> exection (将 ‘n’ 替换为 ‘c’)
exection -> execution (插入 ‘u’)

首先,使用动态规划思想,首先创建一个二维数组subset,长度为len(word2) + 1,宽度为len(word1) + 1,二维数组中的每一个位置用来记录每一步的*小距离。其中*行表示word1为空字符串,并依次从空字符串变成word2(依次插入);*列表示word2为空字符串,并依次从word1变成空字符串(依次删除)。根据上面已知条件对数组进行初始化赋值。

然后,按照以下条件依次对二位数组中的每个位置(row, column)进行赋值:
(1)当word1[row – 1] != word2[column – 1]时,subset[row][column] 的取值等于该位置左方、上方、左上方距离为1的位置的*小值加1,即
subset[row][column] = min(subset[row – 1][column – 1], subset[row – 1][column], subset[row][column – 1]) + 1
(2)当word1[row – 1] == word2[column – 1]时,subset[row][column] 的取值等于该位置左上方的值,可以理解为由于字符相等编辑距离无需加1操作,即当前*小距离等于同时删除word1以及word2的当前字符的*小距离(左上方距离为1处的值)。

下面解释一下二维数组中的移动方向分别表示的意义:

↓ 表示删除word1的当前字符操作(距离+1)
→ 表示插入word2的当前字符操作(距离+1)
↘ 表示将当前word1的字符替换为word2的当前字符(距离+1)
↖ 可以理解为当前word2的字符与当前word1的字符相同时,同时将这两个字符删除(距离维持不变)
举例,word1=kitten,word2=sitting

%title插图%num
word1与word2*小编辑距离即为二维数组*右下方的值:
subset[-1][-1] == 3

代码(python):

def minDistance(word1, word2):
length1 = len(word1) + 1
length2 = len(word2) + 1
subset = [[0] * length2 for i in range(length1)]
for i in range(length2):
subset[0][i] = i
for j in range(length1):
subset[j][0] = j
for row in range(1, length1):
for column in range(1, length2):
if word1[row – 1] != word2[column – 1]:
subset[row][column] = min(subset[row – 1][column – 1],\
subset[row – 1][column], subset[row][column – 1]) + 1
else:
subset[row][column] = subset[row – 1][column – 1]
return subset[-1][-1]

测试:

word1, word2 = “horse”, “ros”
print(minDistance(word1, word2))

输出:

3

一个创业公司的API网关落地实践

HelloFresh是一家食品电商初创公司,用户根据选定的菜谱下单,HelloFresh把菜谱所需要的食材送至用户家中。来自HelloFresh的技术负责人Ítalo Lelis在博客上分享了HelloFresh的API网关落地实践,本文为该博文的译文,并已获得原网站的翻译授权。

HelloFresh的规模一直保持着增长的态势,我们的产品在持续改进,新的想法不断涌现出来,我们拥有完全自动化的供应链。持续的增长给我们带来了惊喜,同时也带来了技术方面的挑战。

在这篇文章里,我将会和大家分享我们的基础设施所经历的一次重大迁移,这次迁移保证了以后的路我们可以走得更快、更灵活,也更安全。

我们*近开发了一个API网关(github.com/hellofresh/janus),所以接下来需要在不停机的情况下对网关后面的主API(单体系统)进行迁移改造。升级之后,我们希望能够开发更多的微服务系统,并且无缝对接到目前我们的基础架构中。

API网关处在基础设施的*外层,它每天需要接收大量的请求,所以我们选择了Go语言来构建网关,因为Golang性能好、简单易用,而且提供了优雅的并发解决方案。我们手头已经有很多现成的工具,它们可以简化我们的迁移工作。

服务发现和客户端负载均衡

我们使用Consul作为服务发现工具,它和HAProxy配合起来使用可以帮我们解决微服务架构的两个主要问题:服务发现(新服务上线时会自动注册)和客户端负载均衡(把请求均衡地分发到各个服务器上)。

自动化

我们的工具箱里*有用的工具或许要数基础设施的自动化。我们使用Ansible在云端管理资源,包括单机、网络、DNS、运行持续集成工具的主机,等等。按照我们的惯例,开发一个新服务时,我们工程师的*件事情就是为这个服务创建Ansible脚本。

日志和监控

从某种程度上说,我们应该监控基础设施里的所有东西。在日志和监控应用方面,我们有一些*佳实践。

  • 办公室里有仪表盘(就是国内公司里的大电视屏,显示系统状态),我们在任何时候都可以查看系统的运行情况。
  • 我们使用ELK技术栈来收集日志,从而可以快速地分析服务的运行情况。
  • 我们使用Statsd和Grafana作为监控工具,这些工具总会给我们带来惊喜。

Grafana的仪表盘为性能度量指标提供了非常完美的视角。

 

理解当前的架构

尽管有了这些工具,我们仍然有一个棘手的问题需要解决:理清当前的架构,然后想清楚如何顺利地进行迁移。我们花了一些时间对遗留系统进行了重构,让它们支持新的网关,同时我们也加入了认证服务。在这个过程中,我们遇到了一些问题。

  • 虽然我们可以对移动应用进行更新,但也要考虑到有些用户可能不愿意升级,所以我们要保持向后兼容,比如DNS,我们要确保旧版本也能正常工作。
  • 我们需要整理出所有公开和私有的API端点,并让它们自动地注册到网关上。
  • 我们需要把认证工作从主API迁移到新的认证服务上。
  • 确保网关和微服务之间通信的安全性。

为了解决这些问题,我们写了一个Go脚本,这个脚本会读取OpenAPI规范(Swagger)文件并为API资源创建规则(比如速率限定、配额、CORS等)代理。

我们在staging环境搭建了整个基础设施,并在上面运行自动化测试,对服务间的通信进行了测试。不得不说,自动化staging测试在整个迁移过程中起到了很大的作用。我们有很多功能测试用例,这些用例保证了主API的功能是完好的。

在确保了staging环境一切正常之后,我们开始考虑如何将它们推到生产环境。

 

*次尝试

可以告诉大家的是,我们的*次尝试简直是灾难性的。尽管我们已经做足了计划,不过仍然不足以把它们推向生产环境。先来看看我们的初始计划。

  • 把*新的API网关部署到staging环境
  • 把主API的变更部署到staging环境
  • 在staging环境运行自动化功能测试
  • 通过网站和移动端进行staging环境的手动测试
  • 把*新的API网关部署到生产环境
  • 把主API的变更部署到生产环境
  • 在生产环境运行自动化功能测试
  • 通过网站和移动端进行生产环境的手动测试
  • 庆祝胜利

在staging环境一切进展得都很顺利,当我们准备进入生产环境时,问题出现了。

  • 认证服务的数据库过载:我们低估了请求的流量,造成数据库拒*连接
  • 错误的CORS配置:部分端点的CORS规则配置错误,造成请求无法获得资源

数据库被冲垮,我们不得不马上回滚。幸运的是,我们的监控系统捕获到了从认证服务获取令牌的问题。

第二次尝试

从*次失败中吸取了教训,我们知道我们还没有为进入生产环境做好准备,于是在回滚之后,立即对问题展开诊断。在再次尝试之前,我们做了一些改进。

  • 准备蓝绿(blue-green)部署过程。我们为生产环境创建了一个副本,包括已经部署好的网关,通过一些简单的配置变更就能让整个集群运行起来,如果需要回滚,也只需做一些简单的配置变更。
  • 从当前的系统收集更多的度量指标,这样可以帮助我们决定该使用多少机器来处理负载。我们利用*次尝试时所使用的数据作为探针,并使用Gatling来运行负载测试,确保我们可以应付预期的流量。
  • 再次进入生产环境之前,我们对认证服务的已知问题进行了修复,包括一个大小写问题、一个JWT签名的性能问题,并添加了更多的日志和监控。

我们花费了一个*拜来完成上述的工作,之后的部署进展得很顺利,中间没有停机。不过尽管部署进展得很顺利,我们仍然发现了一些在自动化测试中没有发现的个别问题,不过这些问题*终得到修复,并没有对系统造成太大影响。

*终结果

*终的架构如下图所示。

 

主API

  • 10多个主API部署在装配了高端CPU的主机上
  • 主从MySQL(3个副本)
  • 认证服务

4个应用服务器

  • 主从PostgreSQL(2个副本)
  • RabbitMQ用于异步地处理用户的更新操作
  • API网关

4个应用服务器

  • 主从MongoDB(4个副本)

其它

  • 使用Ansible批量管理远程服务器
  • 使用Amazon CloudFront作为CDN/WAF
  • 使用Consul和HAProxy作为服务发现和客户端负载均衡工具
  • 使用Stasd和Grafana收集系统度量指标并触发告警
  • 使用ELK技术栈从不同的服务收集日志
  • 使用Concourse CI作为持续集成工具

 

linux shell脚本EOF妙用

在平时的运维工作中,我们经常会碰到这样一个场景:
执行脚本的时候,需要往一个文件里自动输入N行内容。如果是少数的几行内容,还可以用echo追加方式,但如果是很多行,那么单纯用echo追加的方式就显得愚蠢之*了!
这个时候,就可以使用EOF结合cat命令进行行内容的追加了。

下面就对EOF的用法进行梳理:
EOF是END Of File的缩写,表示自定义终止符.既然自定义,那么EOF就不是固定的,可以随意设置别名,在linux按ctrl-d就代表EOF.
EOF一般会配合cat能够多行文本输出.
其用法如下:
<<EOF        //开始
….
EOF            //结束

还可以自定义,比如自定义:
<<BBB        //开始
….
BBB              //结束

通过cat配合重定向能够生成文件并追加操作,在它之前先熟悉几个特殊符号:
< :输入重定向
> :输出重定向
>> :输出重定向,进行追加,不会覆盖之前内容
<< :标准输入来自命令行的一对分隔号的中间内容.

先举一个简单的例子,例1:
# cat << EOF
在出现输入提示符”>”,输入以下内容:
> Hello
> EOF
输入结束后,在终端显示以下内容:
Hello

思考:
我们可以从cat命令的说明中知道,cat的操作对象是文件,但是例1中cat的操作对象不是文件,而是用户输入。

那么我们可以这样理解例1:先在文件file中输入“Hello”,再用cat file输出其中的内容。
也就是说我们可以用一个文件来替代”<< EOF EOF”。
反过来说,如果操作命令中的文件是输入对象,也可以用”<< EOF EOF”来替代的。

为了验证上面的思考,我们试验两个例子:
例2. 假设有如下的磁盘分区脚本:
sfdisk -uM /dev/sda << EOF
,2048,b
,1024,83
,1024,83
EOF
根据之前的思考,将”<< EOF”和”EOF”之间的内容保存到文件part中,然后将脚本修改为:
sfdisk -uM /dev/sda < part
经测试,修改后的方式可以达到同样的分区结果。

例3. 将一个文件的内容输出到另一个文件中:
# cat fileA > fileB
按照之前的思考,将”<< EOF EOF”替代输入对象文件fileA:
# cat << EOF > fileB
经测试,命令执行后提示用户输入内容,输入结束后,用户的输入内容被保存到了fileB中。

综上所述,“<< EOF EOF”的作用是在命令执行过程中用户自定义输入,它类似于起到一个临时文件的作用,只是比使用文件更方便灵活。

下面通过具体实例来感受下EOF用法的妙处:
1)向文件test.sh里输入内容。
[root@slave-server opt]# cat << EOF >test.sh
> 123123123
> 3452354345
> asdfasdfs
> EOF
[root@slave-server opt]# cat test.sh
123123123
3452354345
asdfasdfs

追加内容
[root@slave-server opt]# cat << EOF >>test.sh
> 7777
> 8888
> EOF
[root@slave-server opt]# cat test.sh
123123123
3452354345
asdfasdfs
7777
8888

覆盖
[root@slave-server opt]# cat << EOF >test.sh
> 55555
> EOF
[root@slave-server opt]# cat test.sh
55555

2)自定义EOF,比如自定义为wang
[root@slave-server opt]# cat << wang > haha.txt
> ggggggg
> 4444444
> 6666666
> wang
[root@slave-server opt]# cat haha.txt
ggggggg
4444444
6666666

3)可以编写脚本,向一个文件输入多行内容
[root@slave-server opt]# touch /usr/local/mysql/my.cnf               //文件不提前创建也行,如果不存在,EOF命令中也会自动创建
[root@slave-server opt]# vim test.sh
#!/bin/bash

cat > /usr/local/mysql/my.cnf << EOF                                      //或者cat << EOF > /usr/local/mysql/my.cnf
[client]
port = 3306
socket = /usr/local/mysql/var/mysql.sock

[mysqld]
port = 3306
socket = /usr/local/mysql/var/mysql.sock

basedir = /usr/local/mysql/
datadir = /data/mysql/data
pid-file = /data/mysql/data/mysql.pid
user = mysql
bind-address = 0.0.0.0
server-id = 1
sync_binlog=1
log_bin = mysql-bin

[myisamchk]
key_buffer_size = 8M
sort_buffer_size = 8M
read_buffer = 4M
write_buffer = 4M

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
port = 3306
EOF

[root@slave-server opt]# sh test.sh           //执行上面脚本
[root@slave-server opt]# cat /usr/local/mysql/my.cnf    //检查脚本中的EOF是否写入成功
[client]
port = 3306
socket = /usr/local/mysql/var/mysql.sock

[mysqld]
port = 3306
socket = /usr/local/mysql/var/mysql.sock

basedir = /usr/local/mysql/
datadir = /data/mysql/data
pid-file = /data/mysql/data/mysql.pid
user = mysql
bind-address = 0.0.0.0
server-id = 1
sync_binlog=1
log_bin = mysql-bin

[myisamchk]
key_buffer_size = 8M
sort_buffer_size = 8M
read_buffer = 4M
write_buffer = 4M

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
port = 3306

———————————————————————————
下面分享一个自动新建分区并挂载的脚本:

%title插图%num