wget 网络请求工具

wget 是当前 Unix 系统不可或缺的工具之一。

  • 下载
  • 使用

wget命令用来从指定的URL下载文件。wget非常稳定,它在带宽很窄的情况下和不稳定网络中有很强的适应性,如果是由于网络的原因下载失败,wget会不断的尝试,直到整个文件下载完毕。如果是服务器打断下载过程,它会再次联到服务器上从停止的地方继续下载。这对从那些限定了链接时间的服务器上下载大文件非常有用。

下载

Ubuntu

$ sudo apt install -y wget

CentOS

$ sudo yum install -y wget

macOS

$ brew install wget

使用

下载

$ wget https://wxnacy.com/images/vimgrep.gif

重命名

$ wget -O vg.gif https://wxnacy.com/images/vimgrep.gif

后台下载

后台下载,并将日志输出到 wget-log 中

$ wget -b https://wxnacy.com/images/vimgrep.gif

输入日志到文件

将本要输出到屏幕的日志信息输出到指定文件

$ wget -a[/-o] wget.log https://wxnacy.com/images/vimgrep.gif

下载完整网站

$ wget --mirror -p --convert-links -P ~/Downloads https://wxnacy.com
  • –miror 开户镜像下载。
  • -p 下载所有为了html页面显示正常的文件。
  • –convert-links 下载后,转换成本地的链接。
  • -P ~/Downloads 保存所有文件和目录到本地指定目录。

Gitlab利用Webhook实现Push代码后的jenkins自动构建

之前部署了Gitlab的代码托管平台和Jenkins的代码发布平台。通常是开发后的代码先推到Gitlab上管理,然后在Jenkins里通过脚本构建代码发布。这种方式每次在发版的时候,需要人工去执行jenkins上的构建动作,有时显得过于繁琐。于是就想到了Gitlab的Webhook功能,通过Webhook的相关设置,可以实现代码Push后,自动去触发jenkins上的构建动作,这样就不需要人工干预去执行发版操作了。设置如下:

1)Jenkins上的操作

通常,jenkins在项目配置时是可以配置远程构建触发器,设置好jenkins的回调url后就可以让jenkins进行自动构建。这就需要先下载Gitlab Hook Plugin 插件。登陆Jenkins,分别点击”系统管理”->”插件管理”->”可选插件”,选择Gitlab Hook Plugin

未分类

然后构建相应的项目工程,比如下面的test-wx(下面最关键的是第2步中查看url,然后用这个url回调地址去Gitlab的webhook上添加)
a)先设置代码的git下载路径,这里通过ssh方式(需要提前将Jenkins本机的key添加到Gitlab上)

未分类

b)查看jenkin生成回调地址。在任务重构建触发器下获取回调URL。下面的URL那一行只有Gitlab Hook Plugin插件下载成功后才能显示。

未分类

c)然后设置代码发布的推送脚本

未分类

2)Gitlab上的操作

登陆Gitlab上的testwx3项目中,添加webhook(用上面Jenkins中生成的回调url)

未分类

然后点击这个项目的”Settings”

未分类

未分类

添加成功后,点击此webhook后面的test进行测试

未分类

如果返回Hook successfully executed.表示配置成功。
这样,下次push代码后,就会自动触发jenkins上相关的构建工程进行自动发布了!无需人工干预~

未分类


如上设置后,比如在gitlab的testwx3项目代码库中push一个test.txt文件,然后测试下是否自动发布了

未分类

然后去Jenkins上查看,如下发现已经自动发布了!

未分类

最后去目标机器192.168.1.19的/tmp/testwx目录下发现test.txt文件已经发布过来了~

未分类

适用于DevOps的10款最佳Jenkins插件

目前 Jenkins 有超过 1500 个插件,用于支撑整个持续集成流程。由于插件数量众多,要选择一些合适的 Jenkins 插件会比较困难,本文介绍了一些比较有用的 Jenkins 插件,能够提升开发者效率。
尽管目前在 CI/CD 领域有着众多的平台,Jenkins 一直是最著名的持续集成平台之一。虽然它经历了和 Oracle 的争斗,最终从之前的 Hudson 单独分离出来,但是凭借社区和大公司的支持,目前 Jenkins 有超过 1500 个插件,用于支撑整个持续集成流程。
不过由于插件数量众多,要选择一些合适的 Jenkins 插件会比较困难,本文介绍了一些比较有用的 Jenkins 插件,能够提升开发者效率。

Job DSL Plugin

参考链接:https://github.com/jenkinsci/job-dsl-plugin
对于很多开发者来说,不同的仓库和项目分支都需要去 Jenkins 上重新创建任务。这是一个重复且单调的工作,对于开发者来说非常不友好。
Jenkins Job DSL Plugin 可以让开发者通过 Groovy 脚本来定义和配置任务,随后插件会通过执行这些脚本来维护 Jenkins 任务。这样开发团队可以定制自己的模板文件,通过领域特定语言(Domain Specific Language,DSL)直接定义和创建任务。

Job Generator Plugin

参考链接:https://wiki.jenkins.io/display/JENKINS/Job+Generator+Plugin
和 Job DSL Plugin 类似,Job Generator Plugin 也是用于快速创建任务。对于大团队来说,整个持续集成流程应该类似,不同的项目的区别主要就是代码分支等。该插件可以让团队的配置管理员为整个团队定义一个参数化的模板,项目开发人员可以通过这个模板快速的在 Jenkins 上创建出任务。
该插件和 Job DSL 插件的最大区别是使用者无需了解 Groovy。

Performance Plugin

参考链接:https://plugins.jenkins.io/performance
该插件可以读取和解析测试框架输出的报告,并且在 Jenkins 上绘制性能和稳定性相关的图表。Performance Plugin 支持的测试框架有 JUnit、JMeter, Twitter 的 Lago 和 Taurus。下图是该插件输出的示例图:

未分类

Gitlab Merge Request Builder Plugin

参考链接:https://github.com/timols/jenkins-gitlab-merge-request-builder-plugin
Gitlab Merge Request Builder Plugin 可以方便的自动发起代码审查,它在创建 pull request 的时候,会自动带上关联任务的运行结果,以方便代码审查着确认改动的正确性。
同时,这款插件还支持自动合并,既在代码审查通过后自动合并该 pull request 内容。

JIRA Plugin

参考链接:https://plugins.jenkins.io/jira
JIRA Plugin 可以让 Jenkins 任务和 JIRA 集成起来,这样项目管理者可以通过 JIRA 了解项目进度,开发者也可以通过该插件直接更改 JIRA 上的 issue 状态。

Kubernetes Plugin

参考链接:https://github.com/jenkinsci/kubernetes-plugin
和最近大热的容器编排框架 Kubernetes 集成当然不能落下了。另外,Jenkins 对执行机的管理一直比较弱,无法做到快速的扩容和缩容。Kubernetes Plugin 通过引入 Kubernetes 的容器编排能力,让 Jenkins 执行机运行在 Kubernetes 环境中。

Build Pipeline plugin

参考链接:https://github.com/jenkinsci/build-pipeline-plugin
对一个系统的持续集成会包含很多个方面,如果将它们都杂糅在一个 Jenkins 任务中,会提高排查成本,也不利于整个持续集成的运作。Build Pipeline plugin 可以让项目管理员针对系统持续集成步骤设置一系列关联的任务,任务之间可以设置不同的触发条件,以确认何时需要人工介入。该插件可以让整个持续集成流程变得非常直观:

未分类

SCM Sync Configuration Plugin

参考链接:https://plugins.jenkins.io/scm-sync-configuration
对于项目管理人员来说,项目配置的丢失和代码丢失一样是非常危险的。对于代码我们有代码仓库进行保存,对于配置也需要能够备份和版本管理。SCM Sync Configuration Plugin 可以自动将 Jenkins 任务配置同步到版本管理系统中。另外,该插件还可以跟踪配置的变更情况,让项目管理人员能够清晰的了解任务的修改情况。

Jenkins Maven plugin

参考链接:https://plugins.jenkins.io/maven-plugin
相比于 Jenkins 内置的 Maven 支持,Jenkins Maven plugin 对 Maven 工程提供了更丰富的功能。包括:自动配置报告插件(如 JUnit、Findbugs 等),增量构建,并行构建等。

Jenkins Subversion plugin

参考链接:https://plugins.jenkins.io/subversion
目前仍然有很多项目在使用 Subversion 作为版本控制软件,Jenkins Subversion plugin 让 Jenkins 任务可以支持托管在 Subversion 上的工程。它的功能包括监视 Subversion 仓库变更来触发新的构建和自动更新执行机工作目录,以确保构建的及时性和正确性。

MySQL不支持InnoDB的解决方法

在OpenSUSE下装上MySQL后,发现无法选择添加事务支持数据引擎InnoDB。
G一下后,解决如下:
/var/lib/mysql目录下,删除ibdata1、ib_logfile1、 ib_logfile0,然后重启MySql让其重建以上文件:

mysqladmin -uroot -p shutdown
sudo mysqld_safe &

搞定!
下面是网络上的其它文章。大家也可以参考下。
早上起来,到PHP站点去看了下,准备测试下别人写的一个CMS系统,高兴的下载了程序,然后把程序拷贝到所在目录。由于该程序没有install.php,里面只包含了一个.sql的数据库语句,只得到mysql数据库中去执行这条语句:
进入数据库后,输入source 所在目录/
.sql
这个时候问题出现了:
QUOTE:

MySQL Server Error:
The 'InnoDB' feature is disabled; you need MySQL built with 'InnoDB' to have it working

在mysql中输入SHOW variables like “have_%”查看,显示如下:

mysql> SHOW variables like "have_%"
-> ;
+-----------------------+----------+
| Variable_name | Value |
+-----------------------+----------+
| have_archive | YES |
| have_bdb | NO |
| have_blackhole_engine | NO |
| have_compress | YES |
| have_crypt | NO |
| have_csv | NO |
| have_dynamic_loading | YES |
| have_example_engine | NO |
| have_federated_engine | NO |
| have_geometry | YES |
| have_innodb | DISABLED |
| have_isam | NO |
| have_merge_engine | YES |
| have_ndbcluster | NO |
| have_openssl | DISABLED |
| have_query_cache | YES |
| have_raid | NO |
| have_rtree_keys | YES |
| have_symlink | YES |
+-----------------------+----------+
19 rows in set (0.00 sec)

蓝色表示我的MYSQL并不支持innodb。
MySQL中InnoDB和MyISAM类型的差别

  • InnoDB和MyISAM是在使用MySQL最常用的两个表类型,各有优缺点,视具体应用而定。下面是已知的两者之间的差别,仅供参考。
    1.InnoDB不支持FULLTEXT类型的索引。
    2.InnoDB 中不保存表的具体行数,也就是说,执行select count() from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含 where条件时,两种表的操作是一样的。
    3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
    4.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
    5.LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
    另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like “%aaa%”
    任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。
    如果你想使用外键,事务等功能,记得用innodb引擎。使用方法是create table xxx()engine=innodb;如果想所有建立的表格都用innodb引擎,可以把“default-storage-engine=INNODB”加到/etc/mysql/my.cnf(位置可能不同)。设完之后就可以用“show engines;”检查是否设置好。不过据说该设置在5.0.22下可能无效。

网上查找了,打开我的my.ini文件,找到skip-innodb,改成#skip-innodb。
之后重启mysql。。问题解决。

mysql> SHOW variables like "have_%"
-> ;
+-----------------------+----------+
| Variable_name | Value |
+-----------------------+----------+
| have_archive | YES |
| have_bdb | NO |
| have_blackhole_engine | NO |
| have_compress | YES |
| have_crypt | NO |
| have_csv | NO |
| have_dynamic_loading | YES |
| have_example_engine | NO |
| have_federated_engine | NO |
| have_geometry | YES |
| have_innodb | YES |
| have_isam | NO |
| have_merge_engine | YES |
| have_ndbcluster | NO |
| have_openssl | DISABLED |
| have_query_cache | YES |
| have_raid | NO |
| have_rtree_keys | YES |
| have_symlink | YES |
+-----------------------+----------+
19 rows in set (0.00 sec)

Python-Jenkins API使用 —— 在后端代码中操控Jenkins

最近在工作中需要用到在后台代码中触发Jenkins任务的构建,于是想到Jenkins是否有一些已经封装好的API类库提供,用于处理跟Jenkins相关的操作。下面就简单介绍下我的发现。

Linux Curl

  
首先找到的是Jenkins官网的wiki:https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API

在官网首页就有关于触发job的方法:

未分类

个人尝试了下,该方式是通过命令行直接调curl去发POST请求的方式来触发job的构建。对于用openid管理的Jenkins,需要带上参数–user USER:PASSWORD,其中的USER和PASSWORD不是你的openID登录的账号密码,而是登录后显示在Jenkins中的User Id和API Token,它们的的查看方式如下:

用openID登录jenkins —> 点击右上角的用户名,进入用户个人页面 —> 点击左边的设置,打开设置页面 —> API Token,Show Api Token…

如果需要参数化构建job,则要加上–data-urlencode json='{“parameter”: [{“name”:”param_name1″,”value”:”param_value1″}, {“name”:”param_name2″,”value”:”param_value2″}]}’

显然,这种方式比较繁琐,很容易出现因格式不正确导致触发任务失败,而且这种方式不能帮助我们获取更多的关于job的信息以便于我们后续对job的状态进行跟踪。

Python-Jenkins

  
继续寻找,然后我在Jenkins官网上找到了Python-Jenkins API,仔细阅读后发现,它几乎涵盖了大部分Jenkins的操作,大大方便了我们在后台进行对Jenkins的一些列操作。

Python-Jenkins官网:https://pypi.python.org/pypi/python-jenkins/

Python-Jenkins Doc:http://python-jenkins.readthedocs.io/en/latest/index.html

下面简单介绍下如何使用Python-Jenkins:

1.安装

   sudo pip install python-jenkins

  
2.进入python命令环境或创建新的.py文件jenkinsApiTest.py

   import jenkins

     #定义远程的jenkins master server的url,以及port

     jenkins_server_url='xxxx:xxxx'

     #定义用户的User Id 和 API Token,获取方式同上文

     user_id='xxxx'

     api_token='xxxx'

   #实例化jenkins对象,连接远程的jenkins master server

   server=jenkins.Jenkins(jenkins_server_url, username=user_id, password=api_token)

   #构建job名为job_name的job(不带构建参数)

   server.build_job(job_name)

   #String参数化构建job名为job_name的job, 参数param_dict为字典形式,如:param_dict= {"param1":“value1”, “param2”:“value2”} 

   server.build_job(job_name, parameters=param_dict)

   #获取job名为job_name的job的相关信息

   server.get_job_info(job_name)

   #获取job名为job_name的job的最后次构建号

   server.get_job_info(job_name)['lastBuild']['number']

     #获取job名为job_name的job的某次构建的执行结果状态

   server.get_build_info(job_name,build_number)['result']     

     #判断job名为job_name的job的某次构建是否还在构建中

   server.get_build_info(job_name,build_number)['building']

3.更多其他的API可以参考Python-Jenkins API:http://python-jenkins.readthedocs.io/en/latest/api.html

使用Jenkins自动化部署Java项目

Jenkins介绍

Jenkins是领先的开源自动化服务器,他提供了数百个插件来支持任何项目的构建、部署和自动化。

Jenkins下载

Jenkins的官方网站|下载地址

wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war

Jenkins安装

  1. 启动Jenkins :java -jar jenkins.war
  2. 在浏览器中输入 localhost:8080
  3. 根据提示输入Jenkins的默认密码
  4. 安装建议的插件
  5. 创建admin用户
  6. 选择start using jenkins

Jenkins插件安装

rebuilder : 重新构建
safe restart: 安全重启

Jenkins基础配置

  • 配置全局安全属性
    在Configure Global Security中使用安装矩阵添加admin用户和test用户的权限

  • 添加自定义用户test01,并赋予test的用户权限

自动化部署项目

部署过程

  1. git同步最新代码
  2. 使用maven打包项目
  3. 停止tomcat服务器
  4. 部署项目
  5. 启动tomcat服务器

部署脚本

#!/usr/bin/env bash
#编译+部署order站点

#需要配置如下参数
# 项目路径, 在Execute Shell中配置项目路径, pwd 就可以获得该项目路径
# export PROJ_PATH=这个jenkins任务在部署机器上的路径

# 输入你的环境上tomcat的全路径
# export TOMCAT_APP_PATH=tomcat在部署机器上的路径

### base 函数
killTomcat()
{
    pid=`ps -ef|grep tomcat|grep java|awk '{print $2}'`
    echo "tomcat Id list :$pid"
    if [ "$pid" = "" ]
    then
      echo "no tomcat pid alive"
    else
      kill -9 $pid
    fi
}
cd $PROJ_PATH/order
mvn clean install

# 停tomcat
killTomcat

# 删除原有工程
rm -rf $TOMCAT_APP_PATH/webapps/ROOT
rm -f $TOMCAT_APP_PATH/webapps/ROOT.war
rm -f $TOMCAT_APP_PATH/webapps/order.war

# 复制新的工程
cp $PROJ_PATH/order/target/order.war $TOMCAT_APP_PATH/webapps/

cd $TOMCAT_APP_PATH/webapps/
mv order.war ROOT.war

# 启动Tomcat
cd $TOMCAT_APP_PATH/
sh bin/startup.sh

Jenkins部署任务

1.创建Jenkins任务

  • 输入Jenkins的任务名称
  • 选择构建一个自由风格的软件项目
  • 填写任务描述

2.填写Server信息
3. 配置git参数

  • 输入git地址
  • 在Additional Behaviours中选择Check out to a sub-directory并设置文件名为order

4.填写构建语句,部署环境

  • 在构建中添加构建步骤Execute shell
# 在Jenkins任务执行完毕之后只关闭Jenkins进程,不关闭Server进程,如果不设置Server也会被关闭
BUILD_ID=DONTKILLME
# 加载配置文件
. /etc/profile
# 配置运行参数
export RROJ_PATH=`pwd`
export TOMCAT_PATH=/root/apache-tomcat-9.0.8
# 运行部署脚本
sh $RROJ_PATH/order/deploy.sh
  • 点击立即构建

5.验证部署结果

使用浏览器访问192.168.100.133:8080验证项目是否部署成功

etcd集群故障处理

1. etcd安装

rpm -ivh etcd-3.2.15-1.el7.x86_64.rpm
systemctl daemon-reload
systemctl enable etcd
systemctl start etcd
export ETCDCTL_API=3
systemctl status etcd

hosts如下

192.168.0.100 etcd01
192.168.0.101 etcd02
192.168.0.102 etcd03

2. etcd配置

etcd02配置如下,详细见kubernetes1.9版本集群配置向导

# egrep -v "^$|^#" /etc/etcd/etcd.conf 
ETCD_DATA_DIR="/var/lib/etcd/"
ETCD_LISTEN_PEER_URLS="https://192.168.0.101:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.0.101:2379,http://127.0.0.1:2379"
ETCD_NAME="etcd02"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.0.101:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.0.101:2379"
ETCD_INITIAL_CLUSTER="etcd01=https://192.168.0.100:2380,etcd02=https://192.168.0.101:2380,etcd03=https://192.168.0.102:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="existing"
ETCD_CERT_FILE="/etc/kubernetes/ssl/etcd.pem"
ETCD_KEY_FILE="/etc/kubernetes/ssl/etcd-key.pem"
ETCD_CLIENT_CERT_AUTH="true"
ETCD_TRUSTED_CA_FILE="/etc/kubernetes/ssl/ca.pem"
ETCD_AUTO_TLS="true"
ETCD_PEER_CERT_FILE="/etc/kubernetes/ssl/etcd.pem"
ETCD_PEER_KEY_FILE="/etc/kubernetes/ssl/etcd-key.pem"
ETCD_PEER_CLIENT_CERT_AUTH="true"
ETCD_PEER_TRUSTED_CA_FILE="/etc/kubernetes/ssl/ca.pem"
ETCD_PEER_AUTO_TLS="true"

3. 故障报错

3个节点做集群,直接关机后,etcd02故障,报错:

etcd: advertise client URLs = https://192.168.0.101:2379
etcd: read wal error (wal: crc mismatch) and cannot be repaired
systemd: etcd.service: main process exited, code=exited, status=1/FAILURE

wal的cec校验出错,谷歌了一下,没什么结果,于是移除这个etcd,再恢复
在正常的etcd节点移除

# etcdctl member list
1ce6d6d01109192, started, etcd03, https://192.168.0.102:2380, https://192.168.0.102:2379
9b534175b46ea789, started, etcd01, https://192.168.0.100:2380, https://192.168.0.100:2379
ac2f188e97f50eb7, started, etcd02, https://192.168.0.101:2380, https://192.168.0.101:2379
# etcdctl member remove ac2f188e97f50eb7
Member ac2f188e97f50eb7 removed from cluster 194cd14a48430083

再启动etcd服务

# systemctl start etcd

报错:

etcd: error validating peerURLs {ClusterID:194cd14a48430083 Members:[&{ID:1ce6d6d01109192 RaftAttributes:{PeerURLs:[https://192.168.0.102:2380]} Attributes:{Name:etcd03 ClientURLs:[https://192.168.0.102:2379]}} &{ID:9b534175b46ea789 RaftAttributes:{PeerURLs:[https://192.168.0.100:2380]} Attributes:{Name:etcd01 ClientURLs:[https://192.168.0.100:2379]}}] RemovedMemberIDs:[]}: member count is unequal

报错:

etcd: the member has been permanently removed from the cluster the data-dir used by this member must be removed

4. etcd恢复数据

在etcd02节点恢复一下数据试试:

# mv /var/lib/etcd/member /var/lib/member
# rm -rf /var/lib/etcd/*
# etcdctl snapshot restore /var/lib/member/snap/db --skip-hash-check=true
2018-06-22 11:28:35.622666 I | mvcc: restore compact to 10177401
2018-06-22 11:28:35.659626 I | etcdserver/membership: added member 8e9e05c52164694d [http://localhost:2380] to cluster cdf818194e3a8c32
# systemctl start etcd

服务启动了,自己把自己选做主,服务倒是启动了,加入集群还是出错,用正常的节点备份再恢复

# etcdctl snapshot save etcdback.db
# etcdctl member add etcd02 http://192.168.0.101:2380
Error: member name not provided.

看看现在集群的其他2个etcd

# curl -k --key /etc/kubernetes/ssl/etcd-key.pem --cert /etc/kubernetes/ssl/etcd.pem https://192.168.0.100:2380/members
[{"id":130161754177048978,"peerURLs":["https://192.168.0.102:2380"],"name":"etcd03","clientURLs":["https://192.168.0.102:2379"]},{"id":11192361472739944329,"peerURLs":["https://192.168.0.100:2380"],"name":"etcd01","clientURLs":["https://192.168.0.100:2379"]}]

参考文档:

etcdctl member add etcd_name –peer-urls=”https://peerURLs”

再次添加

# etcdctl member add etcd02 --peer-urls="https://192.168.0.101:2380"
Member 41c2a7b938a5e387 added to cluster 194cd14a48430083

ETCD_NAME="etcd02"
ETCD_INITIAL_CLUSTER="etcd03=https://192.168.0.102:2380,etcd02=https://192.168.0.101:2380,etcd01=https://192.168.0.100:2380"
ETCD_INITIAL_CLUSTER_STATE="existing"

查看etcd member状态:

# etcdctl member list
1ce6d6d01109192, started, etcd03, https://192.168.0.102:2380, https://192.168.0.102:2379
9b534175b46ea789, started, etcd01, https://192.168.0.100:2380, https://192.168.0.100:2379
ad17c3da831c84c7, unstarted, , https://192.168.0.101:2380,

报错:

etcd: request cluster ID mismatch (got 194cd14a48430083 want cdf818194e3a8c32)

发现步骤顺序错误,应该是先添加到etcd集群,再启动etcd服务,我们现在先启动etcd服务,就是一个etcd单点

etcd节点加入集群

故障的etcd主机

# systemctl stop etcd

正常的etcd主机:

# etcdctl member remove ad17c3da831c84c7
# etcdctl member add etcd02 --peer-urls="https://192.168.0.101:2380"
Member 41c2a7b938a5e387 added to cluster 194cd14a48430083

ETCD_NAME="etcd02"
ETCD_INITIAL_CLUSTER="etcd03=https://192.168.0.102:2380,etcd02=https://192.168.0.101:2380,etcd01=https://192.168.0.100:2380"
ETCD_INITIAL_CLUSTER_STATE="existing"

故障的etcd主机,查看现在etcd状态:

# etcdctl endpoint health
127.0.0.1:2379 is healthy: successfully committed proposal: took = 24.52485ms
# etcdctl member list
1ce6d6d01109192, started, etcd03, https://192.168.0.102:2380, https://192.168.0.102:2379
41c2a7b938a5e387, started, etcd02, https://192.168.0.101:2380, https://192.168.0.101:2379
9b534175b46ea789, started, etcd01, https://192.168.0.100:2380, https://192.168.0.100:2379

到这里,etcd故障修复完毕

5. etcd常用命令

查看状态

# export ETCDCTL_API=3

# etcdctl endpoint status --write-out=table
+----------------+------------------+---------+---------+-----------+-----------+------------+
|    ENDPOINT    |        ID        | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+----------------+------------------+---------+---------+-----------+-----------+------------+
| 127.0.0.1:2379 | 41c2a7b938a5e387 |  3.2.15 |   15 MB |      true |       317 |   11051403 |
+----------------+------------------+---------+---------+-----------+-----------+------------+

备份及恢复

etcdctl snapshot save etcdback.db
etcdctl snapshot status etcdback.db --write-out=table
etcdctl snapshot restore etcdback.db --skip-hash-check=true

etcd监控

# curl -L http://localhost:2379/metrics
# HELP etcd_debugging_mvcc_keys_total Total number of keys.
# TYPE etcd_debugging_mvcc_keys_total gauge
etcd_debugging_mvcc_keys_total 776
# HELP etcd_debugging_mvcc_pending_events_total Total number of pending events to be sent.
# TYPE etcd_debugging_mvcc_pending_events_total gauge
etcd_debugging_mvcc_pending_events_total 0
# HELP etcd_debugging_mvcc_put_total Total number of puts seen by this member.
# TYPE etcd_debugging_mvcc_put_total counter
etcd_debugging_mvcc_put_total 9.548201e+06
# HELP etcd_debugging_mvcc_range_total Total number of ranges seen by this member.
# TYPE etcd_debugging_mvcc_range_total counter
etcd_debugging_mvcc_range_total 2.1052143e+07
# HELP etcd_debugging_mvcc_slow_watcher_total Total number of unsynced slow watchers.
# TYPE etcd_debugging_mvcc_slow_watcher_total gauge
etcd_debugging_mvcc_slow_watcher_total 0
# HELP etcd_debugging_mvcc_txn_total Total number of txns seen by this member.
# TYPE etcd_debugging_mvcc_txn_total counter
etcd_debugging_mvcc_txn_total 0
# HELP etcd_debugging_mvcc_watch_stream_total Total number of watch streams.
# TYPE etcd_debugging_mvcc_watch_stream_total gauge
etcd_debugging_mvcc_watch_stream_total 125
# HELP etcd_debugging_mvcc_watcher_total Total number of watchers.
# TYPE etcd_debugging_mvcc_watcher_total gauge
etcd_debugging_mvcc_watcher_total 125
# HELP etcd_debugging_server_lease_expired_total The total number of expired leases.
# TYPE etcd_debugging_server_lease_expired_total counter
etcd_debugging_server_lease_expired_total 3649

适合用prometheus监控

global:
  scrape_interval: 10s
scrape_configs:
  - job_name: etcd
    static_configs:
    - targets: ['192.168.0.100:2379','192.168.0.101:2379','192.168.0.102:2379']

图解raft算法 http://thesecretlivesofdata.com/raft/

etcd获取kubernetes的数据

# export ETCDCTL_API=3
# etcdctl get /registry/namespaces/default --prefix -w json|python -m json.tool
{
    "count": 1,
    "header": {
        "cluster_id": 1823062066148343939,
        "member_id": 11192361472739944329,
        "raft_term": 317,
        "revision": 10880816
    },
    "kvs": [
        {
            "create_revision": 6,
            "key": "L3JlZ2lzdHJ5L25hbWVzcGFjZXMvZGVmYXVsdA==",
            "mod_revision": 6,
            "value": "azhzAAoPCgJ2MRIJTmFtZXNwYWNlEl8KRQoHZGVmYXVsdBIAGgAiACokOTVlNzdjMWEtM2Q1Ny0xMWU4LTk5YzItMDA1MDU2YmU3NWEzMgA4AEIICK7qttYFEAB6ABIMCgprdWJlcm5ldGVzGggKBkFjdGl2ZRoAIgA=",
            "version": 1
        }
    ]
}
查看key的内容
# echo L3JlZ2lzdHJ5L25hbWVzcGFjZXMvZGVmYXVsdA== |base64 -d
/registry/namespaces/default
#!/bin/bash
# Get kubernetes keys from etcd
export ETCDCTL_API=3
keys=`etcdctl get /registry --prefix -w json|python -m json.tool|grep key|cut -d ":" -f2|tr -d '"'|tr -d ","`
for x in $keys;do
  echo $x|base64 -d|sort
done

获取etcd中kubernetes所有对象的key

【网页加速】lua redis的二次升级

之前发过openresty的相关文章,也是用于加速网页速度的,但是上次没有优化好代码,这次整理了下,优化了nginx的配置和lua的代码,感兴趣的话可以看看上篇的文章:
https://www.cnblogs.com/w1570631036/p/8449373.html

为了学习,不断的给自己的服务器装东西,又是logstash,又是kafka,导致主站网络负载、cpu消耗过大,再加上tomcat这个本身就特别占用内存的东西,只要稍微刷新一下网站,就能感受到蜗牛般的速度,实在受不了,前段时间给网站加了n多层缓存,依旧没有改观多少,想了想,算了,一直都这么卡,还不如直接将动态的网站直接变成静态网页存储在redis里面,然后关掉tomcat,貌似没有改观多少,但是在xshell里面敲命令没那么卡了,这里,也提出了一种别样的网站加速方法——redis存储静态网页。
未分类

一、总体流程如下

未分类
1.一次请求过来,通过openresty的nginx来访问lua脚本;
2.读取redis中是否存在该uri对应的静态网页,如果有,则直接返回,否则回源到tomcat,然后将响应的内容保存到redis里面。

二、nginx的设置

openresty中自带了nginx,所以只需要配置一下即可,我们最终的目前是拦截所有以html结尾的请求,如果是以其他后缀结尾的,比如do,则可以直接回滚到tomat里面去。
由于篇幅的关系,只粘贴部分nginx配置,想看全的请转至:mynginxconfig.ngx

server {
    listen       80;
    # listen       443 ssl;   # ssl
    server_name  www.wenzhihuai.com;
    location  ~ .*.(html)$ {       //拦截所有以html结尾的请求,调用lua脚本
        ...
        charset utf8;
        proxy_pass_request_headers off ;
        # 关闭缓存lua脚本,调试的时候专用
        lua_code_cache off;
        content_by_lua_file /opt/lua/hello.lua;
    }
    location / {        //nginx是按顺序匹配的,如果上面的不符合,那么将回滚tomcat
        default_type    text/html;
        root   html;
        index  index.html index.htm;
        ...
        # websocket
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_pass http://backend;
    }

三、lua脚本

为了方便key的操作,经过测试,即使uri带有各种字符,比如 ? . html = &等,都是可以直接设置为redis中的key的,所以,不是那么的需要考虑redis的key违反规则,可以直接将uri设置为key。具体流程如下:

local key = request_uri
首先,key为请求访问的uri
local resp, err = red:get(key)
去redis上查找有没有
if resp == ngx.null then
    如果没有
    ngx.req.set_header("Accept", "text/html,application/xhtml+xml,application/xml;")
    ngx.req.set_header("Accept-Encoding", "")
    这里,特别需要注意的是,要把头部的信息去掉,这里之前说过。(如果不去掉,就是gzip加密返回,然后再经过一层gzip加密返回给用户,导致用户看到的是gzip压缩过的乱码)
    local targetURL = string.gsub(uri, "html", "do")
    这里讲html替换为do,即:不拦截*.do的请求,其可以直接访问tomcat
    local respp = ngx.location.capture(targetURL, { method = ngx.HTTP_GET, args = uri_args })
    开始回源到tomcat
    red:set(key, respp.body)
    将uri(key)和响应的内容设到redis里面去
    red:expire(key, 600)
    lua redis并没有提供在set的时候同时设置过期时间,所以,额外加一行设置过期时间
    ngx.print(respp.body)
    将响应的内容输出给用户
    return
end
ngx.print(resp)

四、测试

进行一次测试,以访问http://www.wenzhihuai.com/jaowejoifjefoijoifaew.html 为例,我的网站并没有设置这个uri,所以,访问的时候,会统一调到错误页面,之后,会在redis中看到有这条记录:
未分类
该地址已经成功被缓存到redis里面去,点击其他页面,可以看到,只要是点击的页面,都被缓存到redis里面去了。总体来说,如果不设置过期时间,可以把整个网页静态化缓存到redis里面,甚至是可以关闭tomcat了,但是这种做法只适用于万年不变的页面,至于用于企业的话,,,,

后记:
其实我有个疑问,我的代码里,并没有设置lua断开redis的连接,不知道会不会有影响,而且它这个是指每次请求过来,都需要重新连接redis么?光是TCP三次握手就耗时不少啊,不知道怎么优化这些信息。

全部代码如下:

local redis = require "resty.redis"
local red = redis:new()
local request_uri = ngx.var.request_uri
local ngx_log = ngx.log
local ngx_ERR = ngx.ERR

local function close_redis(red)
    if not red then
        return
    end
    local pool_max_idle_time = 10000
    local pool_size = 100
    red:set("pool_size", pool_size)
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
    if not ok then
        ngx_log(ngx_ERR, "set redis keepalive error : ", err)
    end
end

local uri = ngx.var.uri

red:set_timeout(1000)
red:connect("119.23.46.71", 6340)
red:auth("root")
local uri_args = ngx.req.get_uri_args()

local key = request_uri
local resp, err = red:get(key)

if resp == ngx.null then
    ngx.req.set_header("Accept", "text/html,application/xhtml+xml,application/xml;")
    ngx.req.set_header("Accept-Encoding", "")
    local targetURL = string.gsub(uri, "html", "do")
    local respp = ngx.location.capture(targetURL, { method = ngx.HTTP_GET, args = uri_args })
    red:set(key, respp.body)
    red:expire(key, 600)
    ngx.print(respp.body)
    return
end
ngx.print(resp)
close_redis(red)

ETCD数据库异常:mvcc: database space exceeded解决

ETCD数据库异常:mvcc: database space exceeded解决

  • 问题来源:在k8s集群中给node打标签发现报错
[root@master1]# kubectl label node  30.4.228.20 env=prod
Error from server: etcdserver: mvcc: database space exceeded
  • 环境信息
etcd集群:30.4.228.19,30.4.228.20,30.4.228.22 (配置了安全加密)

原因分析

  • etcd服务未设置自动压缩参数(auto-compact)
  • etcd 默认不会自动 compact,需要设置启动参数,或者通过命令进行compact,如果变更频繁建议设置,否则会导致空间和内存的浪费以及错误。Etcd v3 的默认的 backend quota 2GB,如果不 compact,boltdb 文件大小超过这个限制后,就会报错:”Error: etcdserver: mvcc: database space exceeded”,导致数据无法写入。

处理过程

1、 获取旧版本号:

[root@etcd1]# rev=$(/usr/local/bin/etcdctl --cacert=/etc/kubernetes/ssl/ca.pem 
--cert=/etc/etcd/ssl/etcd.pem  
--key=/etc/etcd/ssl/etcd-key.pem  
--endpoints="https://127.0.0.1:2379" 
endpoint status --write-out="json"  
| egrep -o '"revision":[0-9]*'  
| egrep -o '[0-9].*') 

[root@etcd1]# echo $rev 

2 、压缩旧版本

[root@etcd1]# /usr/local/bin/etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints="https://30.4.228.20:2379" compact $rev

[root@etcd1]# /usr/local/bin/etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints="https://30.4.228.20:2379" defrag 

[root@etcd1]# /usr/local/bin/etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints="https://30.4.228.20:2379" alarm list 

[root@etcd1]# /usr/local/bin/etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints="https://30.4.228.19:2379" compact $rev

[root@etcd1]# /usr/local/bin/etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints="https://30.4.228.19:2379" defrag 

[root@etcd1]# /usr/local/bin/etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints="https://30.4.228.22:2379" compact $rev

[root@etcd1]# /usr/local/bin/etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints="https://30.4.228.22:2379" defrag 

[root@etcd1]# /usr/local/bin/etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints="https://30.4.228.22:2379" alarm list 

[root@etcd1]# /usr/local/bin/etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints="https://30.4.228.22:2379" alarm disarm

3、查看告警

[root@etcd1]# /usr/local/bin/etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints="https://30.4.228.22:2379" alarm list

[root@etcd1]#  /usr/local/bin/etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints="https://30.4.228.19:2379" alarm list 

[root@etcd1]# /usr/local/bin/etcdctl --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints="https://30.4.228.20:2379" alarm list

etcd相关命令

1、设置etcd配额:

# 设置16MB的配额
etcd --quota-backend-bytes=$((16*1024*1024))

2、触发配额耗尽:

while [1];do dd if=dev/urandom bs=1024 count=1024 
 | ETCDCTL_API=3 etcdctl put key || break; done
...
Error: rpc error: code = 8 desc = etcdserver: mvcc:database space exceeded

3、确认数据空间超出配额:

ETCDCTL_API=3 etcdctl --write-out=table endpoint status
----------------+------------------+-----------+---------+-----------+-----------+------------+
|    ENDPOINT    |        ID        |  VERSION  | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+----------------+------------------+-----------+---------+-----------+-----------+------------+
| 127.0.0.1:2379 | bf9071f4639c75cc | 2.3.0+git | 18 MB   | true      |         2 |       3332 |
+----------------+------------------+-----------+---------+-----------+-----------+------------+

4、查看告警:

ETCDCTL_API=3 etcdctl alarm list

5、整合压缩、碎片整理:

1) 获取当前etcd数据的修订版本(revision)

rev=$(ETCDCTL_API=3 etcdctl --endpoints=:2379 endpoint status --write-out="json" | egrep -o '"revision":[0-9]*' | egrep -o '[0-9]*')

2) 整合压缩旧版本数据

ETCDCTL_API=3 etcdctl compact $rev

3) 执行碎片整理

ETCDCTL_API=3 etcdctl defrag

4) 解除告警

ETCDCTL_API=3 etcdctl alarm disarm

5) 备份以及查看备份数据信息

ETCDCTL_API=3 etcdctl snapshot save backup.db
ETCDCTL_API=3 etcdctl snapshot status backup.db

linux下源码安装redis

redis官方下载网址: https://redis.io/download

安装目录: /usr/local/bin/
配置文件路径: /etc/redis/redis.conf
配置端口: 6379
服务端: /usr/local/bin/redis-server
客户端: /usr/local/bin/redis-cli
持久化文件存放目录路径: /var/lib/redis
pid路径: /var/run/redis.pid
日志路径: /var/log/redis.log

1. centos下安装redis

以centos7.4为例.

1.1. 源码编译安装

$ mkdir ~/soft
$ cd ~/soft
$ wget -c http://download.redis.io/releases/redis-4.0.10.tar.gz
$ tar xzf redis-4.0.10.tar.gz
$ cd redis-4.0.10
$ make
$ sudo make install

1.2. 添加服务并添加到开机自启动

$ cd ~/soft/redis-4.0.10/utils
$ sudo ./install_server.sh
Welcome to the redis service installer
This script will help you easily set up a running redis server
Please select the redis port for this instance: [6379] 
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf] /etc/redis/redis.conf
Please select the redis log file name [/var/log/redis_6379.log] /var/log/redis.log
Please select the data directory for this instance [/var/lib/redis/6379] /var/lib/redis
Please select the redis executable path [] /usr/local/bin/redis-server
Selected config:
Port : 6379
Config file : /etc/redis/redis.conf
Log file : /var/log/redis.log
Data dir : /var/lib/redis
Executable : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
$ 

1.3. 创建redis用户及其用户组并给相应目录授权

$ sudo useradd --r --U -M redis
$ sudo chown redis:redis /var/lib/redis
$ sudo chmod 770 /var/lib/redis

1.4. 修改服务名及配置文件

重命名服务名redis_6379为redis, 在此之前先停止服务:

$ sudo /etc/init.d/redis_6379 stop
$ sudo mv /etc/init.d/redis_6379 /etc/init.d/redis
$ sudo vim /etc/init.d/redis

将文件内的redis_6379替换为redis, vim按ESC切换到命令模式, 替换后保存退出vim

:%s/redis_6379/redis/g
:wq

编辑配置文件/etc/redis/redis.conf:

$ sudo vim /etc/redis/redis.conf
. . . 
daemonize yes
. . . 
supervised systemd
. . . 
pidfile /var/run/redis.pid
. . . 
logfile /var/log/redis.log
. . . 
dir /var/lib/redis

将文件内的redis_6379替换为redis, vim按ESC切换到命令模式, 替换后保存退出vim

:%s/redis_6379/redis/g
:wq

1.5. redis服务管理

$ sudo systemctl daemon-reload
$ sudo systemctl enable redis
$ sudo systemctl status redis
● redis.service - LSB: start and stop redis
   Loaded: loaded (/etc/rc.d/init.d/redis; bad; vendor preset: disabled)
   Active: inactive (dead) since 五 2018-06-22 14:48:36 CST; 7s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 21946 ExecStop=/etc/rc.d/init.d/redis stop (code=exited, status=0/SUCCESS)
  Process: 21909 ExecStart=/etc/rc.d/init.d/redis start (code=exited, status=0/SUCCESS)
6月 22 14:24:50 izm5eat3t2va6ch6mdbpbtz systemd[1]: Starting LSB: start and ...
6月 22 14:24:50 izm5eat3t2va6ch6mdbpbtz redis[21909]: Starting Redis server...
6月 22 14:24:50 izm5eat3t2va6ch6mdbpbtz systemd[1]: Started LSB: start and s...
6月 22 14:48:36 izm5eat3t2va6ch6mdbpbtz systemd[1]: Stopping LSB: start and ...
6月 22 14:48:36 izm5eat3t2va6ch6mdbpbtz redis[21946]: /var/run/redis.pid doe...
6月 22 14:48:36 izm5eat3t2va6ch6mdbpbtz systemd[1]: Stopped LSB: start and s...
Hint: Some lines were ellipsized, use -l to show in full.
$ sudo systemctl start redis
● redis.service - LSB: start and stop redis
   Loaded: loaded (/etc/rc.d/init.d/redis; bad; vendor preset: disabled)
   Active: active (exited) since 五 2018-06-22 14:24:50 CST; 5s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 21909 ExecStart=/etc/rc.d/init.d/redis start (code=exited, status=0/SUCCESS)
6月 22 14:24:50 izm5eat3t2va6ch6mdbpbtz systemd[1]: Starting LSB: start and ...
6月 22 14:24:50 izm5eat3t2va6ch6mdbpbtz redis[21909]: Starting Redis server...
6月 22 14:24:50 izm5eat3t2va6ch6mdbpbtz systemd[1]: Started LSB: start and s...
Hint: Some lines were ellipsized, use -l to show in full.

开启服务: sudo systemctl start redis
停止服务: sudo systemctl stop redis
重启服务: sudo systemctl restart redis
查看进程: sudo lsof -i:6379
杀掉进程: sudo kill -9 pid
进入redis shell: redis-cli

2. ubuntu下安装redis

以ubuntu16.04为例.

源码安装步骤与centos的基本相同。