[{"body":"","link":"http://test.mylass.com/","section":"","tags":null,"title":""},{"body":"","link":"http://test.mylass.com/database/","section":"database","tags":null,"title":"Databases"},{"body":"","link":"http://test.mylass.com/tags/mysql/","section":"tags","tags":null,"title":"mysql"},{"body":"","link":"http://test.mylass.com/series/","section":"series","tags":null,"title":"Series"},{"body":"","link":"http://test.mylass.com/tags/","section":"tags","tags":null,"title":"Tags"},{"body":"","link":"http://test.mylass.com/tags/zabbix/","section":"tags","tags":null,"title":"zabbix"},{"body":"","link":"http://test.mylass.com/series/zabbix/","section":"series","tags":null,"title":"zabbix"},{"body":"近期由于需要缩减机器的配置，以减少配置，需要导出数 zabbix 的些监控数据，以评估服务器的CPU和内存使用情况，做缩减。\n美中不足的 zabbix 的web管理虽然可以查询指定时间的历史数据，但是没有导出报表的功能。\n不过官方提供的 API，可以使用API导出。当然也可以查询数据库中的值，来做分析，目前网上也有多小工具，也是基于这两种方法来做的。\n对于使用过zabbix的同学，我想应该都知道大概原理，不是通过agent或者snmp 收集数据，之后存储的数据中，同时在前台页面展示。\n监控数据主要分为两类，一个是历史数据记录，也就是history之类的表，通过这个表可以查询到相关监控项目的数据。\n另外一个就是趋势数据，是zabbix通过计算（数据来源为history_unit）。\n获取相对应的主机ID 1SELECT hostid,host FROM hosts WHERE host = \u0026#39;b-live-kafka-01\u0026#39;; 2+--------+-----------------+ 3| hostid | host | 4+--------+-----------------+ 5| 10302 | b-live-kafka-01 | 6+--------+-----------------+ 通过 hostid 查询到相当监控项目的id和名称，由于数据过多，使用 LIKE 过滤一下 1SELECT itemid, key_ FROM items WHERE hostid = \u0026#39;10302\u0026#39; AND key_ LIKE \u0026#39;%cpu%\u0026#39;; 2+--------+------------------------------+ 3| itemid | key_ | 4+--------+------------------------------+ 5| 30869 | system.cpu.intr | 6| 30870 | system.cpu.load[all,avg15] | 7| 30871 | system.cpu.load[all,avg1] | 8| 30872 | system.cpu.load[all,avg5] | 9| 130324 | system.cpu.num | 10| 30873 | system.cpu.switches | 11| 30874 | system.cpu.util[,guest] | 12| 30875 | system.cpu.util[,guest_nice] | 13| 30876 | system.cpu.util[,idle] | 14| 30877 | system.cpu.util[,interrupt] | 15| 30878 | system.cpu.util[,iowait] | 16| 30879 | system.cpu.util[,nice] | 17| 30880 | system.cpu.util[,softirq] | 18| 30881 | system.cpu.util[,steal] | 19| 30882 | system.cpu.util[,system] | 20| 30883 | system.cpu.util[,user] | 21+--------+------------------------------+ 2216 rows in set (0.00 sec) 可以看到有很多监控项，由于在历史记录的表中，通过监控项id来查找数据，获取cpu使用率的itemid 1SELECT itemid, key_ FROM items WHERE hostid = \u0026#39;10302\u0026#39; AND key_ = \u0026#39;system.cpu.util[,idle]\u0026#39;; 2+--------+------------------------+ 3| itemid | key_ | 4+--------+------------------------+ 5| 30876 | system.cpu.util[,idle] | 6+--------+------------------------+ 71 row in set (0.00 sec) 通过 itemid 来查找监控记录， 使用 system.cpu.util[,idle]， 这个是CPU空闲率，用100减去这个值，查询最前的20条数据\n1SELECT FROM_UNIXTIME(clock) AS time, 2 100 - value_min AS Min, 3 100 - value_max AS Max, 4 100 - value_avg AS Avg 5FROM trends WHERE itemid = 30876 6ORDER BY clock DESC LIMIT 20; 7+---------------------+---------+--------+---------+ 8| time | Min | Max | Avg | 9+---------------------+---------+--------+---------+ 10| 2022-08-28 08:00:00 | 22.0083 | 3.0211 | 9.8478 | 11| 2022-08-28 07:00:00 | 20.9520 | 2.5756 | 7.8344 | 12| 2022-08-28 06:00:00 | 15.0965 | 2.9327 | 7.9170 | 13| 2022-08-28 05:00:00 | 12.4462 | 2.7913 | 5.7385 | 14| 2022-08-28 04:00:00 | 72.5317 | 3.4075 | 8.6970 | 15| 2022-08-28 03:00:00 | 26.3472 | 3.6292 | 7.8114 | 16| 2022-08-28 02:00:00 | 16.1904 | 3.4179 | 9.3516 | 17| 2022-08-28 01:00:00 | 19.1819 | 7.1658 | 10.9278 | 18| 2022-08-28 00:00:00 | 13.1924 | 3.9569 | 8.2620 | 19| 2022-08-27 23:00:00 | 15.2952 | 4.0299 | 7.3377 | 20| 2022-08-27 22:00:00 | 14.8313 | 5.8909 | 9.1118 | 21| 2022-08-27 21:00:00 | 15.3385 | 4.3806 | 7.8885 | 22| 2022-08-27 20:00:00 | 11.9476 | 4.3139 | 7.7731 | 23| 2022-08-27 19:00:00 | 14.0114 | 4.1177 | 9.1797 | 24| 2022-08-27 18:00:00 | 12.0893 | 4.7092 | 8.3353 | 25| 2022-08-27 17:00:00 | 19.0263 | 3.7427 | 11.2143 | 26| 2022-08-27 16:00:00 | 21.2013 | 9.8987 | 13.9991 | 27| 2022-08-27 15:00:00 | 17.9462 | 9.3643 | 12.9202 | 28| 2022-08-27 14:00:00 | 28.8963 | 7.9107 | 11.8968 | 29| 2022-08-27 13:00:00 | 22.9940 | 9.1483 | 14.9234 | 30+---------------------+---------+--------+---------+ 3120 rows in set (0.00 sec) 指定时间范围查询。 比如最近30天的CPU的最大值，最小值，平均值，保留两位小数，通过表中 clock 列来限制范围，30天是 2592000 秒。\n1SELECT ROUND(MIN(100 - value_min),2) AS Min, 2 ROUND(MAX(100 - value_max),2) AS Max, 3 ROUND(AVG(100 - value_avg),2) AS Avg 4FROM trends 5WHERE 6 itemid = 30876 AND clock \u0026gt;= UNIX_TIMESTAMP() - 2592000; 7+------+-------+-------+ 8| Min | Max | Avg | 9+------+-------+-------+ 10| 7.86 | 39.48 | 14.69 | 11+------+-------+-------+ 121 row in set (0.00 sec) 组合SQL语句，合并查询， 主机名称为 b-live-kafka-01\n1SELECT c.host, ROUND(MIN(100 - value_min),2) AS Min, 2 ROUND(MAX(100 - value_max),2) AS Max, 3 ROUND(AVG(100 - value_avg),2) AS Avg 4FROM trends a 5 JOIN items b ON a.itemid=b.itemid AND key_ = \u0026#39;system.cpu.util[,idle]\u0026#39; 6 JOIN hosts c ON c.hostid=b.hostid AND host = \u0026#39;b-live-kafka-01\u0026#39; 7WHERE a.clock \u0026gt;= UNIX_TIMESTAMP() - 2592000; 8+-----------------+------+-------+-------+ 9| host | Min | Max | Avg | 10+-----------------+------+-------+-------+ 11| b-live-kafka-01 | 7.86 | 39.48 | 14.67 | 12+-----------------+------+-------+-------+ 至此，最近30天的数据，已经查询到了，内存使用率的方法也是一样，区别就是表不一样，CPU的在历史数据在趋势表(trends)中，内存的历史数据在history_uint。\n查询最近30天的内存使用 zabbix 在数据库中，并没有存储内存的百分比，所以需要通过 已用内存 / 总内存 *100 来计算百分比使用率。\n主机名还是为 b-live-kafka-01\n1SELECT a.host, ROUND(Max / total_value * 100, 2) AS MEM FROM ( 2 SELECT c.host, 3 MAX(a.value) AS Max 4 FROM history_uint a 5 join items b ON a.itemid = b.itemid 6 join hosts c ON c.hostid = b.hostid 7 WHERE b.key_ = \u0026#39;vm.memory.size[available]\u0026#39; 8 AND c.host = \u0026#39;b-live-kafka-01\u0026#39; 9 AND a.clock \u0026gt;= UNIX_TIMESTAMP() - (86400 * 30) 10) a JOIN ( 11 SELECT c.host, 12 a.value AS total_value 13 FROM history_uint a 14 join items b ON a.itemid = b.itemid 15 join hosts c ON c.hostid = b.hostid 16 WHERE b.key_ = \u0026#39;vm.memory.size[total]\u0026#39; 17 AND c.host = \u0026#39;b-live-kafka-01\u0026#39; 18 ORDER BY clock DESC LIMIT 1 19) b ON a.host = b.host; 20+-----------------+-------+ 21| host | MEM | 22+-----------------+-------+ 23| b-live-kafka-01 | 32.96 | 24+-----------------+-------+ 251 row in set (0.06 sec) 查询指定主机组内的主机使用率，时间也是最近30天 1SELECT FROM_UNIXTIME(t.clock) AS time, 2 grp.name AS GroupName, 3 h.host as Host, 4 100 - t.value_avg AS CpuAVG 5FROM hosts_groups a 6 JOIN hstgrp grp ON grp.groupid = a.groupid 7 JOIN items b on b.hostid = a.hostid 8 JOIN hosts h ON h.hostid = b.hostid 9 JOIN trends t ON t.itemid = b.itemid 10WHERE grp.name = \u0026#39;common-group\u0026#39; 11 AND b.key_ = \u0026#39;system.cpu.util[,idle]\u0026#39; 12 AND clock \u0026lt;= UNIX_TIMESTAMP() AND clock \u0026gt;= UNIX_TIMESTAMP() - 2592000 13 GROUP BY h.host,t.clock ORDER BY t.clock DESC LIMIT 5; 14+---------------------+-------------------+-------+---------+ 15| time | GroupName | Host | CpuAVG | 16+---------------------+-------------------+-------+---------+ 17| 2022-08-28 23:00:00 | common-group | zk01 | 3.0861 | 18| 2022-08-28 23:00:00 | common-group | rabbitmq01 | 5.0272 | 19| 2022-08-28 23:00:00 | common-group | monitor | 2.6925 | 20| 2022-08-28 23:00:00 | common-group | zk03 | 3.2457 | 21| 2022-08-28 23:00:00 | common-group | kafka01 | 3.5372 | 22+---------------------+-------------------+-------+---------+ ","link":"http://test.mylass.com/database/zabbix-history-data-query/","section":"database","tags":["zabbix","mysql"],"title":"通过SQL查询zabbix历史数据"},{"body":"","link":"http://test.mylass.com/tags/kafka/","section":"tags","tags":null,"title":"kafka"},{"body":"本命令所使用版本为 2.6.0， 其它版本也类似，参考即可\n指定topic保存消息策略为1天\n1/data/kafka_2.12-2.6.0/bin/kafka-configs.sh \\ 2--zookeeper zk01.mylass.com:2181,zk02.mylass.com:2181,zk03.mylass.com:2181/kafka2 \\ 3--entity-type topics \\ 4--entity-name topic-name \\ 5--alter \\ 6--add-config retention.ms=86400000 查看添加的配置\n1/data/kafka_2.12-2.6.0/bin/kafka-configs.sh \\ 2--zookeeper zk01.mylass.com:2181,zk02.mylass.com:2181,zk03.mylass.com:2181/kafka2 \\ 3--entity-type topics \\ 4--entity-name topic-name \\ 5--describe 删除配置，修改可以直接使用添加的命令，同一个配置，后面会覆盖掉前面的\n1/data/kafka_2.12-2.6.0/bin/kafka-configs.sh \\ 2--zookeeper zk01.mylass.com:2181,zk02.mylass.com:2181,zk03.mylass.com:2181/kafka2 \\ 3--entity-type topics \\ 4--entity-name topic-name \\ 5--alter \\ 6--delete-config retention.ms 查看topic 占用磁盘空间。 所有分区+所有副本的全部占用空间，单位是字节 (byte)，大小是包含了元数据的，不仅仅是消息大小\n1/data/kafka_2.12-2.6.0/bin/kafka-log-dirs.sh \\ 2--bootstrap-server 10.0.24.3:9092 \\ 3--topic-list topic-name \\ 4--describe \\ 5--command-config /data/kafka_2.12-2.6.0/config/group.properties | grep -oP \\ 6\u0026#39;(?\u0026lt;=size\u0026#34;:)\\d+\u0026#39; | awk \u0026#39;{ sum += $1 } END { print sum }\u0026#39; 查看所有 groupd 积压情况\n1/data/kafka_2.12-2.6.0/bin/kafka-consumer-groups.sh \\ 2--bootstrap-server 10.0.24.3:9092 \\ 3--all-groups \\ 4--describe \\ 5--command-config /data2/kafka_2.12-2.6.0/config/group.properties PS: 最后两个例子，使用 --bootstrap-server 的情况下，由于本例中是使用的带有 SASL 认证的 kafka， 所以需要 --command-config 指定认证信息。对于没有使用的SASL的，可以删除该参数。\n","link":"http://test.mylass.com/linux/kafka-command/","section":"linux","tags":["kafka"],"title":"kafka 操作相关命令记录"},{"body":"","link":"http://test.mylass.com/series/kfaka/","section":"series","tags":null,"title":"kfaka"},{"body":"","link":"http://test.mylass.com/linux/","section":"linux","tags":null,"title":"Linuxes"},{"body":"","link":"http://test.mylass.com/tags/java/","section":"tags","tags":null,"title":"java"},{"body":"以下是程序\n1import java.util.Properties; 2import java.util.Date; 3import java.text.SimpleDateFormat; 4import java.util.concurrent.ExecutionException; 5 6import org.apache.kafka.clients.CommonClientConfigs; 7import org.apache.kafka.clients.producer.KafkaProducer; 8import org.apache.kafka.clients.producer.ProducerConfig; 9import org.apache.kafka.clients.producer.ProducerRecord; 10import org.apache.kafka.clients.producer.RecordMetadata; 11import org.apache.kafka.common.config.SaslConfigs; 12import org.apache.kafka.common.config.SslConfigs; 13import org.apache.kafka.common.serialization.StringSerializer; 14 15public class MyProducer_9093 { 16 public static String topic = \u0026#34;ssl-test\u0026#34;; 17 public static String bootstrap_server = \u0026#34;test.ifmx.cc:9093\u0026#34;; 18 public static String truststore_jks = \u0026#34;M:\\\\mm\\\\ssl_kafka\\\\src\\\\main\\\\java\\\\kafka_uat_client_truststore.jks\u0026#34;; 19 20 public static void main(String[] args) throws InterruptedException { 21 Properties p = new Properties(); 22 p.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrap_server); 23 p.put(ProducerConfig.ACKS_CONFIG, \u0026#34;1\u0026#34;); 24 p.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); 25 p.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); 26 27 p.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, \u0026#34;SASL_SSL\u0026#34;); 28 p.put(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG, truststore_jks); 29 p.put(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, \u0026#34;FlashKafkaSSL212\u0026#34;); 30 p.put(SaslConfigs.SASL_MECHANISM, \u0026#34;SCRAM-SHA-512\u0026#34;); 31 p.put(SaslConfigs.SASL_JAAS_CONFIG, 32 \u0026#34;org.apache.kafka.common.security.scram.ScramLoginModule required username=\\\u0026#34;multi-redis-sync\\\u0026#34; password=\\\u0026#34;pangoo.redis@sync1\\\u0026#34;;\u0026#34;); 33 p.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, \u0026#34;\u0026#34;); 34 35 36// p.put(\u0026#34;security.protocol\u0026#34;,\u0026#34;SASL_SSL\u0026#34;); 37// p.put(\u0026#34;ssl.truststore.location\u0026#34;, truststore_jks); 38// p.put(\u0026#34;ssl.truststore.password\u0026#34;,\u0026#34;FlashKafkaSSL212\u0026#34;); 39// p.put(\u0026#34;sasl.mechanism\u0026#34;,\u0026#34;SCRAM-SHA-512\u0026#34;); 40// p.put(\u0026#34;ssl.endpoint.identification.algorithm\u0026#34;,\u0026#34;\u0026#34;); 41// p.put(\u0026#34;sasl.jaas.config\u0026#34;, 42// \u0026#34;org.apache.kafka.common.security.scram.ScramLoginModule required username=\\\u0026#34;multi-redis-sync\\\u0026#34; password=\\\u0026#34;pangoo.redis@sync1\\\u0026#34;;\u0026#34;); 43 44 try (KafkaProducer\u0026lt;String, String\u0026gt; kafkaProducer = new KafkaProducer\u0026lt;\u0026gt;(p)) { 45 for (int x = 0; x \u0026lt; 10; x = x + 1) { 46 Date dNow = new Date(); 47 SimpleDateFormat ft = new SimpleDateFormat(\u0026#34;yyyy-MM-dd HH:mm:ss\u0026#34;); 48 String msg = x + \u0026#34; Hello, SASL_SSL Producer message.\u0026#34; + x + \u0026#34; time: \u0026#34; + ft.format(dNow); 49 50 ProducerRecord\u0026lt;String, String\u0026gt; record = new ProducerRecord\u0026lt;\u0026gt;(topic, msg); 51 RecordMetadata metadata = kafkaProducer.send(record).get(); 52 53 System.out.printf(\u0026#34;Successful\\tTopic: %s, Partition: %d, Offset %d%n\u0026#34;,metadata.topic(), metadata.partition(), metadata.offset()); 54 Thread.sleep(50); 55 } 56 } catch (ExecutionException e) { 57 throw new RuntimeException(e); 58 } 59 } 60} python语言\n1#!/usr/bin/env python3 2# --* coding: utf-8 *-- 3 4import urllib3 5import json 6import logging 7from time import sleep 8 9# 定义elasticsearch 主机和端口 10host = \u0026#34;10.138.4.41\u0026#34; 11port = \u0026#34;9200\u0026#34; 12 13# 定义日志文件路径，请尽可能的使用绝对路径 14log_file = \u0026#34;unassigned.log\u0026#34; 15 16logger = logging.getLogger() 17logger.setLevel(logging.DEBUG) 18formatter = logging.Formatter(\u0026#34;%(asctime)s - %(filename)s [line:%(lineno)d] %(levelname)s : %(message)s\u0026#34;) 19 20# 配置日志级别,这里为DEBUG，定义日志写到文件，文件为上面的 log_file 变量 21fh = logging.FileHandler(log_file, mode=\u0026#39;a\u0026#39;) 22fh.setLevel(logging.DEBUG) 23fh.setFormatter(formatter) 24logger.addHandler(fh) 25 26# 除了把日志写入到文件，同时也打印到控制台，即 标准输出(stdout)，这里级别也是 DEBUG 27ch = logging.StreamHandler() 28ch.setLevel(logging.DEBUG) 29ch.setFormatter(formatter) 30logger.addHandler(ch) 31 32 33# 由于每个函数都会用到的 HTTP 对象，所以在这里直接初始化一次 34http = urllib3.PoolManager() 35 36 37def Get_Status(host, port): 38 url = host + \u0026#34;:\u0026#34; + port + \u0026#34;/_cluster/health\u0026#34; 39 r = http.request(\u0026#39;GET\u0026#39;, url) 40 index_status = json.loads(r.data.decode(\u0026#39;utf-8\u0026#39;)) 41 return index_status[\u0026#34;status\u0026#34;] 42 43 44def Red_Index_name(host, port): 45 url = host + \u0026#34;:\u0026#34; + port + \u0026#34;/_cat/shards\u0026#34; 46 r = http.request(\u0026#39;GET\u0026#39;, url) 47 result_str = r.data.decode(\u0026#39;utf-8\u0026#39;) 48 result_list = result_str.split(\u0026#34;\\n\u0026#34;)[0:-1] 49 50 # 获取所有索引的分片信息，找出未分配分片的索引名称，并添加到 list, 51 # 使用 list，兼容存在多个索引出现未分配分片的情况 52 unassigned_list = [] 53 for i in result_list: 54 if \u0026#34;UNASSIGNED\u0026#34; in i: 55 unassigned_list.append(i.split()[0]) 56 return unassigned_list 57 58 59def Node_Name(host, port, index_name): 60 result_dict = {} 61 node_list = [\u0026#39;node01\u0026#39;, \u0026#39;node02\u0026#39;, \u0026#39;node03\u0026#39;, \u0026#39;node04\u0026#39;, \u0026#39;node05\u0026#39;, \u0026#39;node06\u0026#39;] 62 url = host + \u0026#34;:\u0026#34; + port + \u0026#34;/_cat/shards/\u0026#34; + index_name 63 r = http.request(\u0026#39;GET\u0026#39;, url) 64 node_str = r.data.decode(\u0026#39;utf-8\u0026#39;) 65 66 # 由于是6个节点，索引只有一个分片不被分配， 67 # 找出那一个分片原本应该属于的节点，以及该分片的id， 添加到字典，后续提交数据 68 for node in node_list: 69 if not node in node_str: 70 result_dict[\u0026#39;nodename\u0026#39;] = node 71 break 72 format_str = node_str.split(\u0026#34;\\n\u0026#34;)[0:-1] 73 74 for share_id in format_str: 75 if \u0026#34;UNASSIGNED\u0026#34; in share_id: 76 result_dict[\u0026#39;id\u0026#39;] = share_id.split()[1] 77 break 78 return result_dict 79 80 81def exec_unassigned(host, port, index_name, shard_data): 82 summit_data = { 83 \u0026#39;commands\u0026#39;: [ 84 { 85 \u0026#39;allocate\u0026#39;: { 86 \u0026#39;index\u0026#39;: index_name, 87 \u0026#39;shard\u0026#39;: shard_data[\u0026#39;id\u0026#39;], 88 \u0026#39;node\u0026#39;: shard_data[\u0026#39;nodename\u0026#39;], 89 \u0026#39;allow_primary\u0026#39;: True 90 } 91 } 92 ] 93 } 94 encoded_data = json.dumps(summit_data).encode(\u0026#39;utf-8\u0026#39;) 95 url = host + \u0026#34;:\u0026#34; + port + \u0026#34;/_cluster/reroute\u0026#34; 96 return http.request(\u0026#39;POST\u0026#39;, url, body=encoded_data, headers={\u0026#39;Content-Type\u0026#39;: \u0026#39;application/json\u0026#39;}) 97 # return summit_data 98 99 100if __name__ == \u0026#39;__main__\u0026#39;: 101 102 # 查询集群状态，若是 red 的状态，才继续查找未分配的分片信息，提交重新分配 103 if Get_Status(host, port) == \u0026#34;red\u0026#34;: 104 index_name = Red_Index_name(host, port) 105 # if len(index_name) \u0026gt; 1: 106 for x in index_name: 107 shard_data = Node_Name(host, port, x) 108 # print(x, shard_data) 109 r = exec_unassigned(host, port, x, shard_data) 110 if r.status == 200: 111 logger.info(\u0026#34;Success! Server Return: \u0026#34; + 112 r.data.decode(\u0026#39;utf-8\u0026#39;)) 113 else: 114 logger.error(\u0026#34;Failed! Server Return: \u0026#34; + 115 r.data.decode(\u0026#39;utf-8\u0026#39;)) 116 sleep(2) 117 else: 118 pass 119 120# curl -X POST -H \u0026#39;Content-Type\u0026#39;: \u0026#39;application/json\u0026#39; -d \u0026#39;{\u0026#34;commands\u0026#34;:[{\u0026#34;move\u0026#34;:{\u0026#34;index\u0026#34;:\u0026#34;t-data\u0026#34;,\u0026#34;shard\u0026#34;:0,\u0026#34;from_node\u0026#34;:\u0026#34;node02\u0026#34;,\u0026#34;to_node\u0026#34;:\u0026#34;node03\u0026#34;}}]}\u0026#39; http://10.138.4.42:9200/_cluster/reroute html语言\n1\u0026lt;!DOCTYPE HTML\u0026gt; 2\u0026lt;html\u0026gt; 3\u0026lt;meta charset=\u0026#34;utf-8\u0026#34;\u0026gt; 4 5\u0026lt;head\u0026gt; 6 \u0026lt;title\u0026gt;JD_COOKIE\u0026lt;/title\u0026gt; 7 \u0026lt;link rel=\u0026#34;shortcut icon\u0026#34; href=\u0026#34;/favicon.ico\u0026#34;\u0026gt; 8\u0026lt;/head\u0026gt; 9\u0026lt;style type=\u0026#34;text/css\u0026#34;\u0026gt; 10 body { 11 text-align: center; 12 } 13 14 .div { 15 margin: 0 auto; 16 width: 600px; 17 height: 280px; 18 padding: 2px; 19 } 20 21 .inp { 22 width: 75%; 23 } 24\u0026lt;/style\u0026gt; 25 26\u0026lt;body\u0026gt; 27 \u0026lt;div class=\u0026#34;div\u0026#34;\u0026gt; 28 \u0026lt;h2\u0026gt;表哥COOKIE自助更新\u0026lt;/h2\u0026gt; 29 请仅仅填入 pt_pin 和 pt_key 的值\u0026lt;br /\u0026gt; 30 \u0026lt;font color=\u0026#34;red\u0026#34;\u0026gt;不要包含其他字符, 比如 空格 分号等\u0026lt;/font\u0026gt;\u0026lt;br /\u0026gt; 31 \u0026lt;a href=\u0026#34;/help.html\u0026#34; target=\u0026#34;_blank\u0026#34;\u0026gt;点此查看帮助\u0026lt;/a\u0026gt; 32 \u0026lt;hr /\u0026gt; 33 \u0026lt;form action=\u0026#34;/update\u0026#34; method=\u0026#34;get\u0026#34;\u0026gt; 34 \u0026lt;b\u0026gt;pt_pin:\u0026lt;/b\u0026gt;\u0026lt;br /\u0026gt; 35 \u0026lt;input class=\u0026#34;inp\u0026#34; type=\u0026#34;text\u0026#34; name=\u0026#34;pt_pin\u0026#34; required=\u0026#34;required\u0026#34; 36 onkeyup=\u0026#34;this.value=this.value.replace(/(\\s+|;)/g,\u0026#39;\u0026#39;)\u0026#34; /\u0026gt;\u0026lt;br /\u0026gt; 37 \u0026lt;b\u0026gt;pt_key\u0026lt;/b\u0026gt;\u0026lt;br /\u0026gt; 38 \u0026lt;input class=\u0026#34;inp\u0026#34; type=\u0026#34;text\u0026#34; name=\u0026#34;pt_key\u0026#34; required=\u0026#34;required\u0026#34; 39 onkeyup=\u0026#34;this.value=this.value.replace(/(\\s+|;)/g,\u0026#39;\u0026#39;)\u0026#34; /\u0026gt;\u0026lt;br /\u0026gt; 40 \u0026lt;br /\u0026gt; 41 \u0026lt;input type=\u0026#34;submit\u0026#34; value=\u0026#34;Update\u0026#34; /\u0026gt; 42 \u0026lt;/form\u0026gt; 43 \u0026lt;/div\u0026gt; 44\u0026lt;/body\u0026gt; 45 46\u0026lt;/html\u0026gt; js 语言\n1function initializeSearch(index) { 2 const searchKeys = [\u0026#39;title\u0026#39;, \u0026#39;link\u0026#39;, \u0026#39;body\u0026#39;, \u0026#39;id\u0026#39;, \u0026#39;section\u0026#39;, \u0026#39;tags\u0026#39;]; 3 4 const searchPageElement = elem(\u0026#39;#searchpage\u0026#39;); 5 6 const searchOptions = { 7 ignoreLocation: true, 8 findAllMatches: true, 9 includeScore: true, 10 shouldSort: true, 11 keys: searchKeys, 12 threshold: 0.0 13 }; 14 15 index = new Fuse(index, searchOptions); 16 17 function minQueryLen(query) { 18 query = query.trim(); 19 const queryIsFloat = parseFloat(query); 20 const minimumQueryLength = queryIsFloat ? 1 : 2; 21 return minimumQueryLength; 22 } 23 24 function searchResults(results=[], query=\u0026#34;\u0026#34;, passive = false) { 25 let resultsFragment = new DocumentFragment(); 26 let showResults = elem(\u0026#39;.search_results\u0026#39;); 27 if(passive) { 28 showResults = searchPageElement; 29 } 30 emptyEl(showResults); 31 32 const queryLen = query.length; 33 const requiredQueryLen = minQueryLen(query); 34 35 if(results.length \u0026amp;\u0026amp; queryLen \u0026gt;= requiredQueryLen) { 36 let resultsTitle = createEl(\u0026#39;h3\u0026#39;); 37 resultsTitle.className = \u0026#39;search_title\u0026#39;; 38 resultsTitle.innerText = quickLinks; 39 40 let goBackButton = createEl(\u0026#39;button\u0026#39;); 41 goBackButton.textContent = \u0026#39;Go Back\u0026#39;; 42 goBackButton.className = goBackClass; 43 if(passive) { 44 resultsTitle.innerText = searchResultsLabel; 45 } 46 if(!searchPageElement) { 47 results = results.slice(0,8); 48 } else { 49 resultsFragment.appendChild(goBackButton); 50 results = results.slice(0,12); 51 } 52 resultsFragment.appendChild(resultsTitle); 53 54 results.forEach(function(result){ 55 let item = createEl(\u0026#39;a\u0026#39;); 56 item.href = `${result.link}?query=${query}`; 57 item.className = \u0026#39;search_result\u0026#39;; 58 item.style.order = result.score; 59 if(passive) { 60 pushClass(item, \u0026#39;passive\u0026#39;); 61 let itemTitle = createEl(\u0026#39;h3\u0026#39;); 62 itemTitle.textContent = result.title; 63 item.appendChild(itemTitle); 64 65 let itemDescription = createEl(\u0026#39;p\u0026#39;); 66 // position of first search term instance 67 let queryInstance = result.body.indexOf(query); 68 itemDescription.textContent = `${result.body.substring(queryInstance, queryInstance + 200)}`; 69 item.appendChild(itemDescription); 70 } else { 71 item.textContent = result.title; 72 } 73 resultsFragment.appendChild(item); 74 }); 75 } 76 77 if(queryLen \u0026gt;= requiredQueryLen) { 78 if (!results.length) { 79 showResults.innerHTML = `\u0026lt;span class=\u0026#34;search_result\u0026#34;\u0026gt;${noMatchesFound}\u0026lt;/span\u0026gt;`; 80 } 81 } else { 82 showResults.innerHTML = `\u0026lt;label for=\u0026#34;find\u0026#34; class=\u0026#34;search_result\u0026#34;\u0026gt;${ queryLen \u0026gt; 1 ? shortSearchQuery : typeToSearch }\u0026lt;/label\u0026gt;` 83 } 84 85 showResults.appendChild(resultsFragment); 86 } 87 88 function search(searchTerm, scope = null, passive = false) { 89 if(searchTerm.length) { 90 let rawResults = index.search(searchTerm); 91 rawResults = rawResults.map(function(result){ 92 const score = result.score; 93 const resultItem = result.item; 94 resultItem.score = (parseFloat(score) * 50).toFixed(0); 95 return resultItem ; 96 }) 97 98 if(scope) { 99 rawResults = rawResults.filter(resultItem =\u0026gt; { 100 return resultItem.section == scope; 101 }); 102 } 103 104 passive ? searchResults(rawResults, searchTerm, true) : searchResults(rawResults, searchTerm); 105 106 } else { 107 passive ? searchResults([], \u0026#34;\u0026#34;, true) : searchResults(); 108 } 109 } 110 111 function liveSearch() { 112 const searchField = elem(searchFieldClass); 113 114 if (searchField) { 115 const searchScope = searchField.dataset.scope; 116 searchField.addEventListener(\u0026#39;input\u0026#39;, function() { 117 const searchTerm = searchField.value.trim().toLowerCase(); 118 search(searchTerm, searchScope); 119 }); 120 121 if(!searchPageElement) { 122 searchField.addEventListener(\u0026#39;search\u0026#39;, function(){ 123 const searchTerm = searchField.value.trim().toLowerCase(); 124 if(searchTerm.length) { 125 const scopeParameter = searchScope ? `\u0026amp;scope=${searchScope}` : \u0026#39;\u0026#39;; 126 window.location.href = new URL(baseURL + `search/?query=${searchTerm}${ scopeParameter }`).href; 127 } 128 }); 129 } 130 } 131 } 132 133 function passiveSearch() { 134 if(searchPageElement) { 135 const searchTerm = findQuery(); 136 const searchScope = findQuery(\u0026#39;scope\u0026#39;); 137 // search actively after search page has loaded 138 const searchField = elem(searchFieldClass); 139 140 search(searchTerm, searchScope, true); 141 142 if(searchField) { 143 searchField.addEventListener(\u0026#39;input\u0026#39;, function() { 144 const searchTerm = searchField.value.trim().toLowerCase(); 145 search(searchTerm, true); 146 wrapText(searchTerm, main); 147 }); 148 } 149 } 150 } 151 152 function hasSearchResults() { 153 const searchResults = elem(\u0026#39;.results\u0026#39;); 154 if(searchResults) { 155 const body = searchResults.innerHTML.length; 156 return [searchResults, body]; 157 } 158 return false 159 } 160 161 function clearSearchResults() { 162 let searchResults = hasSearchResults(); 163 if(searchResults) { 164 searchResults = searchResults[0]; 165 searchResults.innerHTML = \u0026#34;\u0026#34;; 166 // clear search field 167 const searchField = elem(searchFieldClass); 168 searchField.value = \u0026#34;\u0026#34;; 169 } 170 } 171 172 function onEscape(fn){ 173 window.addEventListener(\u0026#39;keydown\u0026#39;, function(event){ 174 if(event.code === \u0026#34;Escape\u0026#34;) { 175 fn(); 176 } 177 }); 178 } 179 180 let main = elem(\u0026#39;main\u0026#39;); 181 if(!main) { 182 main = elem(\u0026#39;.main\u0026#39;); 183 } 184 185 searchPageElement ? false : liveSearch(); 186 passiveSearch(); 187 188 highlightSearchTerms(findQuery(), \u0026#39;.post_body\u0026#39;, \u0026#39;mark\u0026#39;, \u0026#39;search-term\u0026#39;); 189 190 onEscape(clearSearchResults); 191 192 window.addEventListener(\u0026#39;click\u0026#39;, function(event){ 193 const target = event.target; 194 const isSearch = target.closest(searchClass) || target.matches(searchClass); 195 if(!isSearch \u0026amp;\u0026amp; !searchPageElement) { 196 clearSearchResults(); 197 } 198 }); 199} shell脚本\n1 2 3curl -X PUT http://10.47.56.10:9200/_cluster/settings?pretty -H \u0026#39;Content-Type: application/json\u0026#39; -d\u0026#39;{\u0026#34;transient\u0026#34;: {\u0026#34;cluster.routing.allocation.enable\u0026#34;: \u0026#34;none\u0026#34;}}\u0026#39; 4 5 6curl -X PUT http://10.47.56.10:9200/_cluster/settings?pretty -H \u0026#39;Content-Type: application/json\u0026#39; -d\u0026#39;{\u0026#34;transient\u0026#34;: {\u0026#34;cluster.routing.allocation.enable\u0026#34;: \u0026#34;all\u0026#34;}}\u0026#39; 7 8ansible -i shaoew.ip.txt shaoew -m copy -a \u0026#39;src=log4j-1.2-api-2.16.0.jar dest=/tmp/log4j-1.2-api-2.16.0.jar mode=0644\u0026#39; 9ansible -i shaoew.ip.txt shaoew -m copy -a \u0026#39;src=log4j-api-2.16.0.jar dest=/tmp/log4j-api-2.16.0.jar mode=0644\u0026#39; 10ansible -i shaoew.ip.txt shaoew -m copy -a \u0026#39;src=log4j-core-2.16.0.jar dest=/tmp/log4j-core-2.16.0.jar mode=0644\u0026#39; 11 12mv log4j-1.2-api-2.17.0.jar log4j-1.2-api-2.17.0.jar.bak 13mv log4j-api-2.17.0.jar log4j-api-2.17.0.jar.bak 14mv log4j-core-2.17.0.jar log4j-core-2.17.0.jar.bak 15cp /tmp/log4j-*.1.jar . 16mv log4j-*.jar.bak ~ 17 18 19 20 21mv log4j-1.2-api-2.9.1.jar log4j-1.2-api-2.9.1.jar.bak 22mv log4j-api-2.9.1.jar log4j-api-2.9.1.jar.bak 23mv log4j-core-2.9.1.jar log4j-core-2.9.1.jar.bak 24cp /tmp/log4j* . 25 26mv log4j-1.2-api-2.8.2.jar log4j-1.2-api-2.8.2.jar.bak 27mv log4j-api-2.8.2.jar log4j-api-2.8.2.jar.bak 28mv log4j-core-2.8.2.jar log4j-core-2.8.2.jar.bak 29cp /tmp/log4j* . 30 31 32mv log4j-1.2-api-2.16.0.jar log4j-1.2-api-2.16.0.jar.bak 33mv log4j-api-2.16.0.jar log4j-api-2.16.0.jar.bak 34mv log4j-core-2.16.0.jar log4j-core-2.16.0.jar.bak 35cp /tmp/log4j-*2.17.0.jar . 36rm -f log4j-1.2-api-2.17.0.jar 37 38 39[nec-es] 4010.138.4.37 4110.138.4.38 4210.138.4.39 4310.138.8.8 44 45nec-promotionadmin-web|nec-promotionweb-web 46 47 48NEC-Dev 调整为0的 deployment 49nec-message-service 50 51 52rm -f log4j-[ac]*0.jar 53cp /tmp/log4j-[ac]*1.jar . 54 55 56for i in $(kubectl get pod -n uat | awk \u0026#39;NR\u0026gt;1{print $1}\u0026#39;); do echo $i $(kubectl exec -it $i -n uat -- find /data -name \u0026#39;log4j-core*.jar\u0026#39;);done 2\u0026gt;/dev/null | tee nec-uat-pod.log 57 58 59for i in $(kubectl get pod -n product | awk \u0026#39;NR\u0026gt;1{print $1}\u0026#39;); do echo $i $(kubectl exec -it $i -n product -- find /data -name \u0026#39;log4j-core*.jar\u0026#39;);done 2\u0026gt;/dev/null | tee nec-prod-pod.log 60 61for i in $(kubectl get pod -n dev-jp | awk \u0026#39;NR\u0026gt;1{print $1}\u0026#39;); do echo $i $(kubectl exec -it $i -n dev-jp -- find /data -name \u0026#39;log4j-core*.jar\u0026#39;);done 2\u0026gt;/dev/null | tee nec-dev-pod.log 62 63 64for i in $(kubectl get pod -n uat | awk \u0026#39;NR\u0026gt;1{print $1}\u0026#39;); do echo \u0026#34;$i $(kubect exec -it $i -n uat -- ls -la /proc/*/fd/ 2\u0026gt;/dev/null|grep \u0026#39;log4j-core\u0026#39; | awk \u0026#39;{print $NF}\u0026#39;)\u0026#34;;done 2\u0026gt;/dev/null | tee nec-pod.log 65 66ls -la /proc/*/fd/ 2\u0026gt;/dev/null|grep -E \u0026#34;log4j-core\u0026#34; | awk \u0026#39;{print $NF}\u0026#39; 67 68echo $i, $(kubectl exec -it $i -n uat -- find /data -name \u0026#39;log4j-core*.jar\u0026#39;) 69 70/api/v1/notify/getVideoId 71 72 73fio -ioengine=libaio -bs=4k -direct=1 -thread -rw=randwrite -filename=/data/test1 -name=\u0026#34;BS 4KB write test\u0026#34; -iodepth=16 -runtime=60 74 75sudo fio --name=randwrite --ioengine=libaio --iodepth=8 --rw=randwrite --bs=4k --direct=1 --size=512M --numjobs=2 --runtime=240 --group_reporting --filename=/data/test1 76 77 78 79proxy_set_header X-Real-IP $remote_addr; 80proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 81 82docker 节点 8310.96.83.185 nexus 84 85 86curl -X PUT http://10.120.131.166:9200/orderdiscount/_settings -d \u0026#39;{\u0026#34;number_of_replicas\u0026#34;:0}\u0026#39; 87 88while read line;do ssh -o ConnectTimeout=5 -n $line \u0026#34;free -h | awk \u0026#39;NR==2{print $2}\u0026#39;\u0026#34;; done \u0026lt; s.prod.ip.txt 89 90while read line;do ssh -o ConnectTimeout=5 -n $line \u0026#34;lscpu | awk \u0026#39;/^CPU\\(s\\)/\u0026#39;\u0026#34;; done \u0026lt; s.pre.ip.txt 91 92 93proxy_set_header X-Real-IP $remote_addr; 94proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 95 9610.138.4.37 9710.138.4.38 9810.138.4.39 9910.138.4.31 10010.138.4.32 10110.138.8.9 10210.138.8.8 103 104mv log4j-1.2-api-2.17.0.jar log4j-1.2-api-2.17.0.jar.bak 105mv log4j-api-2.17.0.jar log4j-api-2.17.0.jar.bak 106mv log4j-core-2.17.0.jar log4j-core-2.17.0.jar.bak 107cp /tmp/log4j-*.jar . 108mv log4j-*.jar.bak ~ 109 110 111 112 113for i in $(kubectl get pod -n product | awk \u0026#39;{print $1}\u0026#39; | sed \u0026#39;1d\u0026#39; ); do echo \u0026#34;$i, $(kubectl exec -it $i -n product -- find /data/ -name \u0026#39;*log4j-core-*.jar\u0026#39; )\u0026#34;; echo \u0026#34;\u0026#34;; done ","link":"http://test.mylass.com/linux/java-kafka/","section":"linux","tags":["java","kafka"],"title":"java 连接kafka demo程序"},{"body":"","link":"http://test.mylass.com/tags/python/","section":"tags","tags":null,"title":"python"},{"body":"","link":"http://test.mylass.com/series/python/","section":"series","tags":null,"title":"python"},{"body":"由于安全要求，在使用外网的情况下，使用kafka必须使用加密，但在使用python客户端，出现了问题，使用java则无问题。\n在使用python客户端的时候，由于不能直接使用 jks 证书文件（此为java专用）\n报信信息如下：\n1Traceback (most recent call last): 2 File \u0026#34;m:/mm/kfk/ssl_producer.py\u0026#34;, line 31, in \u0026lt;module\u0026gt; 3 sasl_plain_password=\u0026#39;pangoo.redis@sync1\u0026#39; 4 File \u0026#34;M:\\mm\\lib\\site-packages\\kafka\\producer\\kafka.py\u0026#34;, line 383, in __init__ 5 **self.config) 6 File \u0026#34;M:\\mm\\lib\\site-packages\\kafka\\client_async.py\u0026#34;, line 244, in __init__ 7 self.config[\u0026#39;api_version\u0026#39;] = self.check_version(timeout=check_timeout) 8 File \u0026#34;M:\\mm\\lib\\site-packages\\kafka\\client_async.py\u0026#34;, line 909, in check_version 9 version = conn.check_version(timeout=remaining, strict=strict, topics=list(self.config[\u0026#39;bootstrap_topics_filter\u0026#39;])) 10 File \u0026#34;M:\\mm\\lib\\site-packages\\kafka\\conn.py\u0026#34;, line 1238, in check_version 11 if not self.connect_blocking(timeout_at - time.time()): 12 File \u0026#34;M:\\mm\\lib\\site-packages\\kafka\\conn.py\u0026#34;, line 340, in connect_blocking 13 self.connect() 14 File \u0026#34;M:\\mm\\lib\\site-packages\\kafka\\conn.py\u0026#34;, line 429, in connect 15 if self._try_handshake(): 16 File \u0026#34;M:\\mm\\lib\\site-packages\\kafka\\conn.py\u0026#34;, line 508, in _try_handshake 17 self._sock.do_handshake() 18 File \u0026#34;C:\\Users\\ainy\\AppData\\Local\\Programs\\Python\\Python37\\lib\\ssl.py\u0026#34;, line 1139, in do_handshake 19 self._sslobj.do_handshake() 20ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1091) 一开始以为使用的证书有问题，最后搜索后解决，windows需要指定一下版本号。\n允许不安全的密码，初始化 ssl.SSLContext，并将 ctx 作为 ssl_context 参数传递给 KafkaConsumer 或 KafkaProducer 构造函数\n1ctx = ssl.SSLContext(ssl.PROTOCOL_TLS) 2ctx.set_ciphers(\u0026#39;ALL:@SECLEVEL=0\u0026#39;) 传递给kafka，示例\n1from kafka import KafkaProducer 2import ssl 3 4ctx = ssl.SSLContext(ssl.PROTOCOL_TLS) 5ctx.set_ciphers(\u0026#39;ALL:@SECLEVEL=0\u0026#39;) 6 7producer = KafkaProducer( 8 bootstrap_servers = \u0026#39;localhost:9093\u0026#39;, 9 security_protocol = \u0026#39;SASL_SSL\u0026#39;, 10 sasl_mechanism = \u0026#39;SCRAM-SHA-512\u0026#39;, 11 ssl_check_hostname = False, 12 ssl_certfile = \u0026#39;certificate.pem\u0026#39;, 13 ssl_cafile = \u0026#39;CARoot.pem\u0026#39;, 14 ssl_context = ctx, # 传递给 kafka的producer或者 consumer，本例是 producer 15 sasl_plain_username = \u0026#39;username\u0026#39;, 16 sasl_plain_password = \u0026#39;04UMwt9LUa9MJF6z\u0026#39; 17) ","link":"http://test.mylass.com/linux/python-kafka-ssl-wrong-version-number/","section":"linux","tags":["kafka","python"],"title":"python3客户端连接ssl kafka版本号错误"},{"body":"","link":"http://test.mylass.com/tags/nginx/","section":"tags","tags":null,"title":"nginx"},{"body":"","link":"http://test.mylass.com/series/nginx/","section":"series","tags":null,"title":"nginx"},{"body":"在 nginx 配置文件，if 指令可以实现简单的判断，本身并不支持 and，or 以及嵌套，同时也不支持 else, 可以通过变相的方法来实现。\n基本思路：设置一个变量，然后根据情况，修改变量，最后判断变量\n实现如下：\n1set $custom_flag 0; 2 3if ($http_referer !~ admin[0-9]+\\.mylass\\.com) { 4 set $custom_flag ${custom_flag}1; 5} 6if ($http_referer !~ manager\\.mylass\\.com) { 7 set $custom_flag ${custom_flag}1; 8} 9 10if ($custom_flag = 011) { 11 rewrite .* /bad-request/http-error-400.html break; 12} 本例，通过设置一个初始变量 custom_flag 等于 0，再判断后续情况。\n若两个条件都成立，则 custom_flag 的值最后必定是 011。符合其中一条，则最后的值是 01，都不符合，则是 0，通过这种方法来实现\n","link":"http://test.mylass.com/linux/nginx-if-and-or/","section":"linux","tags":["nginx"],"title":"nginx if判断实现逻辑运算 AND 和 OR 的方法"},{"body":"","link":"http://test.mylass.com/tags/kafkassl/","section":"tags","tags":null,"title":"kafkassl"},{"body":"最近由于需要测试一些数据，而 kafka 的服务器是带有 SSL 加密和 SASL 认证的，所以写了个小的程序。简化后的程序放这里。\n由于在加解密数据时的，需要使用 jks 证书文件，这个 jks 只有 java 可以读取，所以需要从 jks 中提取根证书，命令参数介绍如下。\npass123 为 jks 证书文件密码， 若提示 keytool 命令找不到，请安装 jdk， jdk 包中包含了这个命令。\n1keytool -exportcert -alias caroot -keystore kafka.client.keystore.jks -rfc -file certificate.pem -storepass pass123 2keytool -v -importkeystore -srckeystore kafka.client.keystore.jks -srcalias caroot -destkeystore cert_and_key.p12 -deststoretype PKCS12 -storepass pass123 -srcstorepass pass123 3openssl pkcs12 -in cert_and_key.p12 -nodes -nocerts -out key.pem -passin pass:pass123 4keytool -exportcert -alias caroot -keystore kafka.client.keystore.jks -rfc -file CARoot.pem -storepass pass123 命令完成，除 kafka.client.keystore.jks 外，会生成以下文件：\n1CARoot.pem 2cert_and_key.p12 3certificate.pem 4kafka.client.keystore.jks 5key.pem 消息生产者：\n1import time 2from kafka import KafkaProducer 3import ssl 4 5kafka_server = \u0026#39;kafka01.mylass.com:9093\u0026#39; # 多个节点，可以写成 list 6# kafka_server = [\u0026#39;172.19.169.169:9093\u0026#39;,\u0026#39;172.19.169.170:9093\u0026#39;,\u0026#39;172.19.169.171:9093\u0026#39;] 7topic_name = \u0026#39;ssl-test\u0026#39; 8 9ctx = ssl.SSLContext(ssl.PROTOCOL_TLS) # windows ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number 10ctx.set_ciphers(\u0026#39;ALL:@SECLEVEL=0\u0026#39;) # windows ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number 11 12producer = KafkaProducer( 13 bootstrap_servers = kafka_server, 14 acks = \u0026#39;all\u0026#39;, # ack 类型 15 security_protocol = \u0026#39;SASL_SSL\u0026#39;, 16 sasl_mechanism = \u0026#39;SCRAM-SHA-512\u0026#39;, # 取决于你的服务器用了什么参数，保持一致 17 ssl_check_hostname = False, 18 ssl_certfile = \u0026#39;certificate.pem\u0026#39;, # 经过测试，只配置ca证书即可，这个证书可以不配置 19 ssl_cafile = \u0026#39;CARoot.pem\u0026#39;, # 经过测试，只配置ca证书即可 20 ssl_context = ctx, # windows ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number 21 sasl_plain_username = \u0026#39;username\u0026#39;, 22 sasl_plain_password = \u0026#39;password\u0026#39; 23) 24 25for i in range(5): 26 s0 = time.strftime(\u0026#34;%Y-%m-%d %H:%M:%S\u0026#34;, time.localtime()) 27 s1 = str(s0)+\u0026#39; messages: \u0026#39; + str(i) 28 future1 = producer.send(topic_name, s1.encode(\u0026#39;utf-8\u0026#39;)) #发送消息 29 producer.flush() 30 record = future1.get(timeout=10) 31 print(record) 消息消费者：\n1from kafka import KafkaConsumer 2import ssl 3 4kafka_server = \u0026#39;kafka01.mylass.com:9093\u0026#39; # 多个节点，可以写成 list 5# kafka_server = [\u0026#39;172.19.169.169:9093\u0026#39;,\u0026#39;172.19.169.170:9093\u0026#39;,\u0026#39;172.19.169.171:9093\u0026#39;] 6topic = \u0026#39;ssl-test\u0026#39; 7groupid = \u0026#39;sslgroup1\u0026#39; 8 9ctx = ssl.SSLContext(ssl.PROTOCOL_TLS) # windows ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number 10ctx.set_ciphers(\u0026#39;ALL:@SECLEVEL=0\u0026#39;) # windows ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number 11 12consumer = KafkaConsumer( 13 topic, 14 group_id = groupid, 15 bootstrap_servers = kafka_server, 16 security_protocol = \u0026#39;SASL_SSL\u0026#39;, 17 sasl_mechanism = \u0026#39;SCRAM-SHA-512\u0026#39;, # 取决于你的服务器用了什么参数，保持一致 18 sasl_plain_username = \u0026#39;username\u0026#39;, 19 sasl_plain_password = \u0026#39;password\u0026#39;, 20 ssl_check_hostname = False, 21 ssl_cafile = \u0026#39;CARoot.pem\u0026#39;, 22 ssl_certfile = \u0026#39;certificate.pem\u0026#39;, 23 ssl_context = ctx # windows ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number 24) 25for msg in consumer: 26 print(\u0026#34;partition = %d, offset = %d\u0026#34; % (msg.partition, msg.offset)) # 元数据，可根据情况获取 27 print(\u0026#34;value = %s\u0026#34; % msg.value.decode()) # 消息体 ","link":"http://test.mylass.com/python/python-ssl-kafka-clients/","section":"python","tags":["kafkassl"],"title":"python3操作kafka sasl_ssl客户端程序"},{"body":"","link":"http://test.mylass.com/python/","section":"python","tags":null,"title":"Pythons"},{"body":"","link":"http://test.mylass.com/tags/pycurl/","section":"tags","tags":null,"title":"pycurl"},{"body":"这是一个小工具用，于测试接口响应时间，包括 DNS 解析时间， TCP建立连接时间， 传输数据时间等等。\n程序使用Python3 + pycurl库 curl 本质还是调用 libcurl库，在linux运行没问题，windows7及以前，由于本身并不包含libcurl，可能会出现不可预知问题，不确定一定能使用。\nwindows7使用，需要安装 vc++ 2015\n使用说明 使用标准： 使用时，url部分，请携带协议，即 http://或https://\n下载附件，解压，放到一个目录下，如： F:\\chkurl\\\n打开 cmd 使用 F: 切换到 F盘 使用 cd chkurl 切换目录\n使用 chkurl.exe -h 查看帮助，命令参数介绍如下：\n1Usage: ckurl.py - [OPTIONS] -u [url] 2 3Options: 4 -h, --help 显示帮助 5 -e, --enable_reuse 启用TCP复用连接，默认不启用 6 -k, --insecure 忽略https证书检查（如过期、不受信任域名不匹配） 7 -L, --location 跟随重定向，默认，不跟随 8 -r 10, --redirs_num 10 指定最大重定向次数，默认 10 9 -D 0, --dns_cache 0\t指定DNS缓存时间，0为不缓存，默认 0 10 --timeout=TIMEOUT 指定请求超时时间 11 --connect_time=CONNECT_TIME 连接超时时间 12 -s, --size 显示下载、上传、下载速度与上传速度 13 -u https://lenovo.com, --url 指定测试的URL 14 -c 3, --count=3\t指定测试的次数 15 -H HEADER, --header=HEADER 添加 http 头部信息 16 -i IP, --ip_address=IP\t指定IP，绕过DNS解析 17 -p, --post 使用post提交 18 -d POST_DATA, --data=POST_DATA\tpost提交的数据 19 -F s.json, --data_file=s.json\t从文件读取内容关提交post的数据 20 -l time.log, --logfile=time.log 指定测试速度日志文件指定的内容 21 -b, --body 显示 html body 主体内容，只显示第一次的 对于命令行参数， -H 添加 http头，若要添加多个，请多次使用 -H， 如：\n1chkurl -H \u0026#34;Content-Type:application/json\u0026#34; -H \u0026#34;Connection: keep-alive\u0026#34; -H \u0026#34;xxxxxx\u0026#34; 对于 -i 选项，是指定ip地址，直接使用指定的地址，而不进行DNS解析，可以指定多个，与 -H 选项同样，多个次，请多次使用 -i 选项\n指定多个IP的时候，会循环测试，即，先完成第一个IP的 -c 次数后，进行第二个IP，之后进行第三个、第四个、第五个一直到结束\n指定IP的时候，请务必指定 http:// 或者 https:// 协议\n命令执行完全后，会生成记录文件，如果没有使用 -l 指定位置，则位于当前目录下 time.log\n使用配置文件 可以不指定任何参数，直接运行程序，参数在配置文件定义\nPS: 在使用命令行参数的时候，只要没有指定 -u ，便会使用配置件，覆盖全部的参数\n默认位于程序执行目录下，有一个 config.json 的文件，可在内部配置以上的参数信息 配置文件内容如下：\n1{ 2 \u0026#34;conf\u0026#34;:{ 3 \u0026#34;baseconfig\u0026#34;:{ 4 \u0026#34;tcp_reuse\u0026#34;:false, 5 \u0026#34;follow_redirect\u0026#34;:true, 6 \u0026#34;max_redirects\u0026#34;:10, 7 \u0026#34;dns_cache\u0026#34;:0, 8 \u0026#34;timeout\u0026#34;:120, 9 \u0026#34;connect_time\u0026#34;:120, 10 \u0026#34;cert_check\u0026#34;:false 11 } 12 }, 13 \u0026#34;display\u0026#34;:{ 14 \u0026#34;data_size\u0026#34;:false, 15 \u0026#34;body\u0026#34;:false 16 }, 17 \u0026#34;request\u0026#34;:{ 18 \u0026#34;url\u0026#34;:\u0026#34;https://www.lenovo.com.cn/my_backup\u0026#34;, 19 \u0026#34;count\u0026#34;:3, 20 \u0026#34;http_header\u0026#34;: null, 21 \u0026#34;ip_address\u0026#34;:null, 22 \u0026#34;post\u0026#34;:true, 23 \u0026#34;post_data\u0026#34;:null, 24 \u0026#34;post_data_file\u0026#34;:null 25 }, 26 \u0026#34;logfile\u0026#34;:\u0026#34;time2.log\u0026#34; 27} 配置项说明：\n1baseconfig: 2\ttcp_reuse # TCP连接复用 3\tfollow_redirect： #跟随重定向 4\tmax_redirects： #最大重定向次数 5\tdns_cache： # dns缓存，0为不缓存 6\ttimeout:\t#请求超时 7\tconnect_time\t#连接超时 8\tcert_check:\t忽略证书检查（https) 9\t10display: 11\tdata_size:\t# 显示下载，上传的数据大小，以及上载和上传的速度 12\tobdy:\t# 显示 html body 13request: 14\turl: # 要测试的url 15\tcount: # 测试的次数 16\thttp_header:\t#添加http header， （必须是数组类型） 17\tip_address:\t指定域名的IP，不通过DN解析 （必须是数组类型） 18\tpost:\t# 使用 post 请求 19\tpost_data:\t# post请求提交的数据，如果是json字符串，请转义,因为这个配置文件本身也是 json格式 20\tpost_data_file\t# 从一个文件读取内容，并提交 21\tlogfile:\t# 指定记录文件 request 配置中的 http_header , ip_address ，填写的时候，需要使用数组方式，如不需要，使用空值 null\n1[\u0026#34;192.168.121.171\u0026#34;, \u0026#34;172.19.79.136\u0026#34;, \u0026#34;17.93.2.88\u0026#34;] 2 3[\u0026#34;Content-Type:application/json\u0026#34;, \u0026#34;Connection: keep-alive\u0026#34;] 对于 POST 请求，如果需要提交数据的话，普通字符串，可以直接提交，部分特殊字符需要转义， 如单引号、双引号、百分号%（百分号仅限windows系统）。\n例如使用windows系统的客户端测试,post 请求时提交json字符串的情况，需要转下：例如： 正常的 json 字符串：\n1{\u0026#34;info\u0026#34;:{\u0026#34;name\u0026#34;:\u0026#34;zhangsan\u0026#34;,\u0026#34;age\u0026#34;:18}} 转义后的字符串：\n1{\\\u0026#34;info\\\u0026#34;:{\\\u0026#34;name\\\u0026#34;:\\\u0026#34;zhangsan\\\u0026#34;,\\\u0026#34;age\\\u0026#34;:18}} 转义后放可提交，例如：\n1chkurl.exe -c 3 -u https://www.lenovo.com.cn -p -d \u0026#39;{\\\u0026#34;info\\\u0026#34;:{\\\u0026#34;name\\\u0026#34;:\\\u0026#34;zhangsan\\\u0026#34;,\\\u0026#34;age\\\u0026#34;:18}}\u0026#39; 附： 程序源码\n1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3 4import logging 5# import certifi # windows 6import time 7import pycurl 8from io import BytesIO 9from urllib.parse import urlparse 10from optparse import OptionParser 11import json 12 13 14class ex_curl(object): 15 def __init__(self, url, max_redirs=None, forbid_flush=None, dns_cache=None, timeout=None, connect_time=None, headers=None, redirect=None, ssl_check=None): 16 \u0026#39;\u0026#39;\u0026#39; 17 self.c.setopt(pycurl.CAINFO, certifi.where()) # windows， 由于windows会报错找不到根证书，linux无需配置 18 self.c.setopt(pycurl.MAXREDIRS, 10) # 最大重定向次数 19 self.c.setopt(pycurl.FOLLOWLOCATION,1) # 跟踪重定向 20 self.c.setopt(pycurl.FORBID_REUSE, 1) # 交互完成后强制断开链接，不重用， 启用此项则每次都会重新建立TCP连接 21 self.c.setopt(pycurl.DNS_CACHE_TIMEOUT, 0) # DNS 缓存，单位 秒，0 不缓存，设置为0，则每次都会去尝试解析 22 self.c.setopt(pycurl.TIMEOUT,timeout) # 请求超时 23 self.c.setopt(pycurl.CONNECTTIMEOUT, connect_time) # 连接等街超时，0为不等待 24 self.c.setopt(pycurl.NOPROGRESS,1) # 屏蔽下载进度条 25 \u0026#39;\u0026#39;\u0026#39; 26 27 self.c = pycurl.Curl() 28 self.buffer = BytesIO() 29 30 # self.c.setopt(pycurl.CAINFO, certifi.where()) 31 self.c.setopt(pycurl.WRITEDATA, self.buffer) 32 self.c.setopt(pycurl.URL, url) 33 if ssl_check: 34 self.c.setopt(pycurl.SSL_VERIFYPEER, 0) 35 self.c.setopt(pycurl.SSL_VERIFYHOST, 0) 36 37 if max_redirs is None: 38 pass 39 else: 40 self.c.setopt(pycurl.MAXREDIRS, max_redirs) 41 42 if not forbid_flush: 43 self.c.setopt(pycurl.FORBID_REUSE, 1) 44 else: 45 self.c.setopt(pycurl.FORBID_REUSE, 0) 46 47 if dns_cache is None: 48 dns_cache = 0 49 self.c.setopt(pycurl.DNS_CACHE_TIMEOUT, dns_cache) 50 51 if not timeout is None: 52 self.c.setopt(pycurl.TIMEOUT, timeout) 53 54 if not connect_time is None: 55 self.c.setopt(pycurl.CONNECTTIMEOUT, connect_time) 56 if not headers is None: 57 self.c.setopt(pycurl.HTTPHEADER, headers) 58 if redirect: 59 self.c.setopt(pycurl.FOLLOWLOCATION, 1) 60 61 def GetRequest(self): 62 try: 63 self.c.perform() 64 except Exception as e: 65 print(\u0026#39;connection error:\u0026#39; + str(e)) 66 self.buffer.close() 67 self.c.close() 68 exit(2) 69 return self.c 70 71 def PostRequest(self, post_data=None): 72 if post_data is None: 73 post_data = \u0026#39;\u0026#39; 74 self.c.setopt(pycurl.POSTFIELDS, post_data) 75 try: 76 self.c.perform() 77 except Exception as e: 78 print(\u0026#39;connection error:\u0026#39; + str(e)) 79 self.buffer.close() 80 self.c.close() 81 exit(2) 82 return self.c 83 84 def getinfo(self): 85 h1 = self.c.getinfo(pycurl.HTTP_CODE) # 状态码 86 h2 = self.c.getinfo(pycurl.TOTAL_TIME) # 传输结束总消耗时间 87 h3 = self.c.getinfo(pycurl.NAMELOOKUP_TIME) # DNS解析时间 88 h4 = self.c.getinfo(pycurl.CONNECT_TIME) # 建立连接时间 89 h5 = self.c.getinfo(pycurl.PRETRANSFER_TIME) # 建立连接到准备传输消耗时间 90 h6 = self.c.getinfo(pycurl.STARTTRANSFER_TIME) # 从建立连接到传输开始消耗时间 91 h7 = self.c.getinfo(pycurl.REDIRECT_TIME) # 重定向消耗时间 92 h8 = self.c.getinfo(pycurl.SIZE_UPLOAD) # 上传数据包大小 93 h9 = self.c.getinfo(pycurl.SIZE_DOWNLOAD) # 下载数据包大小 94 h10 = self.c.getinfo(pycurl.SPEED_DOWNLOAD) # 平均下载速度 95 h11 = self.c.getinfo(pycurl.SPEED_UPLOAD) # 平均上传速度 96 h12 = self.c.getinfo(pycurl.HEADER_SIZE) # http头文件大小 97 98 info = {\u0026#39;body\u0026#39;: {}, \u0026#39;data\u0026#39;: {}} 99 info[\u0026#39;data\u0026#39;][\u0026#39;http_code\u0026#39;] = h1 100 info[\u0026#39;data\u0026#39;][\u0026#39;total_time\u0026#39;] = h2 * 1000 101 info[\u0026#39;data\u0026#39;][\u0026#39;namelookup_time\u0026#39;] = h3 * 1000 102 info[\u0026#39;data\u0026#39;][\u0026#39;connect_time\u0026#39;] = h4 * 1000 103 info[\u0026#39;data\u0026#39;][\u0026#39;pretransfer_time\u0026#39;] = h5 * 1000 104 info[\u0026#39;data\u0026#39;][\u0026#39;starttransfer_time\u0026#39;] = h6 * 1000 105 info[\u0026#39;data\u0026#39;][\u0026#39;redirect_time\u0026#39;] = h7 * 1000 106 info[\u0026#39;data\u0026#39;][\u0026#39;upload_size\u0026#39;] = h8 107 info[\u0026#39;data\u0026#39;][\u0026#39;download_size\u0026#39;] = h9 108 info[\u0026#39;data\u0026#39;][\u0026#39;download_speed\u0026#39;] = h10 109 info[\u0026#39;data\u0026#39;][\u0026#39;upload_speed\u0026#39;] = h11 110 info[\u0026#39;data\u0026#39;][\u0026#39;http_header_size\u0026#39;] = h12 111 112 # self.buffer.close() 113 # self.c.close() 114 115 # body = self.buffer.getvalue() 116 117 info[\u0026#39;body\u0026#39;] = self.buffer.getvalue() 118 self.buffer.truncate(0) 119 self.buffer.flush() 120 return info 121 # def GetHeader(self): 122 # return self.GetHeader(self.buffer) 123 124 def cls(self): 125 self.buffer.close() 126 self.c.close() 127 return None 128 129# def GetDomain(url): 130# domain = urlparse(url).netloc 131# if \u0026#34;:\u0026#34; in domain: 132# return domain.split(\u0026#34;:\u0026#34;) 133# return domain 134 135 136def Repurl(url, ip): 137 urlinfo = {} 138 domain = urlparse(url) 139 if \u0026#34;:\u0026#34; in domain.netloc: 140 hosts = domain.netloc.split(\u0026#34;:\u0026#34;) 141 url = domain.scheme + \u0026#34;://\u0026#34; + ip + \u0026#34;:\u0026#34;+hosts[1] + domain.path 142 if len(domain.query) \u0026gt; 0: 143 url += \u0026#34;?\u0026#34; + domain.query 144 if len(domain.fragment) \u0026gt; 0: 145 url += \u0026#34;#\u0026#34; + domain.fragment 146 147 urlinfo[\u0026#34;url\u0026#34;] = url 148 urlinfo[\u0026#34;domain\u0026#34;] = hosts[0] 149 return urlinfo 150 151 url = domain.scheme + \u0026#34;://\u0026#34; + ip + domain.path 152 if len(domain.query) \u0026gt; 0: 153 url += \u0026#34;?\u0026#34; + domain.query 154 if len(domain.fragment) \u0026gt; 0: 155 url += \u0026#34;#\u0026#34; + domain.fragment 156 157 urlinfo[\u0026#34;url\u0026#34;] = url 158 urlinfo[\u0026#34;domain\u0026#34;] = domain.netloc 159 return urlinfo 160 161 162if __name__ == \u0026#39;__main__\u0026#39;: 163 164 text1 = \u0026#34;usage: %prog - [OPTIONS] -u [url]\u0026#34; 165 166 parser = OptionParser(usage=text1) 167 168 parser.add_option( 169 \u0026#34;-e\u0026#34;, \u0026#34;--enable_reuse\u0026#34;, 170 action=\u0026#34;store_true\u0026#34;, 171 dest=\u0026#34;tcp_reuse\u0026#34;, 172 help=\u0026#34;Enable TCP connection reuse\u0026#34; 173 ) 174 parser.add_option( 175 \u0026#34;-k\u0026#34;, \u0026#34;--insecure\u0026#34;, 176 action=\u0026#34;store_true\u0026#34;, 177 dest=\u0026#34;cert_check\u0026#34;, 178 help=\u0026#34;Allow insecure server connections when using SSL\u0026#34; 179 ) 180 parser.add_option( 181 \u0026#34;-L\u0026#34;, \u0026#34;--location\u0026#34;, 182 action=\u0026#34;store_true\u0026#34;, 183 dest=\u0026#34;redirect\u0026#34;, 184 help=\u0026#34;Follow redirection, Default no,\u0026#34; 185 ) 186 parser.add_option( 187 \u0026#34;-r\u0026#34;, \u0026#34;--redirs_num\u0026#34;, 188 type=\u0026#34;int\u0026#34;, 189 action=\u0026#34;store\u0026#34;, 190 dest=\u0026#34;redirs\u0026#34;, 191 help=\u0026#34;Maximum number of redirects\u0026#34; 192 ) 193 parser.add_option( 194 \u0026#34;-D\u0026#34;, \u0026#34;--dns_cache\u0026#34;, 195 type=\u0026#34;int\u0026#34;, 196 action=\u0026#34;store\u0026#34;, 197 dest=\u0026#34;dns_cache\u0026#34;, 198 help=\u0026#34;DNS cache, 0 by default, no cache\u0026#34; 199 ) 200 parser.add_option( 201 \u0026#34;--timeout\u0026#34;, 202 type=\u0026#34;int\u0026#34;, 203 action=\u0026#34;store\u0026#34;, 204 dest=\u0026#34;timeout\u0026#34;, 205 help=\u0026#34;Request timeout\u0026#34; 206 ) 207 parser.add_option( 208 \u0026#34;--connect_time\u0026#34;, 209 type=\u0026#34;int\u0026#34;, 210 action=\u0026#34;store\u0026#34;, 211 dest=\u0026#34;connect_time\u0026#34;, 212 help=\u0026#34;Connect timeout\u0026#34; 213 ) 214 \u0026#39;\u0026#39;\u0026#39;end\u0026#39;\u0026#39;\u0026#39; 215 216 parser.add_option( 217 \u0026#34;-s\u0026#34;, \u0026#34;--size\u0026#34;, 218 action=\u0026#34;store_true\u0026#34;, 219 dest=\u0026#34;size\u0026#34;, 220 help=\u0026#34;Display the download and upload speed and data size\u0026#34; 221 ) 222 parser.add_option( 223 \u0026#34;-u\u0026#34;, \u0026#34;--url\u0026#34;, 224 action=\u0026#34;store\u0026#34;, 225 dest=\u0026#34;url\u0026#34;, 226 help=\u0026#34;Specify URL\u0026#34; 227 ) 228 parser.add_option( 229 \u0026#34;-c\u0026#34;, \u0026#34;--count\u0026#34;, 230 type=\u0026#34;int\u0026#34;, 231 action=\u0026#34;store\u0026#34;, 232 dest=\u0026#34;count\u0026#34;, 233 help=\u0026#34;Specify the number of tests\u0026#34; 234 ) 235 parser.add_option( 236 \u0026#34;-H\u0026#34;, \u0026#34;--header\u0026#34;, 237 action=\u0026#34;append\u0026#34;, 238 dest=\u0026#34;header\u0026#34;, 239 help=\u0026#34;Add http header, Multiple, please use comma to separate.\u0026#34; 240 ) 241 parser.add_option( 242 \u0026#34;-i\u0026#34;, \u0026#34;--ip_address\u0026#34;, 243 action=\u0026#34;append\u0026#34;, 244 dest=\u0026#34;ipaddress\u0026#34;, 245 help=\u0026#34;Specify IP address, bypass DNS resolution\u0026#34; 246 ) 247 parser.add_option( 248 \u0026#34;-p\u0026#34;, \u0026#34;--post\u0026#34;, 249 action=\u0026#34;store_true\u0026#34;, 250 dest=\u0026#34;post_commit\u0026#34;, 251 help=\u0026#34;Post request, Data must be submitted\u0026#34; 252 ) 253 parser.add_option( 254 \u0026#34;-d\u0026#34;, \u0026#34;--data\u0026#34;, 255 action=\u0026#34;store\u0026#34;, 256 dest=\u0026#34;post_data\u0026#34;, 257 help=\u0026#34;Define the data submitted by POST\u0026#34; 258 ) 259 parser.add_option( 260 \u0026#34;-F\u0026#34;, \u0026#34;--data_file\u0026#34;, 261 action=\u0026#34;store\u0026#34;, 262 dest=\u0026#34;post_data_file\u0026#34;, 263 help=\u0026#34;Submit POST data from file\u0026#34; 264 ) 265 266 \u0026#39;\u0026#39;\u0026#39;start, logging 处理\u0026#39;\u0026#39;\u0026#39; 267 parser.add_option( 268 \u0026#34;-l\u0026#34;, \u0026#34;--logfile\u0026#34;, 269 action=\u0026#34;store\u0026#34;, 270 dest=\u0026#34;logfile\u0026#34;, 271 help=\u0026#34;Define log file path\u0026#34; 272 ) 273 \u0026#39;\u0026#39;\u0026#39;end\u0026#39;\u0026#39;\u0026#39; 274 # body 275 parser.add_option( 276 \u0026#34;-b\u0026#34;, \u0026#34;--body\u0026#34;, 277 action=\u0026#34;store_true\u0026#34;, 278 dest=\u0026#34;body\u0026#34;, 279 help=\u0026#34;Displays the body of the page, Last One\u0026#34; 280 ) 281 (options, argv) = parser.parse_args() 282 283 if options.url is None: 284 print(\u0026#34;You did not specify a URL. Read the config.json configuration file\u0026#34;) 285 try: 286 with open(\u0026#34;config.json\u0026#34;, \u0026#34;rb\u0026#34;) as f: 287 glboal_conf = json.loads(f.read()) 288 f.close() 289 except Exception as e: 290 print(str(e)) 291 exit(2) 292 options.forbid_reuse = glboal_conf[\u0026#39;conf\u0026#39;][\u0026#39;baseconfig\u0026#39;][\u0026#39;tcp_reuse\u0026#39;] 293 options.redirect = glboal_conf[\u0026#39;conf\u0026#39;][\u0026#39;baseconfig\u0026#39;][\u0026#39;follow_redirect\u0026#39;] 294 options.redirs = glboal_conf[\u0026#39;conf\u0026#39;][\u0026#39;baseconfig\u0026#39;][\u0026#39;max_redirects\u0026#39;] 295 options.dns_cache = glboal_conf[\u0026#39;conf\u0026#39;][\u0026#39;baseconfig\u0026#39;][\u0026#39;dns_cache\u0026#39;] 296 options.timeout = glboal_conf[\u0026#39;conf\u0026#39;][\u0026#39;baseconfig\u0026#39;][\u0026#39;timeout\u0026#39;] 297 options.connect_time = glboal_conf[\u0026#39;conf\u0026#39;][\u0026#39;baseconfig\u0026#39;][\u0026#39;connect_time\u0026#39;] 298 options.cert_check = glboal_conf[\u0026#39;conf\u0026#39;][\u0026#39;baseconfig\u0026#39;][\u0026#39;cert_check\u0026#39;] 299 options.size = glboal_conf[\u0026#39;display\u0026#39;][\u0026#39;data_size\u0026#39;] 300 options.body = glboal_conf[\u0026#39;display\u0026#39;][\u0026#39;body\u0026#39;] 301 options.url = glboal_conf[\u0026#39;request\u0026#39;][\u0026#39;url\u0026#39;] 302 options.count = glboal_conf[\u0026#39;request\u0026#39;][\u0026#39;count\u0026#39;] 303 options.header = glboal_conf[\u0026#39;request\u0026#39;][\u0026#39;http_header\u0026#39;] 304 options.ipaddress = glboal_conf[\u0026#39;request\u0026#39;][\u0026#39;ip_address\u0026#39;] 305 options.post_commit = glboal_conf[\u0026#39;request\u0026#39;][\u0026#39;post\u0026#39;] 306 options.post_data = glboal_conf[\u0026#39;request\u0026#39;][\u0026#39;post_data\u0026#39;] 307 options.post_data_file = glboal_conf[\u0026#39;request\u0026#39;][\u0026#39;post_data_file\u0026#39;] 308 options.logfile = glboal_conf[\u0026#39;logfile\u0026#39;] 309 310 # if options.count is None or not options.count.isdigit(): 311 # print(\u0026#34;Error! You must specify a number of tests\u0026#34;) 312 # print(\u0026#34;Use -h to view help.\u0026#34;) 313 # exit(2) 314 315 exec_time = time.strftime(\u0026#34;%Y-%m-%d %H:%M:%S\u0026#34;, time.localtime(time.time())) 316 # logging.info(exec_time) 317 if options.logfile is None: 318 log_file = \u0026#34;time.log\u0026#34; 319 else: 320 log_file = options.logfile 321 322 logger = logging.getLogger() 323 logger.setLevel(logging.DEBUG) 324 formatter = logging.Formatter(\u0026#34;%(message)s\u0026#34;) 325 326 fh = logging.FileHandler(log_file, mode=\u0026#39;a\u0026#39;) 327 fh.setLevel(logging.DEBUG) 328 fh.setFormatter(formatter) 329 logger.addHandler(fh) 330 331 ch = logging.StreamHandler() 332 ch.setLevel(logging.DEBUG) 333 ch.setFormatter(formatter) 334 logger.addHandler(ch) 335 logger.info(\u0026#34;%s Test Website: %s, \\tNumber of tests: %s\u0026#34; % 336 (exec_time, options.url, options.count)) 337 338 # 如果指定了IP地址的话，则将请求的URL中的域名部分，换成IP地址， 339 # 将URL拆分之后再重新拼接，目前使用的 urllib.parse urlparse (urlsplit) 340 # 考虑到 带端口的情况，所以如果携带了端口，还需要把端口单独分开 341 # 在指定了 IP 地址的时候，必须带上协议 即 http:// 或者 https:// 342 343 if not options.ipaddress is None: 344 list1 = {} 345 for ips in options.ipaddress: 346 # list1 = {ips:{\u0026#39;data\u0026#39;:[]}} 347 list1[ips] = {\u0026#39;data\u0026#39;: []} 348 req_url = Repurl(options.url, ips) 349 header_list = [] 350 header_list.append(\u0026#34;Host: \u0026#34; + req_url[\u0026#34;domain\u0026#34;]) 351 if not options.header is None: 352 for x in options.header: 353 header_list.append(x) 354 t = ex_curl(req_url[\u0026#34;url\u0026#34;], options.redirs, options.tcp_reuse, 355 options.dns_cache, options.timeout, options.connect_time, header_list, options.redirect, ssl_check=options.cert_check) 356 # print(header_list) 357 # 占位 358 # print(options.header) 359 360 post_req = False 361 if options.post_commit: 362 # if not options.post_data is None and not options.post_data_file is None: 363 # print(\u0026#34;No submitt PostD ATA\u0026#34;) 364 # print(\u0026#34;Use Post request, Use with -d or -D\u0026#34;) 365 # exit(2) 366 if not options.post_data is None: 367 post_req = True 368 post_req_data = options.post_data 369 370 if not options.post_data_file is None: 371 print(options.post_data_file) 372 try: 373 with open(options.post_data_file, \u0026#34;r\u0026#34;) as f: 374 post_req_data = f.read() 375 f.close() 376 except Exception as e: 377 print(str(e)) 378 exit(2) 379 post_req = True 380 # print(post_req_data) 381 post_req = True 382 post_req_data = None 383 # print(header_list) 384 385 for i in range(0, options.count): 386 if post_req: 387 t.PostRequest(post_req_data) 388 else: 389 t.GetRequest() 390 s1 = t.getinfo() 391 392 list1[ips][\u0026#39;data\u0026#39;].append(s1[\u0026#39;data\u0026#39;]) 393 394 if options.body: 395 print(list1[\u0026#39;body\u0026#39;]) 396 t.cls() 397 print(list1) 398 else: 399 list1 = [] 400 list2 = [] 401 t = ex_curl(options.url, options.redirs, options.tcp_reuse, 402 options.dns_cache, options.timeout, options.connect_time, options.header, options.redirect, options.cert_check) 403 post_req = False 404 if options.post_commit: 405 # if not options.post_data is None and not options.post_data_file is None: 406 # print(\u0026#34;No submitt PostD ATA\u0026#34;) 407 # print(\u0026#34;Use Post request, Use with -d or -D\u0026#34;) 408 # exit(2) 409 if not options.post_data is None: 410 post_req = True 411 post_req_data = options.post_data 412 413 if not options.post_data_file is None: 414 try: 415 with open(options.post_data_file, \u0026#34;r\u0026#34;) as f: 416 post_req_data = f.read() 417 f.close() 418 except Exception as s: 419 print(str(s)) 420 exit(2) 421 post_req = True 422 # print(post_req_data) 423 post_req_data = options.post_data 424 post_req = True 425 # print(header_list) 426 427 for i in range(0, options.count): 428 if post_req: 429 t.PostRequest(post_req_data) 430 else: 431 t.GetRequest() 432 s1 = t.getinfo() 433 list1.append(s1[\u0026#39;data\u0026#39;]) 434 list2.append(s1[\u0026#34;body\u0026#34;]) 435 if options.body: 436 print(list2[\u0026#39;body\u0026#39;][0].decode(\u0026#39;utf-8\u0026#39;)) 437 t.cls() 438 439 if options.size: 440 d = { 441 \u0026#39;HTTP Code:\\t\u0026#39;: \u0026#39;http_code\u0026#39;, 442 \u0026#39;Total Time:\\t\u0026#39;: \u0026#39;total_time\u0026#39;, 443 \u0026#39;DNS Lookup:\\t\u0026#39;: \u0026#39;namelookup_time\u0026#39;, 444 \u0026#39;TCP Connect:\\t\u0026#39;: \u0026#39;connect_time\u0026#39;, 445 \u0026#39;Pretransfer:\\t\u0026#39;: \u0026#39;pretransfer_time\u0026#39;, 446 \u0026#39;StartTransfer:\\t\u0026#39;: \u0026#39;starttransfer_time\u0026#39;, 447 \u0026#39;Redirect:\\t\u0026#39;: \u0026#39;redirect_time\u0026#39;, 448 \u0026#39;Download Size:\\t\u0026#39;: \u0026#39;download_size\u0026#39;, 449 \u0026#39;Upload Size:\\t\u0026#39;: \u0026#39;upload_size\u0026#39;, 450 \u0026#39;Download Speed:\\t\u0026#39;: \u0026#39;download_speed\u0026#39;, 451 \u0026#39;Upload Speed:\\t\u0026#39;: \u0026#39;upload_speed\u0026#39;, 452 \u0026#39;Header Size:\\t\u0026#39;: \u0026#39;http_header_size\u0026#39; 453 } 454 else: 455 d = { 456 \u0026#39;HTTP Code:\\t\u0026#39;: \u0026#39;http_code\u0026#39;, 457 \u0026#39;Total Time:\\t\u0026#39;: \u0026#39;total_time\u0026#39;, 458 \u0026#39;DNS Lookup:\\t\u0026#39;: \u0026#39;namelookup_time\u0026#39;, 459 \u0026#39;TCP Connect:\\t\u0026#39;: \u0026#39;connect_time\u0026#39;, 460 \u0026#39;Pretransfer:\\t\u0026#39;: \u0026#39;pretransfer_time\u0026#39;, 461 \u0026#39;StartTransfer:\\t\u0026#39;: \u0026#39;starttransfer_time\u0026#39;, 462 \u0026#39;Redirect:\\t\u0026#39;: \u0026#39;redirect_time\u0026#39;, 463 \u0026#39;Header Size:\\t\u0026#39;: \u0026#39;http_header_size\u0026#39; 464 } 465 466 # print(list1) 467 468 if options.ipaddress: 469 for ips2 in options.ipaddress: 470 logging.info(ips2) 471 for i, n in (d.items()): 472 # print(i, end=\u0026#39;\u0026#39;) 473 text2 = i 474 temp_list = [] 475 for b in range(0, len(list1[ips2][\u0026#39;data\u0026#39;])): 476 temp_list.append(list1[ips2][\u0026#39;data\u0026#39;][b][n]) 477 if n == \u0026#34;download_speed\u0026#34; or n == \u0026#34;upload_speed\u0026#34;: 478 text2 += \u0026#34;No.%d: %.2f bytes/s, \u0026#34; % ( 479 b + 1, list1[ips2][\u0026#39;data\u0026#39;][b][n]) 480 elif n == \u0026#34;download_size\u0026#34; or n == \u0026#34;upload_size\u0026#34;: 481 text2 += \u0026#34;No.%d: %.2f bytes, \u0026#34; % ( 482 b + 1, list1[ips2][\u0026#39;data\u0026#39;][b][n]) 483 elif (type(list1[ips2][\u0026#39;data\u0026#39;][b][n]) == float): 484 text2 += \u0026#34;No.%d: %.2f ms, \u0026#34; % (b + 1, 485 list1[ips2][\u0026#39;data\u0026#39;][b][n]) 486 else: 487 text2 += \u0026#34;No.%d: %d, \u0026#34; % (b + 1, 488 list1[ips2][\u0026#39;data\u0026#39;][b][n]) 489 490 if n == \u0026#34;http_code\u0026#34; or n == \u0026#34;http_header_size\u0026#34;: 491 pass 492 else: 493 text2 += \u0026#34;\\t[Min: %.2f, Max: %.2f, Avg: %.2f]\u0026#34; % ( 494 min(temp_list), max(temp_list), sum(temp_list)/len(temp_list)) 495 logging.info(text2) 496 logging.info(\u0026#34;\\n\u0026#34;) 497 else: 498 for i, n in (d.items()): 499 # print(i, end=\u0026#39;\u0026#39;) 500 text2 = i 501 temp_list = [] 502 503 for b in range(0, len(list1)): 504 temp_list.append(list1[b][n]) 505 if n == \u0026#34;download_speed\u0026#34; or n == \u0026#34;upload_speed\u0026#34;: 506 text2 += \u0026#34;No.%d: %.2f bytes/s, \u0026#34; % (b + 1, list1[b][n]) 507 elif n == \u0026#34;download_size\u0026#34; or n == \u0026#34;upload_size\u0026#34;: 508 text2 += \u0026#34;No.%d: %.2f bytes, \u0026#34; % (b + 1, list1[b][n]) 509 elif (type(list1[b][n]) == float): 510 text2 += \u0026#34;No.%d: %.2f ms, \u0026#34; % (b + 1, list1[b][n]) 511 else: 512 text2 += \u0026#34;No.%d: %d, \u0026#34; % (b + 1, list1[b][n]) 513 514 if n == \u0026#34;http_code\u0026#34; or n == \u0026#34;http_header_size\u0026#34;: 515 pass 516 else: 517 text2 += \u0026#34;\\t[Min: %.2f, Max: %.2f, Avg: %.2f]\u0026#34; % ( 518 min(temp_list), max(temp_list), sum(temp_list)/len(temp_list)) 519 logging.info(text2) 520 logging.info(\u0026#34;\\n\u0026#34;) ","link":"http://test.mylass.com/python/web-service-quality/","section":"python","tags":["python","pycurl","web"],"title":"pycurl 实现web服务质量探测"},{"body":"","link":"http://test.mylass.com/tags/web/","section":"tags","tags":null,"title":"web"},{"body":"","link":"http://test.mylass.com/tags/k8s/","section":"tags","tags":null,"title":"k8s"},{"body":"","link":"http://test.mylass.com/series/k8s/","section":"series","tags":null,"title":"k8s"},{"body":"他是一个全新的基于容器技术的分布式架构领先方案。Kubernetes(k8s)是Google开源的容器集群管理系统（谷歌内部:Borg）。\n在Docker技术的基础上，为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能，提高了大规模容器集群管理的便捷性。\nKubernetes是一个完备的分布式系统支撑平台，具有完备的集群管理能力，多扩多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和发现机制、 內建智能负载均衡器、强大的故障发现和自我修复能力、服务滚动升级和在线扩容能力、 可扩展的资源自动调度机制以及多粒度的资源配额管理能力。 同时Kubernetes提供完善的管理工具，涵盖了包括开发、部署测试、运维监控在内的各个环节\nCentOs7安装Kubernetes kubeadm介绍 1kubeadm是Kubernetes官方提供的用于快速安装Kubernetes集群的工具，伴随Kubernetes每个版本的发布都会同步更新，kubeadm会对集群配置方面的一些实践做调整，通过实验kubeadm可以学习到Kubernetes官方在集群配置上一些新的最佳实践。 安装方式 1kubeadm 简单方便 2一个个组件安装，以守护进程方式安装 环境准备如下 IP地址 主机名 172.19.33.174 master.zj.com 172.19.33.175 node1.zj.com 172.19.33.176 node2.zj.com 配置host 1master如下： 2172.19.33.174 master.zj.com 3172.19.33.175 node1.zj.com 4172.19.33.176 node2.zj.com 5node1如下 6172.19.33.174 master.zj.com 7172.19.33.175 node1.zj.com 8172.19.33.176 node2.zj.com 9node2如下 10172.19.33.174 master.zj.com 11172.19.33.175 node1.zj.com 12172.19.33.176 node2.zj.com 配置 SSH 免密码登录登录 1ssh-keygen 三台机器都要执行 2master执行如下 3ssh-copy-id node1.zj.com 4ssh-copy-id node2.zj.com 5node1执行如下 6ssh-copy-id master.zj.com 7ssh-copy-id node2.zj.com 8node2执行如下 9ssh-copy-id master.zj.com 10ssh-copy-id node1.zj.com 配置阿里云的yum镜像源 docker镜像源 1cd /etc/yum.repos.d/ 2wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo kubernetes镜像源 1cat \u0026lt;\u0026lt;EOF \u0026gt; /etc/yum.repos.d/kubernetes.repo 2[kubernetes] 3name=Kubernetes 4baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 5enabled=1 6gpgcheck=1 7repo_gpgcheck=1 8gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg 9EOF 建立yum缓存 1yum clean all 2yum makecache 3要删除/var/run/yum.pid就可以正常使用了，即rm -rf /var/run/yum.pid 关闭防火墙 1# 每台服务器都要关闭，不关闭kubernetes会执行防火墙操作 2systemctl stop firewalld \u0026amp;\u0026amp; systemctl disable firewalld 关闭交换分区 1swapoff -a 2free -h #查看下 3#关闭后的total应该是0 4#编辑配置文件： /etc/fstab ,注释最后一条 /dev/mapper/centos-swap swap， 5sed -i \u0026#34;s/\\/dev\\/mapper\\/centos-swap/# \\/dev\\/mapper\\/centos-swap/\u0026#34; /etc/fstab 6cat /etc/fstab 关闭 SeLinux 1setenforce 0 2sed -i \u0026#39;s#SELINUX=enforcing#SELINUX=disabled#g\u0026#39; /etc/selinux/config 3cat /etc/selinux/config 4SELINUX=disabled 配置iptable 1# 三台都执行 2cat \u0026lt;\u0026lt;EOF \u0026gt; /etc/sysctl.d/k8s.conf 3net.bridge.bridge-nf-call-ip6tables = 1 4net.bridge.bridge-nf-call-iptables = 1 5EOF 6sysctl --system 安装网络工具包和基础工具包 1yum install net-tools checkpolicy gcc dkms foomatic openssh-server bash-completion -y 安装相关组件 1# master,node都需要安装 2yum install docker-ce-18.06.2.ce -y 3yum install kubelet-1.14.2 kubeadm-1.14.2 kubectl-1.14.2 -y 配置国内docker镜像仓库加速器和cgroup修改为systemd 1mkdir -p /etc/docker 2cat \u0026gt; /etc/docker/daemon.json \u0026lt;\u0026lt;EOF 3{ 4 \u0026#34;registry-mirrors\u0026#34;: [\u0026#34;https://okxfxhu4.mirror.aliyuncs.com\u0026#34;], 5 \u0026#34;exec-opts\u0026#34;: [\u0026#34;native.cgroupdriver=systemd\u0026#34;], 6 \u0026#34;log-driver\u0026#34;: \u0026#34;json-file\u0026#34;, 7 \u0026#34;log-opts\u0026#34;: { 8 \u0026#34;max-size\u0026#34;: \u0026#34;100m\u0026#34; 9 }, 10 \u0026#34;storage-driver\u0026#34;: \u0026#34;overlay2\u0026#34;, 11 \u0026#34;storage-opts\u0026#34;: [ 12 \u0026#34;overlay2.override_kernel_check=true\u0026#34; 13 ] 14} 15EOF 启动docker 1systemctl daemon-reload 2systemctl enable docker 3systemctl start docker 查看systemd 1docker info |grep Cgroup 加载IPVS内核 1modprobe ip_vs_rr 2modprobe ip_vs_wrr 3modprobe ip_vs_sh 并添加到开机启动文件/etc/rc.local里面。 1cat \u0026lt;\u0026lt;EOF \u0026gt;\u0026gt; /etc/rc.local 2modprobe ip_vs_rr 3modprobe ip_vs_wrr 4modprobe ip_vs_sh 5EOF 6source /etc/rc.local 安装 master 节点 因为国内没办法访问Google的镜像源，变通的方法是从其他镜像源下载后，注意下载的版本尽量和我们的kubeadm等版本一样，我们选择v1.14.2，修改tag。执行下面这个Shell脚本即可。\n1#!/bin/bash 2kube_version=:v1.14.2 3kube_images=(kube-proxy kube-scheduler kube-controller-manager kube-apiserver) 4addon_images=(etcd-amd64:3.3.10 coredns:1.3.1 pause-amd64:3.1) 5 6for imageName in ${kube_images[@]} ; do 7 docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName-amd64$kube_version 8 docker image tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName-amd64$kube_version k8s.gcr.io/$imageName$kube_version 9 docker image rm registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName-amd64$kube_version 10done 11 12for imageName in ${addon_images[@]} ; do 13 docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName 14 docker image tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName k8s.gcr.io/$imageName 15 docker image rm registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName 16done 17 18docker tag k8s.gcr.io/etcd-amd64:3.3.10 k8s.gcr.io/etcd:3.3.10 19docker image rm k8s.gcr.io/etcd-amd64:3.3.10 20docker tag k8s.gcr.io/pause-amd64:3.1 k8s.gcr.io/pause:3.1 21docker image rm k8s.gcr.io/pause-amd64:3.1 在master查看相关镜像 1docker images 2REPOSITORY TAG IMAGE ID CREATED SIZE 3k8s.gcr.io/kube-proxy v1.14.2 5c24210246bb 7 days ago 82.1MB 4k8s.gcr.io/kube-apiserver v1.14.2 5eeff402b659 7 days ago 210MB 5k8s.gcr.io/kube-controller-manager v1.14.2 8be94bdae139 7 days ago 158MB 6k8s.gcr.io/kube-scheduler v1.14.2 ee18f350636d 7 days ago 81.6MB 7k8s.gcr.io/coredns 1.3.1 eb516548c180 4 months ago 40.3MB 8k8s.gcr.io/etcd 3.3.10 2c4adeb21b4f 5 months ago 258MB 9k8s.gcr.io/pause 3.1 da86e6ba6ca1 17 months ago 742kB 设置kubelet开机启动 1systemctl enable kubelet 修改swap内存 1sed -i \u0026#34;s/KUBELET_EXTRA_ARGS=/KUBELET_EXTRA_ARGS=\\\u0026#34;--fail-swap-on=false\\\u0026#34;/\u0026#34; /etc/sysconfig/kubelet 2cat /etc/sysconfig/kubelet 3KUBELET_EXTRA_ARGS=\u0026#34;--fail-swap-on=false\u0026#34; 使用kubeadm init自动安装 Master 节点，需要指定版本 init初始化 1kubeadm init --kubernetes-version=v1.14.2 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 2# 服务启动后需要根据输出提示，进行配置： 3mkdir -p $HOME/.kube 4sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config 5sudo chown $(id -u):$(id -g) $HOME/.kube/config 查看相关状态 1kubectl get pod -n kube-system -owide 2NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES 3coredns-fb8b8dccf-br8lt 0/1 Pending 0 118s \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 4coredns-fb8b8dccf-kv5st 0/1 Pending 0 118s \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 5etcd-zj.ops.master 1/1 Running 0 78s 172.19.33.174 zj.ops.master \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 6kube-apiserver-zj.ops.master 1/1 Running 0 71s 172.19.33.174 zj.ops.master \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 7kube-controller-manager-zj.ops.master 1/1 Running 0 79s 172.19.33.174 zj.ops.master \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 8kube-proxy-hg24l 1/1 Running 0 118s 172.19.33.174 zj.ops.master \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 9kube-scheduler-zj.ops.master 1/1 Running 0 60s 给pod配置网络 1# pod网络插件是必要安装，以便pod可以相互通信。在部署应用和启动kube-dns之前，需要部署网络，kubeadm仅支持CNI的网络 2 3# pod支持的网络插件有很多，如Calico，Canal，Flannel，Romana，Weave Net等，因为之前我们初始化使用了参数--pod-network-cidr=10.244.0.0/16，所以我们使用插件flannel 4kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/bc79dd1505b0c8681ece4de4c0d86c5cd2643275/Documentation/kube-flannel.yml 5检查是否正常启动，因为要下载flannel镜像，需要时间会稍微长一些 6kubectl get pods --all-namespaces 7NAMESPACE NAME READY STATUS RESTARTS AGE 8kube-system coredns-fb8b8dccf-hzlc7 0/1 ContainerCreating 0 3m54s 9kube-system coredns-fb8b8dccf-xsxrf 0/1 ContainerCreating 0 3m54s 10kube-system etcd-master.zj.com 1/1 Running 0 2m57s 11kube-system kube-apiserver-master.zj.com 1/1 Running 0 3m15s 12kube-system kube-controller-manager-master.zj.com 1/1 Running 0 3m8s 13kube-system kube-flannel-ds-amd64-h2mcw 1/1 Running 0 25s 14kube-system kube-proxy-m4tng 1/1 Running 0 3m53s 15kube-system kube-scheduler-master.zj.com 1/1 Running 0 3m12s 故障排查思路： 1确认端口和容器是否正常启动，查看 /var/log/message日志信息 2通过docker logs ID查看容器的启动日志，特别是频繁创建的容器 3使用kubectl --namespace=kube-system describe pod POD-NAME查看错误状态的pod日志。 4使用kubectl -n ${NAMESPACE} logs ${POD_NAME} -c ${CONTAINER_NAME}查看具体错误。 5Calico - Canal - Flannel已经被官方验证过，其他的网络插件有可能有坑，能不能爬出来就看个人能力了。 6一般常见的错误是镜像名称版本不对或者镜像无法下载。 安装node节点 1#!/bin/bash 2 3kube_version=:v1.14.2 4coredns_version=1.3.1 5pause_version=3.1 6 7docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy-amd64$kube_version 8docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy-amd64$kube_version k8s.gcr.io/kube-proxy$kube_version 9docker image rm registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy-amd64$kube_version 10 11docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause-amd64:$pause_version 12docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/pause-amd64:$pause_version k8s.gcr.io/pause:$pause_version 13docker image rm registry.cn-hangzhou.aliyuncs.com/google_containers/pause-amd64:$pause_version 14 15docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:$coredns_version 16docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:$coredns_version k8s.gcr.io/coredns:$coredns_version 17docker image rm registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:$coredns_version 查看下载好的镜像 1docker images 2REPOSITORY TAG IMAGE ID CREATED SIZE 3k8s.gcr.io/kube-proxy v1.14.2 5c24210246bb 8 days ago 82.1MB 4k8s.gcr.io/coredns 1.3.1 eb516548c180 4 months ago 40.3MB 5k8s.gcr.io/pause 3.1 da86e6ba6ca1 17 months ago 742kB 添加节点(node1为例) 1kubeadm join 172.19.33.174:6443 --token d58cn9.j4oa27ryu0h5901h \\ 2 --discovery-token-ca-cert-hash sha256:6cbc7333b1e054fd3ebb2c68e4f148c8ad73f29b7aee38070eac535e3b9b2b3b 3# 上面的是key生成是kubeadm init产生的用于加入node节点到mater 4kubeadm token create --print-join-command 5# 查看master初始化信息 6# 按照提示在Master 上执行kubeadm token create生成一个新的token 7# 如果忘记key的话，可以使用kubeadm token list查看 8# node2执行相同的操作 在master执行，看到node节点加入进来\n查看node情况 1kubectl get nodes 2NAME STATUS ROLES AGE VERSION 3master.zj.com Ready master 64m v1.14.2 4node1.zj.com Ready \u0026lt;none\u0026gt; 2m38s v1.14.2 5node2.zj.com NotReady \u0026lt;none\u0026gt; 6s v1.14.2 node节点配置文件 1# 可以把master节点的配置文件放到node节点上面，方便node节点使用kubectl 2node节点上可能没有这个文件 3mkdir -p /root/.kube 4 5node1 6scp /etc/kubernetes/admin.conf 172.16.8.140:/root/.kube/config 7node2 8scp /etc/kubernetes/admin.conf 172.16.8.143:/root/.kube/config 9node3 10scp /etc/kubernetes/admin.conf 172.16.8.155:/root/.kube/config Master 节点上查看 Pod 运行状态 1kubectl get pods -n kube-system -o wide 2NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES 3coredns-fb8b8dccf-4ckv9 1/1 Running 0 38m 10.244.1.2 node1.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 4coredns-fb8b8dccf-dlrb9 1/1 Running 0 38m 10.244.1.3 node1.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 5etcd-master.liudehan.com 1/1 Running 0 37m 172.16.8.153 master.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 6kube-apiserver-master.liudehan.com 1/1 Running 0 37m 172.16.8.153 master.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 7kube-controller-manager-master.liudehan.com 1/1 Running 0 37m 172.16.8.153 master.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 8kube-flannel-ds-amd64-8vd2h 1/1 Running 0 9m16s 172.16.8.143 node2.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 9kube-flannel-ds-amd64-9mb9m 1/1 Running 0 10m 172.16.8.140 node1.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 10kube-flannel-ds-amd64-n28tx 1/1 Running 0 9m9s 172.16.8.155 node3.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 11kube-flannel-ds-amd64-nh2dl 0/1 Init:ImagePullBackOff 0 30m 172.16.8.153 master.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 12kube-proxy-6knch 1/1 Running 0 9m16s 172.16.8.143 node2.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 13kube-proxy-l7gvg 1/1 Running 0 9m9s 172.16.8.155 node3.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 14kube-proxy-lm4lz 1/1 Running 0 10m 172.16.8.140 node1.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 15kube-proxy-qc7sn 1/1 Running 0 38m 172.16.8.153 master.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 16kube-scheduler-master.liudehan.com 1/1 Running 0 37m 172.16.8.153 master.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 17 18# kube-flannel 在每一个 Node 节点上都有运行 更改kube-proxy配置 1kubectl edit configmap kube-proxy -n kube-system 2# 找到如下部分。 3 4 kind: KubeProxyConfiguration 5 metricsBindAddress: 127.0.0.1:10249 6 mode: \u0026#34;ipvs\u0026#34; 7 nodePortAddresses: null 8 oomScoreAdj: -999 9其中mode原来是空，默认为iptables模式，改为ipvs。scheduler默认是空，默认负载均衡算法为轮训 删除node 封锁node，排干node上的pod 1kubectl drain node3.liudehan.com --delete-local-data --force --ignore-daemonsets 删除node3节点 1kubectl delete node node3.liudehan.com 2node \u0026#34;node3.liudehan.com\u0026#34; deleted 3# 在查看发现node3已经不在master节点了 4kubectl get nodes 5NAME STATUS ROLES AGE VERSION 6master.liudehan.com NotReady master 57m v1.14.2 7node1.liudehan.com Ready \u0026lt;none\u0026gt; 28m v1.14.2 8node2.liudehan.com Ready \u0026lt;none\u0026gt; 28m v1.14.2 node3上的pod已经调度到node2 1[root@master] ~$ kubectl get pods -o wide 2NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES 3curl-66959f6557-r4crd 1/1 Running 1 8m34s 10.244.2.7 slave2.hanli.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 4nginx-58db6fdb58-5wt7p 1/1 Running 0 3d6h 10.244.1.4 slave1.hanli.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 5nginx-58db6fdb58-bhmcv 1/1 Running 0 55s 10.244.2.8 slave2.hanli.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 6 7# slave3上执行 8# 在 Node 被删除,需要重启所有 kubeadm 安装状态 9kubeadm reset 重新使node加入集群 1kubeadm join 172.16.8.153:6443 --token 92sot3.g1nyzz82hehvgqh8 \\ 2--discovery-token-ca-cert-hash sha256:8d69226b405ab30faa52c884502a00485390fcbc2e0669f6c2c7c5fa2f85392d k8s上部署一个Whoami 在Master运行部署Whoami 1kubectl create deployment whoami --image=idoall/whoami 2deployment.apps/whoami created 查看Whoami部署状态 1kubectl get deployments 2NAME READY UP-TO-DATE AVAILABLE AGE 3whoami 5/5 5 5 59m 查看Whoami的部署信息 1kubectl get deployments 2NAME READY UP-TO-DATE AVAILABLE AGE 3whoami 5/5 5 5 59m 4[root@master _src]# kubectl describe deployment whoami 5Name: whoami 6Namespace: default 7CreationTimestamp: Sat, 25 May 2019 18:09:18 +0800 8Labels: app=whoami 9Annotations: deployment.kubernetes.io/revision: 1 10Selector: app=whoami 11Replicas: 5 desired | 5 updated | 5 total | 5 available | 0 unavailable 12StrategyType: RollingUpdate 13MinReadySeconds: 0 14RollingUpdateStrategy: 25% max unavailable, 25% max surge 15Pod Template: 16 Labels: app=whoami 17 Containers: 18 whoami: 19 Image: idoall/whoami 20 Port: \u0026lt;none\u0026gt; 21 Host Port: \u0026lt;none\u0026gt; 22 Environment: \u0026lt;none\u0026gt; 23 Mounts: \u0026lt;none\u0026gt; 24 Volumes: \u0026lt;none\u0026gt; 25Conditions: 26 Type Status Reason 27 ---- ------ ------ 28 Progressing True NewReplicaSetAvailable 29 Available True MinimumReplicasAvailable 30OldReplicaSets: \u0026lt;none\u0026gt; 31NewReplicaSet: whoami-8657469579 (5/5 replicas created) 32Events: \u0026lt;none\u0026gt; 查看Whoami的容器日志 1kubectl describe po whoami 2 3Name: whoami-8657469579-6thrj 4Namespace: default 5Priority: 0 6PriorityClassName: \u0026lt;none\u0026gt; 7Node: node3.liudehan.com/172.16.8.155 8Start Time: Sat, 25 May 2019 18:15:27 +0800 9Labels: app=whoami 10 pod-template-hash=8657469579 11Annotations: \u0026lt;none\u0026gt; 12Status: Running 13IP: 10.244.4.3 14Controlled By: ReplicaSet/whoami-8657469579 15Containers: 16 whoami: 17 Container ID: docker://57676edcf1d7620fc3710a5ab376b94212d1ab9bc89b6e3b48301b73d8748918 18 Image: idoall/whoami 19 Image ID: docker-pullable://idoall/whoami@sha256:6e79f7182eab032c812f6dafdaf55095409acd64d98a825c8e4b95e173e198f2 20 Port: \u0026lt;none\u0026gt; 21 Host Port: \u0026lt;none\u0026gt; 22 State: Running 23 Started: Sat, 25 May 2019 18:15:36 +0800 24 Ready: True 25 Restart Count: 0 26 Environment: \u0026lt;none\u0026gt; 27 Mounts: 28 /var/run/secrets/kubernetes.io/serviceaccount from default-token-4zswl (ro) 29Conditions: 30 Type Status 31 Initialized True 32 Ready True 33 ContainersReady True 34 PodScheduled True 35Volumes: 36 default-token-4zswl: 37 Type: Secret (a volume populated by a Secret) 38 SecretName: default-token-4zswl 39 Optional: false 40QoS Class: BestEffort 41Node-Selectors: \u0026lt;none\u0026gt; 42Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s 43 node.kubernetes.io/unreachable:NoExecute for 300s 44Events: \u0026lt;none\u0026gt; 45 46Name: whoami-8657469579-k2db4 47Namespace: default 48Priority: 0 49PriorityClassName: \u0026lt;none\u0026gt; 50Node: node3.liudehan.com/172.16.8.155 51Start Time: Sat, 25 May 2019 18:15:27 +0800 52Labels: app=whoami 53 pod-template-hash=8657469579 54Annotations: \u0026lt;none\u0026gt; 55Status: Running 56IP: 10.244.4.2 57Controlled By: ReplicaSet/whoami-8657469579 58Containers: 59 whoami: 60 Container ID: docker://cfae50bf7fd21386fb6fca2986adaf091f047b4dbe759de177317d5d828e73d1 61 Image: idoall/whoami 62 Image ID: docker-pullable://idoall/whoami@sha256:6e79f7182eab032c812f6dafdaf55095409acd64d98a825c8e4b95e173e198f2 63 Port: \u0026lt;none\u0026gt; 64 Host Port: \u0026lt;none\u0026gt; 65 State: Running 66 Started: Sat, 25 May 2019 18:15:35 +0800 67 Ready: True 68 Restart Count: 0 69 Environment: \u0026lt;none\u0026gt; 70 Mounts: 71 /var/run/secrets/kubernetes.io/serviceaccount from default-token-4zswl (ro) 72Conditions: 73 Type Status 74 Initialized True 75 Ready True 76 ContainersReady True 77 PodScheduled True 78Volumes: 79 default-token-4zswl: 80 Type: Secret (a volume populated by a Secret) 81 SecretName: default-token-4zswl 82 Optional: false 83QoS Class: BestEffort 84Node-Selectors: \u0026lt;none\u0026gt; 85Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s 86 node.kubernetes.io/unreachable:NoExecute for 300s 87Events: \u0026lt;none\u0026gt; 88 89Name: whoami-8657469579-rtsr4 90Namespace: default 91Priority: 0 92PriorityClassName: \u0026lt;none\u0026gt; 93Node: node2.liudehan.com/172.16.8.143 94Start Time: Sat, 25 May 2019 18:15:23 +0800 95Labels: app=whoami 96 pod-template-hash=8657469579 97Annotations: \u0026lt;none\u0026gt; 98Status: Running 99IP: 10.244.2.3 100Controlled By: ReplicaSet/whoami-8657469579 101Containers: 102 whoami: 103 Container ID: docker://89f518bd04ff6830e252e6e45004eb0d7aa64d0acc7550d432ccffda12d5f2d7 104 Image: idoall/whoami 105 Image ID: docker-pullable://idoall/whoami@sha256:6e79f7182eab032c812f6dafdaf55095409acd64d98a825c8e4b95e173e198f2 106 Port: \u0026lt;none\u0026gt; 107 Host Port: \u0026lt;none\u0026gt; 108 State: Running 109 Started: Sat, 25 May 2019 18:15:37 +0800 110 Ready: True 111 Restart Count: 0 112 Environment: \u0026lt;none\u0026gt; 113 Mounts: 114 /var/run/secrets/kubernetes.io/serviceaccount from default-token-4zswl (ro) 115Conditions: 116 Type Status 117 Initialized True 118 Ready True 119 ContainersReady True 120 PodScheduled True 121Volumes: 122 default-token-4zswl: 123 Type: Secret (a volume populated by a Secret) 124 SecretName: default-token-4zswl 125 Optional: false 126QoS Class: BestEffort 127Node-Selectors: \u0026lt;none\u0026gt; 128Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s 129 node.kubernetes.io/unreachable:NoExecute for 300s 130Events: \u0026lt;none\u0026gt; 131 132Name: whoami-8657469579-vkv92 133Namespace: default 134Priority: 0 135PriorityClassName: \u0026lt;none\u0026gt; 136Node: node2.liudehan.com/172.16.8.143 137Start Time: Sat, 25 May 2019 18:15:23 +0800 138Labels: app=whoami 139 pod-template-hash=8657469579 140Annotations: \u0026lt;none\u0026gt; 141Status: Running 142IP: 10.244.2.2 143Controlled By: ReplicaSet/whoami-8657469579 144Containers: 145 whoami: 146 Container ID: docker://9418e3560da086e1bcfe831d4168797ed9b8ff1f303b82633e142d53282d2d71 147 Image: idoall/whoami 148 Image ID: docker-pullable://idoall/whoami@sha256:6e79f7182eab032c812f6dafdaf55095409acd64d98a825c8e4b95e173e198f2 149 Port: \u0026lt;none\u0026gt; 150 Host Port: \u0026lt;none\u0026gt; 151 State: Running 152 Started: Sat, 25 May 2019 18:15:36 +0800 153 Ready: True 154 Restart Count: 0 155 Environment: \u0026lt;none\u0026gt; 156 Mounts: 157 /var/run/secrets/kubernetes.io/serviceaccount from default-token-4zswl (ro) 158Conditions: 159 Type Status 160 Initialized True 161 Ready True 162 ContainersReady True 163 PodScheduled True 164Volumes: 165 default-token-4zswl: 166 Type: Secret (a volume populated by a Secret) 167 SecretName: default-token-4zswl 168 Optional: false 169QoS Class: BestEffort 170Node-Selectors: \u0026lt;none\u0026gt; 171Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s 172 node.kubernetes.io/unreachable:NoExecute for 300s 173Events: \u0026lt;none\u0026gt; 174 175Name: whoami-8657469579-xqb7j 176Namespace: default 177Priority: 0 178PriorityClassName: \u0026lt;none\u0026gt; 179Node: node1.liudehan.com/172.16.8.140 180Start Time: Sat, 25 May 2019 18:09:23 +0800 181Labels: app=whoami 182 pod-template-hash=8657469579 183Annotations: \u0026lt;none\u0026gt; 184Status: Running 185IP: 10.244.1.4 186Controlled By: ReplicaSet/whoami-8657469579 187Containers: 188 whoami: 189 Container ID: docker://09bb5819083dfebfc067680fb4af8434b07d1a3a3fc4e3630d7a0a194fa01578 190 Image: idoall/whoami 191 Image ID: docker-pullable://idoall/whoami@sha256:6e79f7182eab032c812f6dafdaf55095409acd64d98a825c8e4b95e173e198f2 192 Port: \u0026lt;none\u0026gt; 193 Host Port: \u0026lt;none\u0026gt; 194 State: Running 195 Started: Sat, 25 May 2019 18:09:34 +0800 196 Ready: True 197 Restart Count: 0 198 Environment: \u0026lt;none\u0026gt; 199 Mounts: 200 /var/run/secrets/kubernetes.io/serviceaccount from default-token-4zswl (ro) 201Conditions: 202 Type Status 203 Initialized True 204 Ready True 205 ContainersReady True 206 PodScheduled True 207Volumes: 208 default-token-4zswl: 209 Type: Secret (a volume populated by a Secret) 210 SecretName: default-token-4zswl 211 Optional: false 212QoS Class: BestEffort 213Node-Selectors: \u0026lt;none\u0026gt; 214Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s 215 node.kubernetes.io/unreachable:NoExecute for 300s 216Events: \u0026lt;none\u0026gt; 为Whoami扩展端口 1kubectl create service nodeport whoami --tcp=80:80 2service/whoami created 3# 上面的命令将在主机上为 Whoami 部署创建面向公众的服务。 4# 由于这是一个节点端口部署，因此 kubernetes 会将此服务分配给32000+范围内的主机上的端口 查看当前的服务状态 1kubectl get svc,pods -o wide 2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR 3service/kubernetes ClusterIP 10.96.0.1 \u0026lt;none\u0026gt; 443/TCP 161m \u0026lt;none\u0026gt; 4service/whoami NodePort 10.100.216.150 \u0026lt;none\u0026gt; 80:31203/TCP 73m app=whoami 5 6NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES 7pod/whoami-8657469579-6thrj 1/1 Running 0 68m 10.244.4.3 node3.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 8pod/whoami-8657469579-k2db4 1/1 Running 0 68m 10.244.4.2 node3.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 9pod/whoami-8657469579-rtsr4 1/1 Running 0 68m 10.244.2.3 node2.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 10pod/whoami-8657469579-vkv92 1/1 Running 0 68m 10.244.2.2 node2.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 11pod/whoami-8657469579-xqb7j 1/1 Running 0 74m 10.244.1.4 node1.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 12 13上面的服务可以看到Whoami运行在32707端口，通过ip+端口访问 测试Whoami服务是否运行正常 1curl node1.liudehan.com:31203 2[mshk.top]I\u0026#39;m whoami-8657469579-6thrj 扩展部署应用 1kubectl scale --replicas=5 deployment/whoami 2deployment.extensions/whoami scaled 查看扩展后的结果,可以看到 Whoami 在 c1、c2、c3上面都有部署\n1kubectl get svc,pods -o wide 2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR 3service/kubernetes ClusterIP 10.96.0.1 \u0026lt;none\u0026gt; 443/TCP 165m \u0026lt;none\u0026gt; 4service/whoami NodePort 10.100.216.150 \u0026lt;none\u0026gt; 80:31203/TCP 78m app=whoami 5 6NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES 7pod/whoami-8657469579-6thrj 1/1 Running 0 72m 10.244.4.3 node3.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 8pod/whoami-8657469579-k2db4 1/1 Running 0 72m 10.244.4.2 node3.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 9pod/whoami-8657469579-rtsr4 1/1 Running 0 72m 10.244.2.3 node2.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 10pod/whoami-8657469579-vkv92 1/1 Running 0 72m 10.244.2.2 node2.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 11pod/whoami-8657469579-xqb7j 1/1 Running 0 78m 10.244.1.4 node1.liudehan.com \u0026lt;none\u0026gt; \u0026lt;none\u0026gt; 测试扩展后的结果 1root@master _src]# curl node1.liudehan.com:31203 2[mshk.top]I\u0026#39;m whoami-8657469579-k2db4 3[root@master _src]# curl node1.liudehan.com:31203 4[mshk.top]I\u0026#39;m whoami-8657469579-xqb7j 5[root@master _src]# curl node1.liudehan.com:31203 6[mshk.top]I\u0026#39;m whoami-8657469579-xqb7j 7[root@master _src]# curl node1.liudehan.com:31203 8[mshk.top]I\u0026#39;m whoami-8657469579-vkv92 9[root@master _src]# curl node1.liudehan.com:31203 10[mshk.top]I\u0026#39;m whoami-8657469579-xqb7j 11[root@master _src]# curl node1.liudehan.com:31203 12[mshk.top]I\u0026#39;m whoami-8657469579-vkv92 13[root@master _src]# curl node1.liudehan.com:31203 14[mshk.top]I\u0026#39;m whoami-8657469579-k2db4 删除Whoami部署 1[root@master _src]# kubectl delete deployment whoami 2deployment.extensions \u0026#34;whoami\u0026#34; deleted 3[root@master _src]# kubectl get deployments 4No resources found. 查看运行的server 1[root@master _src]# kubectl get service 2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 3kubernetes ClusterIP 10.96.0.1 \u0026lt;none\u0026gt; 443/TCP 172m 4whoami NodePort 10.100.216.150 \u0026lt;none\u0026gt; 80:31203/TCP 84m 删除servre 1root@master _src]# kubectl delete svc whoami 2service \u0026#34;whoami\u0026#34; deleted 3[root@master _src]# kubectl get service 4NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 5kubernetes ClusterIP 10.96.0.1 \u0026lt;none\u0026gt; 443/TCP 175m ","link":"http://test.mylass.com/post/kubeadm_install/","section":"post","tags":["k8s","kubernetes"],"title":"kubeadmin安装k8s"},{"body":"","link":"http://test.mylass.com/tags/kubernetes/","section":"tags","tags":null,"title":"kubernetes"},{"body":"","link":"http://test.mylass.com/post/","section":"post","tags":null,"title":"Posts"},{"body":"参考 https://xts.so/linux/install-the-alpine-linux-on-raspberry-pi-zero-w.html\n运行脚本\n1setup-alpine 在安装的过程中，会提示你设置键盘布局、设置 WiFi 网络、设置时区、设置时间同步程序、设置apk软件源，设置root密码等等，按向导提示安装即可。\n如果是普通安装，Alpine Linux 将会把整个系统安装到 FAT32 启动分区中，每次启动电脑的时候，会自动创建一个内存盘作为根分区。这种默认的安装方式比较简单，但却让 Zero W 本来就有限的内存显得更加捉襟见肘。\nsys 模式\n于是我选择了另一种安装方式—— sys 模式——将整个系统安装到一个 ext4 分区中。这样不需要内存盘作为根分区，可以节省出保贵的内存，也能让系统更可靠。请注意使用这种安装方式，在安装向导中需在 save config 和 save cache 步骤的提示中输入 none\n走完setup-alpine脚本之后，我们还需要安装 ext4 文件系统的支持，这部分需要联网下载安装。\n使用fdisk将剩余的空间划分 1fdisk /dev/mmcblk0 2\tn 3\tp 4\t2 5\tw 6\t# 起始位置和结束位置，注意看原来的分区 安装 ext2/3/4 文件系统支持 1apk update 2apk add e2fsprogs 格式化之前创建的分区 1mkfs.ext4 /dev/mmcblk0p2 # 如果提示找不到，需要重启系统 把格式化好的分区挂载出来 1mount /dev/mmcblk0p2 /mnt 使用 setup-disk 安装系统 1setup-disk -m sys /mnt #因为setup-disk脚本还不太完善，安装过程中可能会提示一些错误，忽略即可。 清理用不到的文件 1mount -o remount,rw /dev/mmcblk0p1 2 3rm -f /media/mmcblk0p1/boot/* 4cd /mnt 5rm boot/boot 将启动镜像和 Alpine Linux 的init ram移动到 FAT32 分区中的正确位置 1mv boot/* /media/mmcblk0p1/boot/ 2rm -Rf boot # 删除 ext4 分区中的 boot 目录 3mkdir media/mmcblk0p1 # 下次重启后 FAT32 分区的新挂载点 建立一个软链，这样以后升级系统后无需人工复制到 FAT32 分区中。不用担心错误提示 1ln -s media/mmcblk0p1/boot boot 更新/etc/fstab分区挂载配置 1echo \u0026#34;/dev/mmcblk0p1 /media/mmcblk0p1 vfat defaults 0 0\u0026#34; \u0026gt;\u0026gt; etc/fstab 2sed -i \u0026#39;/cdrom/d\u0026#39; etc/fstab # 显示树莓派上没有光驱 3sed -i \u0026#39;/floppy/d\u0026#39; etc/fstab # 也没有软驱 ","link":"http://test.mylass.com/linux/alpine-raspi-install/","section":"linux","tags":["linux"],"title":"alpine raspi 安装"},{"body":"","link":"http://test.mylass.com/tags/linux/","section":"tags","tags":null,"title":"linux"},{"body":"","link":"http://test.mylass.com/series/linux/","section":"series","tags":null,"title":"linux"},{"body":"","link":"http://test.mylass.com/archives/","section":"","tags":null,"title":""},{"body":"在配置文件中定义，一般是nginx.conf\n场景：如，有两个网站，使用不同的服务器来提供的，但是我的公网IP只有一个。 现在把这个公网IP的80端口映射到一台转发的nginx上面，再在这一台上面配置反向代理，就可以实现。\n如A网站的地址是 192.168.10.23 域名是 www.example.com B网站的地址是 192.168.10.24 域名是 www.test.com\n在 nginx 的配置反向代理如下\n1server { 2 listen 80; 3 server_name www.example.com; 4 5 location / { 6 proxy_pass http://192.168.10.23; 7 } 8} 9 10server { 11 listen 80; 12 server_name www.test.com; 13 14 location / { 15 proxy_pass http://192.168.10.24; 16 } 17} 主要是 server_name 指定域名，以及 proxy_pass 指定后端的服务器\n启用 http 的 ssl 配置 1server { 2 listen 443 http2;\t# 监听的端口， https的默认端口为443 3 server_name www.test.com;\t# 域名 4 5 ssl_certificate /path/to/your/file/site.pem;\t# 证书文件 6 ssl_certificate_key /path/to/your/file/site.key;\t# 私钥文件 7 8 location / { 9 proxy_pass http://192.168.10.24; 10 } 11} ","link":"http://test.mylass.com/linux/nginx-proxy/","section":"linux","tags":["nginx","linux"],"title":"nginx反向代理"},{"body":"本站说明 开设本站，本意为记录技术相关分享，以及日常工作遇到的问题和解决方法。以及思路。\n关于本站的所有文章，转载请注意出处。码字不易，谢谢配合。\n本站所使用的环境：\nUbuntu Hugo Nginx Hugo 是由 Go 编写的静态网站生成器，开源。\n文章使用 Markdown 编写，然后由 Hugo 输出成 Html 纯静态页。由于没有后台程序，所以访问速度很快。\n唯一缺点就是大部分主题的功能太少。很多功能可能需要自行开发。并且国内文档也很少。\n对于我（非开发岗位）来说，简直是心有余力不足！\n感兴趣的可自行询问搜索引擎。\n个人说明 不知不觉，在IT行已经摸爬滚打很多年了，有心酸的泪水，也有收获的喜悦。\n对于技术方面，一直保持严谨的态度。不断的完善自己。\n这些年，也走了很多弯路，不管是工作上，还是生活上。总之个人感觉一团糟。\n时过境迁，日子一天天过去，希望大家都能过的开心，珍惜每一天，努力做最好的自己。\n个人微博，虽然不怎么更新 https://weibo.com/u/2048273350 ","link":"http://test.mylass.com/about/","section":"","tags":null,"title":"About Me"},{"body":"","link":"http://test.mylass.com/tags/nginx.conf/","section":"tags","tags":null,"title":"nginx.conf"},{"body":"使用 docker 容器，使用 docker-compose 管理\ncompose 目录 /root/nginx-container\nnginx 配置文件：\n1/root/nginx-container/conf/nginx.conf 2/root/nginx-container/conf.d/*.conf SSL 证书存放路径，在此目录再以项目或站点名称创建文件夹存放\n1/root/nginx-container/ssl/ 目前 sxsc 站点的配置文件 /root/nginx-container/conf/conf.d/sxsc.ltd.conf ， SSL 证书存放路径 /root/nginx-container/ssl/sxsc.ltd/ .\n添加新站点 在 /root/nginx-container/conf/conf.d/ 目录下创建一个新文件，并以 .conf 结尾， 可以用站点名称命名，如：www.sxsc.com.conf, 配置文件内容，可参考以下\n1server { 2 listen 80; # 监听端口 3 server_name sxsc.ltd www.sxsc.ltd; # 域名、主机名 4 # 以下是 http 跳转到 https，并返回 HTTP 301 永久重写向. 5 # 适合开启了https的站点，若用户从https访问则自动跳转到https 6 location / { 7 rewrite ^/(.*)$ https://www.sxsc.ltd/$1 permanent; 8 } 9} 10server { 11 listen 443 ssl; # 监听端口，并开启 SSL 12 server_name sxsc.ltd www.sxsc.ltd; # 域名、主机名 13 root /data/www/html/sxsc; # 网站根目录 14 index index.html index.htm index.php; # index设定，即没有指定文件名时自动查找的文件 15 16 ssl_certificate ssl/sxsc.ltd/sxsc_cert.crt; # SSL 证书文件路径 17 ssl_certificate_key ssl/sxsc.ltd/sxsc_cert.key; # SSL 证书私钥文件路径 18 19 # SSL 调优 20 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # SSL 协议版本 21 ssl_ciphers ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!AESGCM; 22 ssl_prefer_server_ciphers on; 23 ssl_session_cache shared:SSL:5m; # 开启 SSL 复用 Session，减少 TLS 握手 24 ssl_session_timeout 1h; # SSL 缓存有效期，单位：d(天)、h(时)、m(分)、 25 26 # HSTS 配置，添加 http header， 强制浏览器直接使用 https 访问，在浏览器初次打开时记录，有效期一年 27 # 再次访问，则会再次刷新。 28 # 若开启这个配置，注意 SSL 证书，不能过期。 29 # 若过期，则已经缓存这个的站点HSTS信息的浏览器，则会因为证书过期不能打开 30 31 # add_header Strict-Transport-Security \u0026#34;max-age=31536000; includeSubDomains; preload\u0026#34; always; 32 33 # 请求数据限制，单个IP，每秒最多32个请求，缓存区16个 34 # 一秒内，同一个IP，第49个请求，会返回 HTTP 503 35 # Request limit 36 # limit_req_zone $binary_remote_addr zone=req_zone:15m rate=32r/s; 37 # limit_req zone=req_zone burst=16; 38 39 # 禁止类似 Curl 类的工具，以及空的UA访问及抓取 40 # 若 curl 指定特别的UA，则不能限制 41 if ($http_user_agent ~* \u0026#34;Scrapy|HttpClient|Teleport|TeleportPro|curl|^$\u0026#34;) 42 { 43 return 403; 44 } 45 46 # 禁止 非常规GET POST HEAD 请求 47 if ($request_method !~* ^(GET|HEAD|POST)$) 48 { 49 return 403; 50 } 51 52 # php 配置 53 location ~* [^/]\\.php(/|$) 54 { 55 try_files $uri =404; 56 fastcgi_pass unix:/tmp/php-cgi.sock; 57 fastcgi_index index.php; 58 include fastcgi.conf; 59 } 60 # JS CSS文件缓存 61 location ~* .*\\.(js|css)$ 62 { 63 expires 2d; 64 } 65 66 # 图片缓存 67 location ~* .*\\.(jpg|jpeg|tiff|tif|png|gif|bmp|ico|png|swf)$ 68 { 69 expires 2d; 70 } 71 72 location ~ /\\. 73 { 74 deny all; 75 } 76 77 location ~* .*\\.(htaccess|log)$ 78 { 79 deny all; 80 } 81} 以上为基本配置，可根据实际情况再调节\n修改配置文件的后的重启 修改配置文件以后，不要直接重启，先测试文件是否有错误的地方\n由于使用的是 docker ，使用 compose 管理以下是测试配置文件的命令\n1cd /root/nginx-nginx-container 2docker-compose exec webngx nginx -t -c /etc/nginx/nginx.conf 3 nginx: the configuration file /etc/nginx/nginx.conf syntax is ok 4 nginx: configuration file /etc/nginx/nginx.conf test is successful 若提示 OK 则没有问题，使用命令重启或重载配置文件\n1cd /root/nginx-nginx-container 2docker-compose restart # 重启 3docker-compose exec webngx nginx -s reload # 平滑重启（重载配置文件） 4docker-compose exec webngx ngins -s reopen # 重新打开文件 ","link":"http://test.mylass.com/linux/nginx/","section":"linux","tags":["nginx","nginx.conf","linux"],"title":"nginx站点配置"},{"body":"","link":"http://test.mylass.com/tags/database/","section":"tags","tags":null,"title":"database"},{"body":"","link":"http://test.mylass.com/tags/mariadb/","section":"tags","tags":null,"title":"mariadb"},{"body":"简介 在默认情况下，必须授权于用户权限，用户才可以连接，例如：授权 tom 用户，可以从 192.168.1.10 来连接\n权限方面，则可以配置用户，如创建表，修改表结构，删除表，创建索引、视图，等等\n以下是命令行相关的配置，若使用管理工具，则管理工具可以GUI方面配置\n可以配置权限如下所示：\n数据 表结构 管理 SELECT CREATE GRANT INSERT ALTER SUPER UPDATE INDEX PROCESS DELETE DROP RELOAD FILE CREATE TEMPORARY TABLES SHUTDOWN . SHOW VIEW SHOW DATABASES . CREATE ROUTINE LOCK TABLES . EXECUTE REFERENCES . CREATE VIEW REPLICATION CLIENT . EVENT REPLICATION SLAVE . TRIGGER CREATE USER 可以先创建用户，然后再授权，也可以在授权的时候直接创建，都可以，一个是两条指令，一个是一条 以下实例是直接授权并创建\n使用 GRANT 授权， REVOKE 撤销授权\n查看当前连接的用户权限\n1mysql\u0026gt; SHOW GRANTS\\G; 2*************************** 1. row *************************** 3Grants for root@localhost: GRANT ALL PRIVILEGES ON *.* TO \u0026#39;root\u0026#39;@\u0026#39;localhost\u0026#39; IDENTIFIED BY PASSWORD \u0026#39;*C6F63C5B0F14196C90D143A46D2046B350D612B3\u0026#39; WITH GRANT OPTION 4*************************** 2. row *************************** 5Grants for root@localhost: GRANT PROXY ON \u0026#39;\u0026#39;@\u0026#39;\u0026#39; TO \u0026#39;root\u0026#39;@\u0026#39;localhost\u0026#39; WITH GRANT OPTION 62 rows in set (0.00 sec) 7 8ERROR: 9No query specified 创建 user1 用户，并授予所有库所有表所有权限，允许从任意地点登录，并设置密码为 123456\n1mysql\u0026gt; GRANT ALL PRIVILEGES ON *.* TO \u0026#39;user1\u0026#39;@\u0026#39;%\u0026#39; IDENTIFIED BY \u0026#39;1213456\u0026#39;; 2 Query OK, 0 rows affected (0.00 sec) 3 4mysql\u0026gt; 授权 user2 对 forum 库所有权限，只允许从 192.168.1.10 登录，密码为qazwsx\n1GRANT ALL PRIVILEGES ON forum.* TO \u0026#39;user2\u0026#39;@\u0026#39;192.168.1.10\u0026#39; IDENTIFIED BY \u0026#39;qazwsx\u0026#39;; 授权 user2 对 wpsell 库下的 order 表只能查询数据，并且只允许从 192.168.x.x 网段登录，密码为qazwsx\n1GRANT ALL SELECT ON wpsell.order TO \u0026#39;user2\u0026#39;@\u0026#39;192.168.%\u0026#39; IDENTIFIED BY \u0026#39;qazwsx\u0026#39;; 查看当前用户连接的用户权限\n1SHOW GRANTS; 查看指定用户权限\n1SHOW GRANTS FOR \u0026#39;user2\u0026#39;@\u0026#39;192.168.%\u0026#39;; 撤销相应用户权限\n1REVOKE SELECT, INSERT,UPDATE,DELETE ON forum.* FROM \u0026#39;sunny\u0026#39;@\u0026#39;192.168.1.110\u0026#39;; 撤销相应用户的所有权限\n1REVOKE ALL PRIVILEGES ON forum.* FROM \u0026#39;sunny\u0026#39;@\u0026#39;192.168.1.110\u0026#39;; REVOKE 回收权限，并不会删除账号，删除账号使用 DROP USER 指令\n1DROP USER \u0026#39;sunny\u0026#39;@\u0026#39;localhost\u0026#39;; 修改用户密码 修改当前用户的密码，也就是自己的密码\n1SET PASSWORD=PASSWORD(\u0026#39;your new password\u0026#39;); 修改指定用户的密码\n1SET PASSWORD FOR \u0026#39;sunny\u0026#39;@\u0026#39;localhost\u0026#39;=PASSWORD(\u0026#39;New password\u0026#39;); 也可以使用 SQL 直接修改表来修改密码\n1USE mysql; 2UPDATE user SET password=PASSWORD(\u0026#39;Newpassword), authenication_string=PASSWORD(\u0026#39;Newpassword\u0026#39;) WHERE user=\u0026#39;sunny\u0026#39;; ","link":"http://test.mylass.com/post/mariadb-privileges/","section":"post","tags":["mysql","mariadb","database"],"title":"mariadb权限配置"},{"body":"","link":"http://test.mylass.com/series/mysql/","section":"series","tags":null,"title":"mysql"},{"body":"由于最近需要做一个下载站，下载站上放的是我们软件，以及一些工具文件，需要做一个md5值和sha1值，以便下载者核对该值，确保文件在下载过程中，不被中间人篡改。\n为此，我写了一个脚本，用来扫描某个目录下的文件，然后计算出对应文件的 md5值和 sha1值，并写入到一个文本文件里面。\n由于有的文件比较大，单个文件达到 GB 以上，这样每次计算都比较耗时，所以，在脚本中，加入了判断。\n首先会查找目录下所有文件，之后依次判断每个文件是否已经存在 md5 值 和 sha1 值的文本文件存在（计算出值存放在文本文件里面），如果文件存在，则会比较该文件是否比原文件新，或是值文件比原文件新，则代表原文件没有修改过，若是旧，则说明原文件修改过。（我们总是先修改文件，再计算MD5和sha1 值，所以值文件一定比原文件新）。\n脚本第三行，为你的要计算的文件路径，也就是我的下载站根目录，由于根目录我只放目录，没有文件，所以这个目录下的文件，不会被计算，若您需要计算，可自行修改下。\n脚本执行后，会生成两个.txt 文件，分别为原文件的文件名+md5.txt 和 原文件名+sha1.txt\n以下是脚本源代码：\n1#!/bin/bash 2 3cd /var/www/html/download 4s_dir=$(pwd) 5find * -type d | while read dir 6\tdo 7\tcd $dir 8\tfind * -not -name \u0026#34;*.md5.txt\u0026#34; -not -name \u0026#34;*.sha1.txt\u0026#34; -maxdepth 0 -type f | while read file 9\tdo 10\tif [ -f ${file}.md5.txt ]; then 11\tif [ ${file}.md5.txt -ot ${file} ]; then 12\tmd5sum ${file} | awk \u0026#39;{print $1}\u0026#39; \u0026gt; ${file}.md5.txt 13\tfi 14\telse 15\tmd5sum ${file} | awk \u0026#39;{print $1}\u0026#39; \u0026gt; ${file}.md5.txt 16\tfi 17\tif [ -f ${file}.sha1.txt ]; then 18\tif [ ${file}.sha1.txt -ot ${file} ]; then 19\tsha1sum ${file} | awk \u0026#39;{print $1}\u0026#39; \u0026gt; ${file}.sha1.txt 20\tfi 21\telse 22\tsha1sum ${file} | awk \u0026#39;{print $1}\u0026#39; \u0026gt; ${file}.sha1.txt 23\tfi\t24\tdone 25\tcd $s_dir 26\tdone 脚本您可以放到计划任务里面，根据您的文件变化频繁程度，决定每次执行的间隔，当然若您的文件变动不频繁，也可以每次有变动后手动执行。\n执行脚本后，会生成两个.txt 结尾的文件，文件名原文件伯保持一致，如下图所示，是我们的软件镜像下载站。\n","link":"http://test.mylass.com/linux/scan-directory-all-file-md5/","section":"linux","tags":null,"title":"扫描目所有文件，并计算md5值和sha1值"},{"body":"本文介绍linux服务的开户自动启动方式，分两两种，以下\n使用 systemctl 方式 在 /lib/systemd/system/ 目录创建文件，并写以下内容\n1[Unit] 2Description=liquid api server Compatibility 3After=network.target 4 5[Service] 6User=go 7ExecStart=/data/subfile/liquid-api-server/liquid-api 8#ExecStartPre=rm -rf /data/subfile/tmp/cache/* 9#ExecStartPost= 10Restart=on-failure 11RestartSec=5s 12SysVStartPriority=99 13 14[Install] 15WantedBy=multi-user.target 注解 [Unit] 区块，启动顺序与依赖关系 Description 服务注释，可随意写 After 指定在某个服务启动以后，再启动此服务，比如这个是依赖网络的，那就在网络服务启动之再启动这个\n[Service] 区块是核心，主要在这里 User 指定运行程序的用户，或不指定，则是root用户 ExecStart 指定运行的程序路径和参数，注意：这里必须是绝对路径 ExecStartPre 指定运行程序前的指令，比如每次启动前清除缓存 ExecStartPost 启动后的执行后的指令 Restart 指定重启行为，on-failure 代表非正常退出时重启（退出代码非0） RestartSec 退出后重启的间隔 SysVStartPriority 优先级，自定服务一般设置为99即可 [install] 区块保持默认即可\n使用 启动脚本方式 1 /data/subfile/liquid-api-server/liquid-api 22019/12/07 10:11:07 configFile.Get err 3#open config/app-local.yaml: no such file or directory 如上日志，目前咱们这个服务，没办法使用绝对路径来启动，必须先cd到目录，才可以启动，所以只能用这种方法\nubuntu 18.04 以后，默认没有开户 /etc/rc.local 开机启动脚本，首先开启它\n修改 /lib/systemd/system/rc-local.service 文件，内容保持和下方一样即可\n1[Unit] 2Description=/etc/rc.local Compatibility 3Documentation=man:systemd-rc-local-generator(8) 4#ConditionFileIsExecutable=/etc/rc.local 5After=network.target 6 7[Service] 8Type=forking 9ExecStart=/etc/rc.local start 10TimeoutSec=0 11RemainAfterExit=yes 12GuessMainPID=no 13SysVStartPriority=99 14 15[Install] 16WantedBy=multi-user.target 创建 /etc/rc.local 文件\n1sudo touch /etc/rc.local 2 3sudo chmod +x /etc/rc.local 启用 rc.local 脚本\n1systemctl enable rc-local.service 创建启动脚本，并添加自起服务 1sudo vim /usr/share/subtitle.sh 脚本位置无所谓，记住就好，后面会用到\n文件添加以下内容，咱们这个因为必须 cd到目录才可以启动，并且指定 go 用户运行，所以脚本如下，其它的参考示例了。\n1#!/bin/bash 2sleep 10 3cd /data/subfile/liquid-api-server 4sudo -u go nohup /data/subfile/liquid-api-server/liquid-api \u0026gt; /dev/null 2\u0026gt;\u0026amp;1 \u0026amp; 5sleep 1 6cd /data/subfile/subtitle-server 7sudo -u go nohup /data/subfile/subtitle-server/subtitle \u0026gt; /dev/null 2\u0026gt;\u0026amp;1 \u0026amp; 这个启用了 nohup来保证不会因为shell的断开而停止后台运行， \u0026gt; /dev/null 2\u0026gt;\u0026amp;1 \u0026amp; 表示将程序所产生的所有输出（不论标准或错误），全部重定向到 /dev/null ，并且后台运行， 默认情况下，nohup 会在执行的目录创建.nohup来记录程序的标准输出和错误输出，而有些程序的标准输出量特别多，时间长了，会把磁盘空间占满，所以重写向到垃圾桶，可保证不会因为程序的输出信息而占满磁盘空间带来其它的问题。\n添加执行权限\n1sudo chmod +x /usr/share/subtitle.sh 添加到 /etc/rc.local\n1sudo vim /etc/rc.local 添加e脚本的问题，注意脚本需要有执行位权限：\n1#!/bin/sh -e 2 3/usr/share/subtitle.sh 4 5eixt 0 以后所有添加的其它服务，都必须添加在 exit 0 这一行的前面\n","link":"http://test.mylass.com/linux/linux-auto-start/","section":"linux","tags":["linux"],"title":"linux开机自动启动"},{"body":"","link":"http://test.mylass.com/tags/autoinstall/","section":"tags","tags":null,"title":"autoinstall"},{"body":"","link":"http://test.mylass.com/tags/pxe/","section":"tags","tags":null,"title":"pxe"},{"body":"在以前，我这里说过 ubuntu 的 pxe 全自动安装，适合用于机器多而且都要装系统的情况，那个时候的是 ubuntu server 12.04 的版本，由于我们的客户的机器是分批要的，之前的是 ubuntu server 12.04，后来，有一段时间，没有要机器，再后来，客户改需求，需要装 ubuntu 14.04，我这边呢，还是用以前的 12.04 的方法，来配置 pxe。netboot 目录下的文件，也全部都替换成了 14.04 镜像里的内容，但是在安装的时候，就报错了，报错信息如下：\n1An installation step failed. You can try to run the failing item again from the menu, or skip it and choose something else. The failing step is: Install the system 截图如下：\n看这个错误的意思，是说，安装系统失败，一个安装步骤失败，可能重试或跳过。\n可是就很奇怪了，以为是镜像的问题，于是呼，就用镜像直接安装，一点问题也没有。问题有点奇怪，使用 pxe 安装 ubuntu 14.04 ，报安装步骤失败，而不使用 pxe ，则一点问题没有。\n在网上找了找资料，也问问了别人，后来找到了原因。大概原因如下：\n在 ubuntu 14.04 以及以后的版本，在使用 pxe 安装的时候，都必须要指定一个 live-install/net-image 参数，是指，从网络安装，若不指定，则就会报错，像上图一样，橙屏，安装步骤失败。但在 ubuntu 12.04 的版本，可以不指定，也可以指定，无所谓的，而我之前的环境，安装的就是 12.04 的版本，当初并没有指定，也可以正常安装，但在 14.04 就不行了。\n在 install 标签下的 append 指定，包括 ks文件的位置，指定：\n1live-installer/net-image=http://10.0.3.8/ubuntu-14.04.5/install/filesystem.squashfs 10.0.3.8 为我服务器，ubuntu-14.04.5 是光盘的镜像，挂载到这个目录。\n我的 txt.cfg 如下：\n1[root@localhost ~]# cat /var/lib/tftpboot/ubuntu-installer/amd64/boot-screens/txt.cfg 2default install 3label install 4 menu label ^Install 5 menu default 6 kernel ubuntu-installer/amd64/linux 7 append ks=http://10.0.3.8/ks/ks.cfg vga=788 initrd=ubuntu-installer/amd64/initrd.gz live-installer/net-image=http://10.0.3.8/ubuntu-14.04.5/install/filesystem.squashfs 8label cli 9 menu label ^Command-line install 10 kernel ubuntu-installer/amd64/linux 11 append tasks=standard pkgsel/language-pack-patterns= pkgsel/install-language-support=false vga=788 initrd=ubuntu-installer/amd64/initrd.gz --- quiet 12[root@localhost ~]# 其它的步骤，可以参考我的文章， 可以点这里查看\n","link":"http://test.mylass.com/linux/ubuntu-install-step-fail/","section":"linux","tags":["pxe","autoinstall"],"title":"ubuntu14.04 pxe 安装步骤失败"},{"body":"","link":"http://test.mylass.com/tags/localrepo/","section":"tags","tags":null,"title":"localrepo"},{"body":"linux vsftpd，大家在做 vsftpd 的时候，不知道在有没有注意过一个问题，那就是用户可以切换到 ftp 根目录的上一层目录，而且这是默认的设置，不知道设计者这么做，考虑的是什么？有知道的朋友，还请留言，讨论一下。\n在 FTP 登录完成后，都可以切换到系统根目录。这里我给大家来试验一下。这里命令行的方式来登录。 C:\\Users\\ainy\u003eftp ifool.me\r连接到 ifool.me。\r220 (vsFTPd 3.0.2)\r200 Always in UTF8 mode.\r用户(ifool.me:(none)): ainy\r331 Please specify the password.\r密码:\r230 Login successful.\rftp\u003e\rftp\u003e\rftp\u003e cd /\r250 Directory successfully changed.\rftp\u003e\rftp\u003e\rftp\u003e dir\r200 PORT command successful. Consider using PASV.\r150 Here comes the directory listing.\rdrwxr-xr-x 2 0 0 4096 May 14 20:08 bin\rdrwxr-xr-x 3 0 0 4096 Apr 03 20:07 boot\rdrwxr-xr-x 16 0 0 2840 Jul 26 14:28 dev\rdrwxr-xr-x 75 0 0 4096 Aug 16 14:39 etc\r-rw-r--r-- 1 0 0 5684 Jun 03 01:40 header.php\rdrwxr-xr-x 7 0 0 4096 Aug 16 14:39 home\rlrwxrwxrwx 1 0 0 31 Apr 03 20:06 initrd.img -\u003e /boot/initrd.img-3.16.0-4-amd64\rdrwxr-xr-x 13 0 0 4096 May 14 19:47 lib\rdrwxr-xr-x 2 0 0 4096 Apr 03 20:05 lib64\rdrwx------ 2 0 0 16384 Apr 03 20:04 lost+found\rdrwxr-xr-x 2 0 0 4096 Apr 03 20:05 media\rdrwxr-xr-x 2 0 0 4096 Apr 03 20:05 mnt\rdrwxr-xr-x 2 0 0 4096 May 25 23:32 ntp\rdrwxr-xr-x 2 0 0 4096 Apr 03 20:05 opt\rdr-xr-xr-x 102 0 0 0 Jul 26 14:25 proc\rdrwx------ 7 0 0 4096 Aug 16 10:16 root\rdrwxr-xr-x 17 0 0 540 Aug 15 23:51 run\rdrwxr-xr-x 2 0 0 4096 Jul 29 18:19 sbin\rdrwxr-xr-x 3 0 0 4096 Aug 15 23:51 srv\r-rw-r--r-- 1 0 0 108296 Jun 03 01:42 style.css\rdr-xr-xr-x 13 0 0 0 Jul 26 14:26 sys\rdrwxrwxrwt 11 0 0 4096 Aug 16 14:44 tmp\rdrwxr-xr-x 10 0 0 4096 Apr 03 20:05 usr\rdrwxr-xr-x 11 0 0 4096 May 14 22:35 var\rlrwxrwxrwx 1 0 0 27 Apr 03 20:06 vmlinuz -\u003e boot/vmlinuz-3.16.0-4-amd64\r226 Directory send OK.\rftp: 收到 1634 字节，用时 0.19秒 8.74千字节/秒。\rftp\u003e\r可以看到，登入 ftp 后，直接 cd / 就切换到了系统的根目录，那么文件是否可以下载呢，再来试验一下 ftp\u003e\rftp\u003e\rftp\u003e cd /etc/ssh/\r250 Directory successfully changed.\rftp\u003e\rftp\u003e get sshd_config\r200 PORT command successful. Consider using PASV.\r150 Opening BINARY mode data connection for sshd_config (2548 bytes).\r226 Transfer complete.\rftp: 收到 2548 字节，用时 0.00秒 2548000.00千字节/秒。\rftp\u003e\r如此可见，用户可以切换到系统任意目录，也可以下载任意文件（当然前提是登录 ftp 的用户对相应的文件有读取权限），这样若是某个 用户 的密码过于简单，则有可能被黑客使用弱口令方式，攻击到 ftp ，这样的话，整个系统都在 默的眼下了，什么文件都可以拿到，因为 linux 系统里绝大部分文件，都是 755 的权限。\n既然这样，那必须要禁止切换用户切换\nC:\\Users\\ainy\u003eftp ifool.me\r连接到 ifool.me。\r220 (vsFTPd 3.0.2)\r200 Always in UTF8 mode.\r用户(ifool.me:(none)): ainy\r331 Please specify the password.\r密码:\r230 Login successful.\rftp\u003e\rftp\u003e pwd\r257 \"/home/ainy\"\rftp\u003e\r禁止前，使用 pwd 命令，发现所以路径为真实的路径，当然这也是 vsftpd 默认的情况，默认本地用户的目录为自己的家目录。\n打开 vsftpd.conf 配置文件，找到如下两行\nchroot_list_enable=YES\rchroot_list_file=/etc/vsftpd.chroot_list\r去掉前面的 # 号，若没有这两行，可以手动添加，配置完成以后，创建chroot_list 文件，并重启vsftpd 服务\n1touch /etc/vsftpd.chroot_list 2echo \u0026#34;ainy\u0026#34; \u0026gt; /etc/vsftpd.chroot_list 3/etc/init.d/vsftpd restart /etc/vsftpd.chroot_list 文件，代表的就是禁止哪些用户切换到上层目录，用户只在存在于这个文件里，则不能切换到上层目录，文件一行一个用户。\n完成后再次重新登录 ftp 会发现这个用户登录不了了，报一个 500 的错误，具体为500 OOPS: vsftpd: refusing to run with writable root inside chroot()\n这个错误我在网上找了一下，只需要在 vsftpd.conf 添加一行\n1allow_writeable_chroot=YES 即可解决500 OOPS: vsftpd: refusing to run with writable root inside chroot()的报错，配置文件改完后，再重启服务，然后再来试一下\nC:\\Users\\ainy\u003eftp ifool.me\r连接到 ifool.me。\r220 (vsFTPd 3.0.2)\r200 Always in UTF8 mode.\r用户(ifool.me:(none)): ainy\r331 Please specify the password.\r密码:\r230 Login successful.\rftp\u003e\rftp\u003e\rftp\u003e pwd\r257 \"/\"\rftp\u003e\rftp\u003e\rftp\u003e cd /\r250 Directory successfully changed.\rftp\u003e\rftp\u003e\rftp\u003e dir\r200 PORT command successful. Consider using PASV.\r150 Here comes the directory listing.\r226 Directory send OK.\rftp\u003e\rftp\u003e dir -a\r200 PORT command successful. Consider using PASV.\r150 Here comes the directory listing.\rdrwxr-xr-x 2 1004 1004 4096 Aug 16 14:39 .\rdrwxr-xr-x 2 1004 1004 4096 Aug 16 14:39 ..\r-rw-r--r-- 1 1004 1004 220 Nov 13 2014 .bash_logout\r-rw-r--r-- 1 1004 1004 3515 Nov 13 2014 .bashrc\r-rw-r--r-- 1 1004 1004 675 Nov 13 2014 .profile\r226 Directory send OK.\rftp: 收到 323 字节，用时 0.01秒 24.85千字节/秒。\rftp\u003e\r这次我们可以看到，登入 ftp 后的目录，就是根目录 / 不管再怎么切换，始终在自己的家目录里，不能切换到上层目录。\n","link":"http://test.mylass.com/linux/vsftpd-disable-directory/","section":"linux","tags":["yum","localrepo"],"title":"vsftpd 3.x 禁止用户切换(访问)到上一级目录"},{"body":"","link":"http://test.mylass.com/tags/yum/","section":"tags","tags":null,"title":"yum"},{"body":"在linux 包的管理上，我们都知道，大部分是有依赖关系的，那么依赖关系是什么呢，也就是说，当你需要装一个包的时候，你的这个包，可能还需要其它的库文件，而这个库文件，是来自某一个包的，假设这个包名叫做A，那么，你需要先安装A，这个A还需要其它的库，那个库又来自B包，依此类推，这安装一个包，真是够麻烦的。\n好在有yum，yum是一个在Fedora和RedHat以及CentOS中的Shell前端软件包管理器。基于RPM包管理，能够从指定的服务器自动下载RPM包并且安装，可以自动处理依赖性关系，并且一次安装所有依赖的软件包，无须繁琐地一次次下载、安装。正好解决了这些依赖问题。\n可偏偏，有的时候，因为某些原因，我们的linux服务器，不能连接互联网，我们知道，yum是连接到互联网上的服务器去下载包的，是不是这样就没用yum了？答案是否定的，我们可以利用安装光盘，制作本地yum源。\n本次试验环境使用CentOS 6.7\n先使用xmanager winscp 等，把光盘镜像文件，传到服务器上，本次实验环境，就放到 /data 目录下吧，这里要说一下，必须要是完整的光盘映像，minimal netinstall liveCD，这些，包都不全，只有最基本的包。不知道怎么区分的，可以看映象文件的大小，只有几百兆的，那肯定不是完整的安装光盘镜像\n挂载光盘映象文件，并把包复制到本地，本次环境的两个光盘映象文件名是：CentOS-6.7-x86_64-bin-DVD1.iso CentOS-6.7-x86_64-bin-DVD2.iso\n1mkdir /yum 2mount -t iso9660 -r -o ro,loop /data/CentOS-6.7-x86_64-bin-DVD1.iso /mnt 3cp -ar /mnt* /yum 4umount /mnt 5mount -t iso9660 -r -o ro,loop /data/CentOS-6.7-x86_64-bin-DVD2.iso /mnt 6cp /mnt/Packages/*.rpm /mnt/Packages/ 7umount /mnt 文件复制完成以后，我们来配置一下yum源，先在 /data 下创建一个文件夹，把原有yum配置文件移动到这下面，也正好做了一个备份\n1mkdir /data/yum.backup 2mv /etc/yum.repos.d/* /data/yum.backup/ 使用 vim 创建并一个配置文件。名字随便起，注意必须要以 .repo 结尾，这里我就叫 local 吧\n1vim /etc/yum.repos.d/local.repo 写上下面的内容\n1[local] 2name=local 3baseurl=file:///yum 4enabled=1 5gpgcheck=0 完成后，保存退出\n到这里，我们配置完成了，可以使用yum来安装了，这里我来安装一个 gcc 来试验一下\n1sudo yum install gcc 2Loaded plugins: fastestmirror 3Setting up Install Process 4Loading mirror speeds from cached hostfile 5Resolving Dependencies 6--\u0026gt; Running transaction check 7---\u0026gt; Package gcc.x86_64 0:4.4.7-16.el6 will be installed 8--\u0026gt; Processing Dependency: libgomp = 4.4.7-16.el6 for package: gcc-4.4.7-16.el6.x86_64 9--\u0026gt; Processing Dependency: cpp = 4.4.7-16.el6 for package: gcc-4.4.7-16.el6.x86_64 10--\u0026gt; Processing Dependency: glibc-devel \u0026gt;= 2.2.90-12 for package: gcc-4.4.7-16.el6.x86_64 11--\u0026gt; Processing Dependency: cloog-ppl \u0026gt;= 0.15 for package: gcc-4.4.7-16.el6.x86_64 12--\u0026gt; Processing Dependency: libgomp.so.1()(64bit) for package: gcc-4.4.7-16.el6.x86_64 13--\u0026gt; Running transaction check 14---\u0026gt; Package cloog-ppl.x86_64 0:0.15.7-1.2.el6 will be installed 15--\u0026gt; Processing Dependency: libppl_c.so.2()(64bit) for package: cloog-ppl-0.15.7-1.2.el6.x86_64 16--\u0026gt; Processing Dependency: libppl.so.7()(64bit) for package: cloog-ppl-0.15.7-1.2.el6.x86_64 17---\u0026gt; Package cpp.x86_64 0:4.4.7-16.el6 will be installed 18--\u0026gt; Processing Dependency: libmpfr.so.1()(64bit) for package: cpp-4.4.7-16.el6.x86_64 19---\u0026gt; Package glibc-devel.x86_64 0:2.12-1.166.el6 will be installed 20--\u0026gt; Processing Dependency: glibc-headers = 2.12-1.166.el6 for package: glibc-devel-2.12-1.166.el6.x86_64 21--\u0026gt; Processing Dependency: glibc-headers for package: glibc-devel-2.12-1.166.el6.x86_64 22---\u0026gt; Package libgomp.x86_64 0:4.4.7-16.el6 will be installed 23--\u0026gt; Running transaction check 24---\u0026gt; Package glibc-headers.x86_64 0:2.12-1.166.el6 will be installed 25--\u0026gt; Processing Dependency: kernel-headers \u0026gt;= 2.2.1 for package: glibc-headers-2.12-1.166.el6.x86_64 26--\u0026gt; Processing Dependency: kernel-headers for package: glibc-headers-2.12-1.166.el6.x86_64 27---\u0026gt; Package mpfr.x86_64 0:2.4.1-6.el6 will be installed 28---\u0026gt; Package ppl.x86_64 0:0.10.2-11.el6 will be installed 29--\u0026gt; Running transaction check 30---\u0026gt; Package kernel-headers.x86_64 0:2.6.32-573.el6 will be installed 31--\u0026gt; Finished Dependency Resolution 32 33Dependencies Resolved 34 35============================================ 36Package Arch Version Repository Size 37============================================ 38Installing: 39gcc x86_64 4.4.7-16.el6 local 10 M 40Installing for dependencies: 41cloog-ppl x86_64 0.15.7-1.2.el6 local 93 k 42cpp x86_64 4.4.7-16.el6 local 3.7 M 43glibc-devel x86_64 2.12-1.166.el6 local 985 k 44glibc-headers x86_64 2.12-1.166.el6 local 614 k 45kernel-headers x86_64 2.6.32-573.el6 local 3.9 M 46libgomp x86_64 4.4.7-16.el6 local 134 k 47mpfr x86_64 2.4.1-6.el6 local 157 k 48ppl x86_64 0.10.2-11.el6 local 1.3 M 49 50Transaction Summary 51============================================= 52Install 9 Package(s) 53 54Total download size: 21 M 55Installed size: 39 M 56Is this ok [y/N]: 好了，出现询问你是否要安装，代表已经配置成功！！\n","link":"http://test.mylass.com/linux/centos-local-yum-repo/","section":"linux","tags":["yum","localrepo"],"title":"centos 本地yum源配置"},{"body":"简介：最近单位存了两百多台服务器，分批出给客户，客户要求的是ubuntu server 12.04，64位系统，要求我们装好后发货，第一批是76台，想想这数量，一台一台安装，每一台的安装向导，分区，软件包，账号密码这些都得填写，这样下去，那得到什么时候了？\n无人值守安装的过程 机器启动，并从网卡引导 网卡获取ip地址，获取tftp 服务器地址，以及启动文件名称 从tftp服务器下载启动文件 读取相关配置 启动安装 于是乎，就用起pxe+kickstart 来安装吧，说到这两个东西，相信大家肯定熟悉，龙其是做为深资的装机专业户，好了，进入正题\n本次环境： 硬件：cisco UCS C220M3\n软件：ubuntu server 12.04 64位\n安装及配置，首先需要安装 apache tftpserver kickstart 配置工具 1sudo apt-get install system-config-kickstart tftpd-hpa tftp-hpa apache2 启动 tftp和apache 1sudo /etc/init.d/tftp-hpa start 2sudo /etc/init.d/apache2 start 这里我们使用 ubuntu 12.04的镜像，直接挂到目录下，可以通过wget 下载镜像，或者使用xmanager、winscp 从本地上传到服务器，均可，看你更习惯用哪种方法，本次环境就，就放到系统 / 目录下在网站目录建立一个文件夹，用于挂载镜像\n1sodu mkdir /var/www/html/ubuntu12.04 挂载镜像文件到目录，并设置开机自动挂载\n1sudo mount -t iso9660 -r -o ro,loop /ubuntu-12.04.5-server-amd64.iso /var/www/html/ubuntu12.04 2sudo echo \u0026#34;/ubuntu-12.04.5-server-amd64.iso /var/www/html/ubuntu12.04 iso9660 ro,loop,defaults 0 0\u0026#34; \u0026gt;\u0026gt; /etc/fstab 创建ks目录 1sudo mkdir /var/www/html/ks 复制启动文件到tftpboot目录 1sudo cp -arf /var/www/html/ubuntu12.04/install/netboot/* /var/lib/tftpboot 添加 ks.cfg 文路径，在install标签下的append 添加ks=http://10.0.3.8/ks/ks.cfg\n1sudo nano /var/lib/tftpboot/ubuntu-installer/amd64/boot-screens/txt.cfg 修改好的内容如下：\n1default install 2 label install 3 menu label ^Install 4 menu default 5 kernel ubuntu-installer/amd64/linux 6 append ks=http://10.0.3.11/ks/ks.cfg vga=788 initrd=ubuntu-installer/amd64/initrd.gz --quiet //本次环境服务器的IP为10.0.3.11 7label cli 8 menu label ^Command-line install 9 kernel ubuntu-installer/amd64/linux 10 append tasks=standard pkgsel/language-pack-patterns= pkgsel/install-language-support=false vga=788 initrd=ubuntu-installer/amd64/initrd.gz --- quiet ks配置文件：\n这个配置文件，可以用kickstart工具来生成，启动这个工具的话，需要图形界面\n启动工具命令\n1sudo system-config-kickstart 截图如下（左侧是各种类型，也就是我们安装系统的时候，那些选项啦），右侧是设置的内容，全部设置好后，点击左上角的，File，然后点击Save File，就保存到/var/www/html/ks目录下\n我这里环境，使用的是 cisco（思科）交换机，做的dhcp，下面贴上Cisco（思科）交换机dhcp 的命令\n进入全局配置模式\n1ip dhcp pool pxe 2 network 10.0.3.0 255.255.255.0 3 bootfile pxelinux.0 4 next-server 10.0.3.11 5 default-router 10.0.3.254 6 dns-server 10.0.2.2 10.0.2.1 7 lease 0 2 简述： pxe为dhcp pool的名字，可以自行定义\nnetwork 要分配的地址的网段\nbootfile 指定启动文件，注意后面是pxelinux.0，是数字0，不是字母o\ndefault-routeer 和dns-server 为网关和dns，不是必须指定的参数，但如果不指定，安装过程中会跳出来，让你手动输入，这样就不能无人值守安装了\nnext-server 指定tftp服务器，嗯，也就是我们配置服务器地址，10.0.3.11\n下而我们来启动一台机器，安装，这里我再启动一个虚拟机，启动时选择从网络启动\n附1：在某些环境，可能我们的交换机并不是网管交换机，做不了dhcp，这个时候怎么办呢，可以使用linux做为dhcp，这里附上dhcp安装和配置，还以是此服务器上安装\n1sudo apt-get install dhcp3-server 2sudo mv /etc/dhcpd/dhcpd.conf /etc/dhcpd/dhcpd.conf.bak 3sudo nano /etc/dhcpd/dhcpd.conf 配置文件\n1subnet 10.0.3.0 netmask 255.255.255.0 { 2 range 10.0.3.20 10.0.3.100; #地址分配范围 3 option routers 10.0.3.254; #网关 4 option domain-name-servers 10.0.2.1,10.0.2.2; #分配的dns服务器地址，多个地址用英文状态下的逗号 ( , )分隔 5 default-lease-time 7200; #默认租期，单位是秒（s） 6 max-lease-time 14400; #最大租期，单位是秒（s） 7 filename \u0026#34;pxelinux.0\u0026#34;; #pxe启动文件名称，注意文件最后是数字0，不是字母o 8 next-server 10.0.3.11; # tftp 服务器地址 9} 启动dhcp服务\n1sudo /etc/init.d/isc-dhcp-server start 附2：我的ks文件\n1install 2text 3lang en_US 4langsupport en_US 5keyboard us 6mouse 7timezone --utc Asia/Shanghai 8rootpw --iscrypted $1$RjFLPS.0$uBqLmqzdRShnlhGOBUqDJ1 9user tdt --fullname \u0026#34;tdt\u0026#34; --iscrypted --password $1$8zjnLFyv$diBX.YRBk6RoKCBZO5GID. 10reboot 11url --url http://10.0.3.11/ubuntu-server-12.04 12bootloader --location=mbr 13zerombr yes 14clearpart --all --initlabel 15part / --asprimary --fstype ext4 --size 28000 16part /data --asprimary --fstype ext4 --size 256000 17part swap --asprimary --size 1 --grow 18auth --useshadow --enablemd5 19network --bootproto=dhcp --device=eth0 20firewall --disabled 21skipx 22%packages 23@openssh-server 我的环境是，一块300G SAS盘\n以上分区是 / 分区 28G，/data分区是256G，剩下还剩16G，就给了swap，这是客户要求的分区情况，一共三个分区，每个分区，都是主分区，请根据你的实际情况进行调整\n本人的KS，会清空硬盘所有分区和数据，使用前，如果有重要文件，请先备份。\n","link":"http://test.mylass.com/linux/linux-auto-install/","section":"linux","tags":["pxe","autoinstall"],"title":"ubuntu linux pxe 无人值守安装"},{"body":"","link":"http://test.mylass.com/tags/cisco/","section":"tags","tags":null,"title":"cisco"},{"body":"配置 crypto 策略 第一阶段协商，或是做ipsec，需保证两端一致，否则协商不会成功 1crypto ikev1 policy 10 2 authentication pre-share 3 encryption 3des 4 hash md5 5 group 2 6 lifetime 86400 配置 crypto 动态map和 map 1crypto ipsec ikev1 transform-set ezvpn_set esp-3des esp-md5-hmac 2crypto dynamic-map ezvpn_dymap 10 set ikev1 transform-set ezvpn_set 3crypto map ezvpn_map 10 ipsec-isakmp dynamic ezvpn_dymap 将 ikev1 和 crypto map 应用到出接口 1crypto ikev1 enable outside 2crypto map ezvpn_map interface outside 配置 tunnel group 及 pre-shared 密钥 1tunnel-group ezvpn_group type remote-access 2tunnel-group ezvpn_group ipsec-attributes 3 ikev1 pre-shared-key qq123456 用户相关 允许用户访问的内网网段 1access-list Split_tunnel_list extended permit ip 10.22.13.0 255.255.255.0 any 2access-list Split_tunnel_list extended permit ip 10.22.15.0 255.255.255.0 any 3access-list Split_tunnel_list extended permit host 10.27.128.239 any 给予用户分配的IP池 1ip local pool net_vpn_1 10.255.254.11-10.255.254.126 mask 255.255.255.128 策略配置 1group-policy ezvpn_group_policy_user1 internal 2group-policy ezvpn_group_policy_user1 attributes 3 address-pools value net_vpn_1 4 split-tunnel-policy tunnelspecified 5 split-tunnel-network-list value Split_tunnel_list 配置用户并且关联到策略 1username user1 password cisco123 2username user1 attributes 3 vpn-group-policy ezvpn_group_policy_user1 NAT 免除 no nat 将所有内网会用到的网段关，和所有根据不同策略的用户的地址池的地址，来做 object\n多个网段可以使用 object-group 单个网段可直接用 object network 即可\n1object-group network nonat_source 2 network-object 10.22.13.0 255.255.255.0 3 network-object 10.22.15.0 255.255.255.0 4 network-object 10.27.128.224 255.255.255.240 5 network-object 10.39.176.32 255.255.255.224 6 exit 7 8object-group network nonat_dest 9 network-object 10.255.254.0 255.255.255.224 10 network-object 10.255.253.0 255.255.255.0 11 exit 12 13nat (inside,outside) source static nonat_source nonat_source destination static nonat_dest nonat_dest no-proxy-arp 扩展配置： 针对不同用户设置不同的内网访问权限 其实也就是通过access-list 访问控制列表来实现，也可叫做感兴趣流\n需求描述：公司内网划分共有4个网段，其列表和用途如下： 10.21.18.0/25 #测试A组使用 10.21.18.128/25 #测试B组使用 10.21.19.0/24 # 研发部门使用 10.21.20.0/24 #生产服务器使用 需求： 测试A组和B组分别分配3个账号，他们只可以访问自己网段的 研发部门12个账号，只允许访问研发部门的网段 运维部门 4 个账号，可以访问所有网段 两台公共服务器，OA 和 文件服务器，所有账号都可以访问 OA的 ip 为 10.21.20.16， 文件服务器为 10.21.20.135 实现思路：针对不需求做不同的访问控制列表，创建 group-policy，并绑定到不同的用户 配置地址池 配置不同用户的分配的地址池，也可以只用一个地址池，具体看需求，这里分多个，以部门来分\n1ip local pool testA_ipools 10.255.254.1-10.255.254.6 mask 255.255.255.248 2ip local pool testB_ipools 10.255.254.9-10.255.254.14 mask 255.255.2555.248 3ip local pool developer_ipools 10.255.254.17-10.255.254.30 mask 255.255.255.240 4ip local pool yunwei_ipools 10.255.255.254.33-10.255.254.38 mask 255.255.255.248 配置访问控制列表 根据部门来做访问控制列表，源地址为允许访问的服务器地址或网段，目标可以写上面的地址池网段，也可以写 any\n1access-list testA_access extended permit ip 10.21.18.0 255.255.255.128 any 2access-list testA_access extended permit ip host 10.21.20.16 any 3access-list testA_access extended permit ip host 10.21.20.135 any 4 5access-list testB_access extended permit ip 10.21.18.128 255.255.255.128 any 6access-list testB_access extended permit ip host 10.21.20.16 any 7access-list testB_access extended permit ip host 10.21.20.135 any 8 9access-list developer_access extended permit ip 10.21.19.0 255.255.255.0 any 10access-list developer_access extended permit ip host 10.21.20.16 any 11access-list developer_access extended permit ip host 10.21.20.135 any 12 13access-list yunwei_access extended permit ip 10.21.18.0 255.255.254.0 any 14access-list yunwei_access extended permit ip 10.21.20.0 255.255.255.0 any 配置 测试 A 组的 group policy 1group-policy testA_group_policy internal 2group-policy testA_group_policy attributes 3 address-pools value testA_ipools 4 split-tunnel-policy tunnelspecified 5 split-tunnel-network-list value testA_access 配置 测试 B 组的 group policy 1group-policy testB_group_policy internal 2group-policy testB_group_policy attributes 3 address-pools value testB_ipools 4 split-tunnel-policy tunnelspecified 5 split-tunnel-network-list value testB_access 配置 研发 组的 group policy 1group-policy developer_group_policy internal 2group-policy developer_group_policy attributes 3 address-pools value developer_ipools 4 split-tunnel-policy tunnelspecified 5 split-tunnel-network-list value developer_access 配置 运维组的 group policy 1group-policy yunwei_group_policy internal 2group-policy yunwei_group_policy attributes 3 address-pools value yunwei_ipools 4 split-tunnel-policy tunnelspecified 5 split-tunnel-network-list value yunwei_access 创建用户并分配策略 测试A组用户 1username tom password cisco123 2username tom attributes 3 pn-group-policy testA_group_policy 4 exit 5 6username jack password cisco456 7username jack 8 testA_group_policy testA_group_policy 测试B组用户 1username rose password cisco123 2username rose attributes 3 pn-group-policy testB_group_policy 4 exit 5 6username tony password cisco456 7username tony 8 testA_group_policy testB_group_policy ................................ 其它用户照上面例子配置即可， ................................\n","link":"http://test.mylass.com/post/ciscoasavpn/","section":"post","tags":["cisco","vpn","network"],"title":"cisco asa vpn配置"},{"body":"","link":"http://test.mylass.com/tags/network/","section":"tags","tags":null,"title":"network"},{"body":"","link":"http://test.mylass.com/tags/vpn/","section":"tags","tags":null,"title":"vpn"},{"body":"","link":"http://test.mylass.com/series/vpn/","section":"series","tags":null,"title":"vpn"}]