<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Cylon&#39;s Collection</title>
    <link>https://www.oomkill.com/</link>
    <description>Recent content on Cylon&#39;s Collection</description>
    <generator>Hugo -- 0.125.7</generator>
    <language>zh</language>
    <lastBuildDate>Fri, 28 Nov 2025 23:00:36 +0800</lastBuildDate>
    <atom:link href="https://www.oomkill.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Moto G75解锁和国际版rom安装步骤</title>
      <link>https://www.oomkill.com/moto-g75-unlock-and-flush-rom/</link>
      <pubDate>Tue, 25 Nov 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/moto-g75-unlock-and-flush-rom/</guid>
      <description>前言 motorola 和 one plus 应该是目前中国大陆的手机品牌最容易解锁的一款了，其他的都已经被招安内置审查app了。
G75 版本更新策略，找到有两种
一个是 5 个系统版本更新，6个安全更新
Thank you for taking the time to reach out to us. I understand how important updates are to everyone. The device is planned to receive 5 OS upgrades and 6 years of bimonthly security updates from the time of release. [1]
一个是 3 个系统大版本号，6个安全更新
Thanks for reaching out! The Motorola G75 is confirmed to receive 3 major Android updates along with 6 years of security patches.</description>
    </item>
    <item>
      <title>利用github构建个人yum仓库</title>
      <link>https://www.oomkill.com/utilize-github-yum-repo/</link>
      <pubDate>Mon, 30 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/utilize-github-yum-repo/</guid>
      <description>为什么选择 GitHub 作为 YUM 仓库？ 免费托管：GitHub 提供免费的文件存储和 HTTP 服务。 CDN：结合 jsDelivr 等 CDN 服务，可以加速用户的访问速度。 无成本：无需自己搭建服务器，降低维护成本。 使用便利：可以一条命令完成安装，无需再上传安装包了，也可以用来制作下线版本的 yum 仓库。 基本思路 YUM 仓库的核心是文件索引（repodata）和 HTTP 服务。GitHub 提供静态文件托管和 HTTP 访问支持，可以作为 YUM 仓库的存储平台。此外，可以通过 CDN 服务（如 jsDelivr）加速访问（可选）。
存储：将 RPM 包和仓库索引文件存储在 GitHub 仓库中。 访问：通过 GitHub 的 raw 文件访问路径或 jsDelivr 提供 HTTP 服务。 生成索引：使用 createrepo 工具生成 YUM 仓库的元数据（repodata）。 步骤 1：生成 repodata 安装 createrepo 工具 确保已安装 createrepo 工具，用于生成 YUM 仓库的元数据。
bash 1 sudo yum install createrepo -y 创建目录结构 为不同发行版（这里为 CentOS 7 和 Rocky 9）创建对应的目录结构：</description>
    </item>
    <item>
      <title>记录一次服务器断电引起的etcd无法启动问题处理</title>
      <link>https://www.oomkill.com/server-power-outage-etcd-panic-lease/</link>
      <pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/server-power-outage-etcd-panic-lease/</guid>
      <description>背景 在一次物理机断电回复后，Kubernetes 集群因断电或其他原因导致 etcd 启动时出现 “panic: lease ID must be 8-byte” 错误。本文记录如何诊断和修复 etcd 数据损坏，并恢复 Kubernetes 集群的过程。
问题描述 在尝试启动 etcd 服务时，日志显示以下错误：
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 {&amp;#34;level&amp;#34;:&amp;#34;warn&amp;#34;,&amp;#34;ts&amp;#34;:&amp;#34;2025-06-26T08:46:12.</description>
    </item>
    <item>
      <title>CoreDNS 开发系列-4：高并发域名平台架构设计</title>
      <link>https://www.oomkill.com/coredns-serial-04-system-design/</link>
      <pubDate>Sun, 15 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/coredns-serial-04-system-design/</guid>
      <description>本文是CoreDNS 开发系列第4章 CoreDNS 开发系列-1：CoreDNS核心概念和安装配置说明 CoreDNS 开发系列-2：CoreDNS插件详解 CoreDNS 开发系列-3：开发自定义插件 CoreDNS 开发系列-4：高并发域名平台架构设计 在本章节中将创建一个项目，旨在构建一个基于 CoreDNS 的域名系统，该项目目的是可以构建一个完整的 DNS 平台而不是管理平台，可以作为独立的 DNS Provider 运行业务域名解析；也可以作为企业内部 DNS的使用。
分层架构设计 系统采用四层架构设计：
视图层：也称为 API 层，负责提供 DNS 的管理后台， API 接口。 业务层：主要作为 CoreDNS Plugins 实现，用于集成 DNS Server。 数据层：视图层与业务层的联动，多数据库支持（SQLite/MySQL/PostgreSQL）、Redis 缓存、数据同步。 基础设施层：提供 command line 工具，并为 DNS Server 提供四层防火墙、监控告警数据。并提供整个公司生态的服务注册、服务发现等功能。 系统功能需求 功能模块 详细描述 优先级 View 支持多视图配置，智能解析 高 Zone 管理 DNS 区域管理与配置 高 域名管理 管理域中的域名解析 高 Transfer 与云 DNS 供应商数据同步 高 白名单 域名解析黑白名单控制，包含全局和单域名 高 证书管理 Let&amp;rsquo;s Encrypt 证书自动申请与续期 高 解析切换 提供多解析功能，实现故障切换 高 域名检测 域名可用性检测，可以配合切换功能完成故障自动切换 高 CDN 集成 CDN 切换与管理功能 中 运维工具 提供命令行工具 中 GeoIP 基于地理位置的智能 DNS 解析 低 外部系统注册 服务自动注册与发现 低 性能需求 性能指标 目标值 备注 QPS 100,000 一个 view 内的集群至少达到的值 项目分模块设计 视图层 模块名称 功能描述 域、域名管理 完成基础 Zone, Domain的管理功能 证书管理 Let&amp;rsquo;s Encrypt 证书自动申请与续期 View管理 管理域与业务层插件进行联动 白名单管理 域名解析黑白名单控制 Geo 管理 基于地理位置的智能 DNS 解析 CDN 集成 集成CDN联动功能 服务注册插件 提供全企业内的服务注册功能（View+业务） 业务层 模块名称 功能描述 实现方式 DNS 服务 DNS 查询处理、插件加载管理 原生 coredns 数据库 Zone, Domain 信息入库，通过库 Custom Plugin Redis 缓存插件 Zone, Domain 的热点缓存功能 Custom Plugin GeoIP 插件 基于地理位置的智能解析 Custom Plugin View View 的管理和配置 Custom Plugin 白名单 域名访问控制 Custom Plugin Transfer 区域传送与同步 Custom Plugin 基础设施层 模块名称 功能描述 实现技术 服务发现 服务注册与发现 Nacos DNS查询流程设计 多级缓存策略</description>
    </item>
    <item>
      <title>CoreDNS 开发系列-3：开发自定义插件</title>
      <link>https://www.oomkill.com/coredns-serial-03-custom-plugin/</link>
      <pubDate>Fri, 13 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/coredns-serial-03-custom-plugin/</guid>
      <description>本文是CoreDNS 开发系列第3章 CoreDNS 开发系列-1：CoreDNS核心概念和安装配置说明 CoreDNS 开发系列-2：CoreDNS插件详解 CoreDNS 开发系列-3：开发自定义插件 CoreDNS 开发系列-4：高并发域名平台架构设计 在上一篇文章中，我们了解了 CoreDNS 的基本概念、安装和配置文件的说明，与 CoreDNS 中的插件，本文将从零开始，深入学习 CoreDNS 插件开发的完整流程，让您能够开发出满足特定业务需求的高质量插件。在最后我们学习一下 CoreDNS 中的外部插件用以引入开发思路，来解决我们平台中的一些难点。
代码构成 在学习开发插件之前，我们先需要了解下 CoreDNS 的代码目录构成。
text 1 2 3 4 5 6 7 8 9 10 11 coredns/ ├── core/ # 核心组件 │ ├── dnsserver/ # DNS 服务器实现 │ └── plugin/ # 插件管理框架 ├── plugin/ # 内置插件目录 │ ├── cache/ # 缓存插件 │ ├── forward/ # 转发插件 │ ├── kubernetes/ # Kubernetes插件 │ └── .</description>
    </item>
    <item>
      <title>解决AWS EKS error You must be logged in to the server (Unauthorized)</title>
      <link>https://www.oomkill.com/aws-eks-error-you-must-be-logged-in-to-the-server/</link>
      <pubDate>Sat, 07 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/aws-eks-error-you-must-be-logged-in-to-the-server/</guid>
      <description>问题描述 当获取了 EKS kubeconfig 后，使用该 kubeconfig 提示如下报错
bash 1 2 $ kubectl get pod --kubeconfig kubeconfig error: You must be logged in to the server (Unauthorized) 但该 IAM 用户已经存在了管理员权限了
问题原因 该文章有对这个问题进行描述
quote 您不是集群创建者
如果您的 IAM 实体未用于创建集群，说明您不是集群创建者。在这种情况下，请完成以下步骤，将您的 IAM 实体映射到 aws-auth ConfigMap 以允许访问集群 [1]
这里检查和文章描述一致, 但还是这样的问题
bash 1 2 3 4 5 6 $ aws sts get-caller-identity { &amp;#34;UserId&amp;#34;: &amp;#34;AIDAXxxxxxxxIIWKMR22Q&amp;#34;, &amp;#34;Account&amp;#34;: &amp;#34;55555555496&amp;#34;, &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::55555555496:user/eks-user&amp;#34; } quote 这是因为，必须将该用户作为集群的 Access 进行关联，而不是授权 “EKS*” 相关权限 图 - 集群用户选择已经存在的 IAM 用户</description>
    </item>
    <item>
      <title>解决openvpn与其他vpn路由冲突问题</title>
      <link>https://www.oomkill.com/resolve-openvpn-tailscale-routers-conflict/</link>
      <pubDate>Sat, 07 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/resolve-openvpn-tailscale-routers-conflict/</guid>
      <description>需求分析 openvpn在调研时不支持分流配置，需求是openvpn的开启不要影响现有的网络环境。在经过调研，发现 openvpn配置文件可以使用一些指令来指定访问某些地址的路由经过openvpn的设备，这样就可以实现了流量分流。
配置指令说明 这里主要用到了下面的参数
指令 说明 dhcp-option 添加额外的网络参数，可以是在客户端配置，或者服务端推送，这里有指定 DNS redirect-gateway def1 使用这个 def1 flag 可以使用0.0.0.0/1 and 128.0.0.0/1 来覆盖默认路由，这里的好处是不会擦除原有的默认网关 route 可以在建立连接后，自动添加一些路由，并且在TUN/TAP设备关闭后，自动销毁 gateway 默认来自 第二参数或者默认网关，第二参数为
vpn_gateway 指远端的vpn地址
net_gateway 指 per-existing IP默认网关 route-nopull 当在客户端使用时，此选项有效禁止从Server将路由添加到客户端的路由表中，但是请注意，此选项仍然允许 Server 设置TCP/IP 客户端TUN/TAP接口的属性 （这里主要用作创建openvpn自己的网络接口）。 pull-filter 忽略server端push 的资源，这些选项就是来自 —pul 或者其他选项的，例如其他选项 dhcp-option/route/gateway 等。 最终的配置为
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 client proto udp explicit-exit-notify remote x.</description>
    </item>
    <item>
      <title>jenkins pipeline关联aws access key</title>
      <link>https://www.oomkill.com/jenkins-pipeline-associate-aws-access-key/</link>
      <pubDate>Fri, 06 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/jenkins-pipeline-associate-aws-access-key/</guid>
      <description>插件说明 Jenkins 有一个 aws credentials 插件，可以关联到 pipeline 中使用
https://plugins.jenkins.io/aws-credentials/
官方也有给出示例，如何使用 pipeline 关联 ecr
text 1 2 3 withCredentials([[ $class: &amp;#39;AmazonWebServicesCredentialsBinding&amp;#39;, credentialsId: &amp;#39;plt-ia-dev-images-ecr-use1-read&amp;#39;, roleArn: &amp;#39;arn:aws:iam::130312249203:role/PullDockerImages&amp;#39;, roleSessionName: &amp;#39;PullDockerImages&amp;#39;]]){ sh &amp;#34;aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin ecr_registry } 配置过程 创建一个 iam 用户，用于 jenkins 获取 ecr token使用
图 - IAM User图创建用户 - 创建ecr-usernote 不要选择 “Provide user access to the AWS Management Console - optional ” 权限可以选择 “AmazonEC2ContainerRegistryFullAccess”， 也可根据自己需求进行选择</description>
    </item>
    <item>
      <title>CoreDNS 开发系列-2：CoreDNS插件详解</title>
      <link>https://www.oomkill.com/coredns-serial-02-coredns-plugins/</link>
      <pubDate>Wed, 04 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/coredns-serial-02-coredns-plugins/</guid>
      <description>本文是CoreDNS 开发系列第2章 CoreDNS 开发系列-1：CoreDNS核心概念和安装配置说明 CoreDNS 开发系列-2：CoreDNS插件详解 CoreDNS 开发系列-3：开发自定义插件 CoreDNS 开发系列-4：高并发域名平台架构设计 在上一篇文章中，我们了解了 CoreDNS 的基本概念、安装和配置文件的说明。在本文将深入探讨 CoreDNS 的插件 (Plugins)，这是 CoreDNS 强大功能的核心所在。通过理解插件机制和核心插件的工作原理，我们将为后续开发自定义插件和构建 DNS 平台奠定坚实基础。
插件系统设计理念 通常情况下，CoreDNS Plugins在设计上围绕下面的原则进行的
单一职责：每个插件只负责自己负责的功能 链式处理：插件按配置顺序执行链处理请求 可插拔性：插件可以灵活组合和替换 扩展性：支持用户自定义插件开发插件来扩展功能 基于这些原则，使得 CoreDNS 非常强大，非常易于扩展性（对比与最流行的两款开源 DNS 产品来说，Bind, PowerDNS）。
CoreDNS与主流DNS服务产品的对比 下表是调研了三款最流行的 DNS 开源产品来对最符合本项目的后端作为对比，CoreDNS的灵活性相对比较适宜
特性 CoreDNS BIND9 PowerDNS 类型 权威/递归 权威/递归 权威/递归 AXFR/IXFR 支持 支持, trasfer 插件 支持 支持 view 支持（geo, view插件） 原生支持（view 指令） 支持（仅仅LMDB后端） 数据库支持 支持（通过自定义插件 mysql, redis） 有限 DLZ模块 (Dynamically Loadable Zones) [1] 原生有限支持 [2] DNSSEC 支持（NSEC） 全面支持（NSEC/NSEC3） 全面支持（NSEC/NSEC3） 扩展性 极佳（插件架构） 有限扩展，支持c语言库作为plugins 良好 易用性 高（简单配置，现代化） 中（配置复杂，需经验） 高（Web 界面、API） 社区与生态 活跃（CNCF 项目，Kubernetes 生态） 非常活跃（ISC 维护） 活跃（商业支持） 与本项目需求契合度 极高（插件化支持View, AXFR/IXFR, GEO） 高（原生支持VIEW, AXFR/IXFR） 高（数据库支持强，API 同步简单） CoreDNS插件的类型 CoreDNS插件分为两种类型插件，“In-tree Plugins” [3] 和 “External Plugins” [4]；“In-tree Plugins” 是 CoreDNS 官方在提供 coredns 二进制文件时就内置编译到程序内的插件，用户可以自己去配置使用这些插件；“External Plugins” 是包含 CoreDNS 官方与三方作者维护的插件，用户如果想使用的话，需要自行编译 coredns 版本使用。</description>
    </item>
    <item>
      <title>CVE-2024-6387漏洞修复(Rocky9)</title>
      <link>https://www.oomkill.com/upgrade-openssh-in-rocky/</link>
      <pubDate>Mon, 02 Jun 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/upgrade-openssh-in-rocky/</guid>
      <description>下载 openssh-9.9p 源码包 下载地址
下载之后解压看 README 和 INSTALL
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 libcrypto from either of LibreSSL or OpenSSL. Building without libcrypto is supported but severely restricts the available ciphers and algorithms. - LibreSSL (https://www.libressl.org/) 3.1.0 or greater - OpenSSL (https://www.openssl.org) 1.1.1 or greater LibreSSL/OpenSSL should be compiled as a position-independent library (i.e. -fPIC, eg by configuring OpenSSL as &amp;#34;.</description>
    </item>
    <item>
      <title>CoreDNS开发系列-1：CoreDNS核心概念和安装配置说明</title>
      <link>https://www.oomkill.com/coredns-serial-01-coredns-concept/</link>
      <pubDate>Tue, 20 May 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/coredns-serial-01-coredns-concept/</guid>
      <description>本文是CoreDNS 开发系列第1章 CoreDNS 开发系列-1：CoreDNS核心概念和安装配置说明 CoreDNS 开发系列-2：CoreDNS插件详解 CoreDNS 开发系列-3：开发自定义插件 CoreDNS 开发系列-4：高并发域名平台架构设计 CoreDNS 概述 什么是CoreDNS CoreDNS 是一个由 Go 编写的灵活、可扩展的 DNS 服务器。他非常灵活，几乎全部功能都由 plugin 来实现，CoreDNS 官网也有说 “CoreDNS is powered by plugins.” 。Plugins 能够作为 “独立” 或和 CoreDNS “共同” 来执行 “DNS Function” 在 CoreDNS 中被设计为是一个由 “软件实现的 CoreDNS Plugin API”，例如 Kubernetes Provider 可以提供在 k8s 集群里的服务发现。再例如 file 可以提供作为一个 DB 来使用。
CoreDNS 的设计与 与 Caddy 一样也是通过 “插件” 进行扩展，并原生支持 Prometheus 也是 CoreDNS 的一大优势，这意味着我们可以将其连接到现有的 Prometheus 基础架构中进行监控、警报和仪表板管理。
CoreDNS 核心架构 Server：负责监听 DNS 查询请求 Plugins Chain：按照配置顺序串联起来的插件序列 Handler：每个插件实现的请求处理器 Middleware：在请求处理过程中的中间件 DNS 请求在 CoreDNS 中的处理流程如下：</description>
    </item>
    <item>
      <title>Amazon ECR自动创建不存在的存储库</title>
      <link>https://www.oomkill.com/aws-ecr-auto-create-repository/</link>
      <pubDate>Fri, 02 May 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/aws-ecr-auto-create-repository/</guid>
      <description>Amazon ECR 目前不支持镜像存储库的自动创建。当开发人员向 Amazon ECR 推送一个新进项，如果与其对应的存储库不存在，推送就会失败。Amazon ECR 相比起其他公有云，他的镜像是必须要求 dockerhub.io/test/nginx:version, 这里 nginx 才会被是为一个镜像存储库，而 GCP 的 Artifact registry 是 test (Project )才会被视为一个镜像存储库。这样对于存储仓库就不需要额外创建了。
下文阐述 Amazon ECR创建仓库的方法
方法1：awscli awscli 中有 create-repository 子命令，允许用户创建一个仓库
bash 1 aws ecr create-repository --repository-name ${REPO_NAME} 可以使用脚本来检测仓库是否存在 [1]
bash 1 2 3 4 5 6 7 8 9 output=$(aws ecr describe-repositories --repository-names ${REPO_NAME} 2&amp;gt;&amp;amp;1) if [ $? -ne 0 ]; then if echo ${output} | grep -q RepositoryNotFoundException; then aws ecr create-repository --repository-name ${REPO_NAME} else &amp;gt;&amp;amp;2 echo ${output} fi fi 或 [1]</description>
    </item>
    <item>
      <title>创建一个aws ecr自动刷新密钥的sidecar</title>
      <link>https://www.oomkill.com/aws-ecr-auto-refresh-sidecar/</link>
      <pubDate>Fri, 02 May 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/aws-ecr-auto-refresh-sidecar/</guid>
      <description>创建 Dockerfile, 因为需要 aws 命令，就不特别去安装了，直接使用 awslinux 的镜像
docker 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 FROM amazonlinux:2 RUN yum update -y &amp;amp;&amp;amp; \ yum install -y awscli jq &amp;amp;&amp;amp; \ yum clean all WORKDIR /app COPY refresh-ecr-credentials.sh ENV AWS_REGION=${AWS_REGION:-us-east-1} ENV REFRESH_INTERVAL=${REFRESH_INTERVAL:-3600} ENV CREDENTIALS_DIR=${CREDENTIALS_DIR:-/shared_credentials} ENV AWS_CREDENTIALS_FILE=${AWS_CREDENTIALS_FILE:-/opt/password} RUN mkdir -p ${CREDENTIALS_DIR} ~/.aws /opt &amp;amp;&amp;amp; \ chmod 700 ${CREDENTIALS_DIR} ~/.aws /opt &amp;amp;&amp;amp; \ chmod +x /app/refresh-ecr-credentials.</description>
    </item>
    <item>
      <title>Demo - Pod终止的生命周期</title>
      <link>https://www.oomkill.com/kubernetes-terminate-processing/</link>
      <pubDate>Tue, 29 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-terminate-processing/</guid>
      <description>原理 通常 Pod 体面终止的过程为：kubelet 先发送一个带有体面超时限期的 TERM（又名 SIGTERM，根据参数terminationGracePeriodSeconds来决定） 信号到每个容器中的主进程，将请求发送到容器运行时来尝试停止 Pod 中的容器。 停止容器的这些请求由容器运行时以异步方式处理。 这些请求的处理顺序无法被保证。许多容器运行时遵循容器镜像内定义的 STOPSIGNAL 值， 如果不同，则发送容器镜像中配置的 STOPSIGNAL，而不是 TERM 信号。 一旦超出了体面终止限期，容器运行时会向所有剩余进程发送 KILL 信号，之后 Pod 就会被从 API 服务器上移除。 如果 kubelet 或者容器运行时的管理服务在等待进程终止期间被重启， 集群会从头开始重试，赋予 Pod 完整的体面终止限期。
通常终止流程按照下面约束进行：
如果 Pod 中的容器之一定义了 preStop 回调 且 Pod 规约中的 terminationGracePeriodSeconds 未设为 0， kubelet 开始在容器内运行该回调逻辑。默认的 terminationGracePeriodSeconds 设置为 30 秒.
如果 Pod 未定义 preStop 回调，根据默认的 terminationGracePeriodSeconds 设置为 30 秒。进行 kill -9（无论terminationGracePeriodSeconds 有没有配置）
如果 preStop 回调在体面期结束后仍在运行，kubelet 将请求短暂的、一次性的体面期延长 2 秒。即 30 + 2 s 后删除Pod。</description>
    </item>
    <item>
      <title>🙋🏻‍♂️关于</title>
      <link>https://www.oomkill.com/about/</link>
      <pubDate>Sat, 26 Apr 2025 22:23:25 +0800</pubDate>
      <guid>https://www.oomkill.com/about/</guid>
      <description>Hi, I am Cylon I am a programmer.
At the same time, I work full time is Kubernetes Engineer, If I were to express my occupation about this sector with three words, it would be engineering, research and practicality.
I liked Linux, Network and Programming. In a free time, I generally study programming language and network technology 🙂
about me Event logs about me
2015 Graduated from HBU. 2016 PHP Programmer.</description>
    </item>
    <item>
      <title>物理机断电导致osd故障排查记录</title>
      <link>https://www.oomkill.com/ch10-3-troubeshooting-osd-crash-by-poweroff/</link>
      <pubDate>Wed, 16 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch10-3-troubeshooting-osd-crash-by-poweroff/</guid>
      <description>ceph版本 nautilus
处理过程 查看 ceph 集群状态
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ceph -s cluster: id: baf87797-3ec1-4f2c-8126-bf0a44051b13 health: HEALTH_WARN 3 osds down 1 host (3 osds) down 1 pools have many more objects per pg than average Degraded data redundancy: 1167403/4841062 objects degraded (24.115%), 391 pgs degraded, 412 pgs undersized services: mon: 3 daemons, quorum 10.</description>
    </item>
    <item>
      <title>spinnaker对接AWS ECR</title>
      <link>https://www.oomkill.com/spinnaker-aws-ecr-integration/</link>
      <pubDate>Mon, 31 Mar 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/spinnaker-aws-ecr-integration/</guid>
      <description>问题描述 当在使用 docker login 登录 ECR 时需要获取对应的密钥，而在 aws 中可以运行 aws ecr get-login 以获取登录的密钥。这里存在的问题是，AWS ECR 的密钥有效期是 12 小时，必须做到每 12 小时轮换一次。在配置时，就需要解决 clouddriver 可以实时使用最新密钥登录来获取镜像仓库中容器版本。那么问题就变成了：如何可以解决这个限制并允许 Spinnaker 与 AWS ECR 交互？
问题参考 ecr-token-refresh 在实施过程中，参考了 “Using AWS ECR with Spinnaker and Kubernetes” [1] 文章，这篇文章属于官方博客。在这里提到一个方法：“使用 sidecar 来间接刷新 aws ecr 密钥，来完成 clouddriver 可以正常获取密钥。
这里提到的一个项目 ”ecr-token-refresh“ [2] ，这是作者自己编写的一个程序，该程序会定期刷新 ecr 的身份验证令牌。
在参考这个项目实施时，官方提示是下面配置，但和其他传统的 spinnaker 镜像仓库的配置是相同的，要让 --password-file 是动态的。
bash 1 2 3 4 5 $ hal config provider docker-registry account add my-docker-registry \ --address https://&amp;lt;aws-account-number&amp;gt;.</description>
    </item>
    <item>
      <title>深入理解Kubernetes Pod网络原理 - CNI</title>
      <link>https://www.oomkill.com/deep-dive-k8s-network-cni/</link>
      <pubDate>Sun, 02 Feb 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/deep-dive-k8s-network-cni/</guid>
      <description>本文是关于深入理解Kubernetes网络原理系列第3章 深入理解Kubernetes Pod网络原理 - 网络名称空间 深入理解Kubernetes Pod网络原理 - Linux虚拟网络技术 深入理解Kubernetes Pod网络原理 - CNI 深入理解Kubernetes Pod网络原理 - 跟随 flannel 学习CNI原理 深入理解Kubernetes Pod网络原理 - 跟随 flannel + multus 剖析 Chained Plugins 深入理解Kubernetes Pod网络原理 - 从零实现一个 CNI Plugin part 1 (Shell) 深入理解Kubernetes Pod网络原理 - 从零实现一个 CNI Plugin part 2 (libcni) 深入理解Kubernetes Pod网络原理 - Kubernetes网络模型 1 深入理解Kubernetes Pod网络原理 - Kubernetes网络模型 2 深入理解Kubernetes Pod网络原理 - Pod网络排错思路 概述 这是我在 kubernetes 网络之旅中的中的第4部分，主要学习 CNI 规范（5要素，旧版本是4要素）。要深深记住这些，在后面旅程中常常被用到。
Notes 本文讲解均按照 1.</description>
    </item>
    <item>
      <title>使用WSL2安装kind (Win10 &amp; DockerDesktop)</title>
      <link>https://www.oomkill.com/kind-wsl2-windows10-installation/</link>
      <pubDate>Sun, 12 Jan 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kind-wsl2-windows10-installation/</guid>
      <description>本文说明如何使用 Windows 10 创建单节点的 kind 集群 (KinD Kubernetes in Docker)。
先提条件 条件 版本 操作系统：Windows 10 或 Windows 11 May 2020 Update (build 19041) Docker in WSL2 推荐安装Docker Desktop WSL2 distro 镜像 这里采用Debian 内存 至少 8GB 内存 方式1：直接使用 docker desktop进行安装 软件 版本 Docker Desktop 4.8.1 WSL Linux Ubuntu 22 kubectl 使用 wsl ubuntu 22 作为客户端 安装 Docker Desktop 首先完成 Windows 开启 WSL2 和 安装好 Docker Desktop, 可以参考附录1 [1]
安装 kubectl 这里使用和 kind 版本一致的 kubectl 1.</description>
    </item>
    <item>
      <title>filebeat helm chart多配置文件配置</title>
      <link>https://www.oomkill.com/filebeat/</link>
      <pubDate>Thu, 02 Jan 2025 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/filebeat/</guid>
      <description>filebeat helm chart 在配置 filebeatConfig 想配置成多配置文件模式，但是网上没有找到对应配置，单配置文件模式如下所示
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 filebeatConfig: filebeat.yml: | filebeat.inputs: - type: container paths: - /var/log/containers/*.log processors: - add_kubernetes_metadata: host: ${NODE_NAME} matchers: - logs_path: logs_path: &amp;#34;/var/log/containers/&amp;#34; output.elasticsearch: host: &amp;#39;${NODE_NAME}&amp;#39; hosts: &amp;#39;[&amp;#34;https://${ELASTICSEARCH_HOSTS:elasticsearch-master:9200}&amp;#34;]&amp;#39; username: &amp;#39;${ELASTICSEARCH_USERNAME}&amp;#39; password: &amp;#39;${ELASTICSEARCH_PASSWORD}&amp;#39; protocol: https ssl.certificate_authorities: [&amp;#34;/usr/share/filebeat/certs/ca.crt&amp;#34;] 在网上有找到一个配置 [1] 是讲启用 filebeat module
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 filebeatConfig: filebeat.</description>
    </item>
    <item>
      <title>grafana loki的理解与配置(2.9)</title>
      <link>https://www.oomkill.com/grafana-loki-2-9/</link>
      <pubDate>Wed, 25 Dec 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/grafana-loki-2-9/</guid>
      <description>loki的部署模式 grafana loki 在 helm 中版本变化很大，理解部署模式有助于快速 run 一组 loki 服务；loki 服务是一个单体二进制文件运行的微服务架构模式，具体运行的角色通过 -target 参数来区分运行什么组件。
单体模式 单体模式又称整体模式，源自官网 (Monolithic mode)，这个模式指的是 -target=all 时运行的服务。需要注意的是单体模式下，每天读写量为 20GB.
Monolithic mode is useful for getting started quickly to experiment with Loki, as well as for small read/write volumes of up to approximately 20GB per day. [1]
该模式下loki 所有的组件都为二进制文件或者容器作为单一进程运行。
SSD SSD (Simple Scalable deployment mode) 简单可扩展部署模式，是 loki 对内部组件进行分类，当参数 target 我i -target=write , -target=read, -target=backend 时，是作为 SSD mode 启动。其中 write 和 backend 是有状态服务，read 是无状态服务。</description>
    </item>
    <item>
      <title>Hugo博客添加标签云</title>
      <link>https://www.oomkill.com/hugo-add-tag-cloud/</link>
      <pubDate>Wed, 27 Nov 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/hugo-add-tag-cloud/</guid>
      <description>因为 www.sulvblog.cn 域名过期，正好需要查看这个配置，发现搜索引擎已经被删除了特备份一份
1.逻辑控制 定位到layouts/_default/terms.html，把之前的terms-tags标签控制代码注释掉，换成如下代码
html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 &amp;lt;ul class=&amp;#34;terms-tags&amp;#34;&amp;gt; {{- $type := .Type }} {{- range $key, $value := .Data.Terms.Alphabetical }} {{- $name := .Name }} {{- $count := .Count }} {{- with $.Site.GetPage (printf &amp;#34;/%s/%s&amp;#34; $type $name) }} &amp;lt;li&amp;gt; {{ $largestFontSize := 1.5 }} {{ $smallestFontSize := 1 }} {{ $fontSpread := sub $largestFontSize $smallestFontSize }} {{ $max := add (len (index $.</description>
    </item>
    <item>
      <title>debian12 - 高版本系统安装旧版本k8s异常处理</title>
      <link>https://www.oomkill.com/debian12-install-k8s-1.16/</link>
      <pubDate>Sun, 24 Nov 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/debian12-install-k8s-1.16/</guid>
      <description>今日在部署旧版本 k8s 集群 (1.16.10) 时出现错误，主要是在新版本操作系统上部署老版本 k8s，kubelet会出现如下错误
bash 1 2 W1123 22:31:47.383423 3686 server.go:605] failed to get the kubelet&amp;#39;s cgroup: mountpoint for cpu not found. Kubelet system container metrics may be missing. W1123 22:31:47.383572 3686 server.go:612] failed to get the container runtime&amp;#39;s cgroup: failed to get container name for docker process: mountpoint for cpu not found. Runtime system container metrics may be missing. 错误原因 上面的报错是 Kubelet 无法正确访问 Docker 容器运行时的 cgroup 信息，特别是关于 CPU 使用的 cgroup 信息</description>
    </item>
    <item>
      <title>TLS Everywhere - 解密kubernetes集群的安全认证</title>
      <link>https://www.oomkill.com/k8s-auth-and-regenerate-cert/</link>
      <pubDate>Sun, 24 Nov 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/k8s-auth-and-regenerate-cert/</guid>
      <description>本文是关于Kubernetes 4A解析的第5章 深入理解Kubernetes 4A - Authentication源码解析 深入理解Kubernetes 4A - Authorization源码解析 深入理解Kubernetes 4A - Admission Control源码解析 深入理解Kubernetes 4A - Audit源码解析 TLS Everywhere - 解密kubernetes集群的安全认证 所有关于Kubernetes 4A部分代码上传至仓库 github.com/cylonchau/hello-k8s-4A
在 kubernetes 集群中，所有的通讯都是用 TLS 进行加密和认证，本文使用一次老集群（二进制部署集群）证书更换作为记录，通过这种方式深入对 kubernetes 的认证方式来了解更换证书的步骤，以及一次模拟老集群的更换步骤。
本文使用证书生成工具为 “kubernetes-generator” [1] 专用于 k8s 二进制部署生成证书和安装包的工具。
note 本文中的引用文档使用 web.archive 进行保存，避免官方版本更新，其概念与文档中的概念有变动导致，资料引用失败。 Kubernetes认证方式 为了了解证书更换需要做那些步骤，所以必须了解 k8s 的认证方式，这样才能更好的在更换证书时对集群上部署的业务系统的影响降低到最低。
X509 证书 kube-apiserver 的启动参数 --client-ca-file，可以使用客户端办法机构，英文代号就是熟悉的 “CA” (Certificate authority)，当这个证书传递后，可以验证 kube-apiserver 用于验证向 kube-apiserver 提供的客户端证书，这里包含 k8s 中提供的用户种类的两种：
用户名：对应证书的 CN (Common Name) 用户组：对应证书的O (organization)，用于对一个用户组进行授权，例如 “system:masters” 表示一个组 [1]，允许不受限制地访问 kube-apiserver 静态token kube-apiserver 的启动参数 --token-auth-file，是以文件提供给 kube-apiserver，该 Token 会长期有效，并且如果不重启服务 Token 是不会更新。</description>
    </item>
    <item>
      <title>openssl.cnf详解</title>
      <link>https://www.oomkill.com/openssl-cnf/</link>
      <pubDate>Sat, 23 Nov 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/openssl-cnf/</guid>
      <description>下面是一个完整 openssl.cnf 配置文件
ini 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 BASE_DOMAIN= CLUSTER_NAME= CERT_DIR= APISERVER_CLUSTER_IP= MASTER_NAME= [ ca ] # man ca default_ca = CA_default [ CA_default ] # Directory and file locations.</description>
    </item>
    <item>
      <title>zookeeper版本升级 - from 3.4 to 3.8</title>
      <link>https://www.oomkill.com/zk-upgrade-3.4-to-3.6/</link>
      <pubDate>Thu, 21 Nov 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/zk-upgrade-3.4-to-3.6/</guid>
      <description>最近，我不得不将 Zookeeper 3.4.18 集群升级到 3.6+。要求是：无感升级，不丢失数据，并且尽量不向任何用户发出通知。在调研zookeeper 版本后，发现 3.6+ 支持了 metrics 模块，比较符合需求，所以需要从 3.4.18 升级至 3.6.4
3.5 + 支持动态配置 3.6.0+ 支持内置 metrics 模块 现有集群配置 集群IP 当前目录 新版本目录 192.240.16.18 /usr/local/zookeeper-3.4.14/ /usr/local/apache-zookeeper-3.6.4-bin/ 192.240.16.21 /usr/local/zookeeper-3.4.14/ /usr/local/apache-zookeeper-3.6.4-bin/ 192.240.16.28 /usr/local/zookeeper-3.4.14/ /usr/local/apache-zookeeper-3.6.4-bin/ 192.240.16.147 /usr/local/zookeeper-3.4.14/ /usr/local/apache-zookeeper-3.6.4-bin/ 192.240.16.202 /usr/local/zookeeper-3.4.14/ /usr/local/apache-zookeeper-3.6.4-bin/ 下载安装包 在官方 archive 找到对应安装包
从 zk 3.5 起安装包分为带 “bin” 和不带 “bin” 的
带 “bin” 的包含所需jar包 不带 “bin” 的需要自行编译 bash 1 wget https://archive.apache.org/dist/zookeeper/zookeeper-3.6.4/ 解压
bash 1 tar Czxf /usr/local/ apache-zookeeper-3.6.4-bin.tar.gz &amp;amp;&amp;amp; cd /usr/local 升级版本 注意以下步骤需要对每个 zk 服务器都执行一边</description>
    </item>
    <item>
      <title>CentOS7&amp;Rocky9更新xz</title>
      <link>https://www.oomkill.com/xz-upgrade/</link>
      <pubDate>Fri, 01 Nov 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/xz-upgrade/</guid>
      <description>centos&amp;amp;rocky 升级 xz，需要和目前系统对比每个xz包，和每个xz包内的文件有哪些；然后，根据不同类型的包（base, devel, lib)，三个进行打包操作。
下载curl源码包 升级至少需要更新至 xz 5.4.6 ，首先从官网下载源码包 [1]
将xz作为rpm 下面是 rpm 的规格文件
spec 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 Name: xz Version: 5.</description>
    </item>
    <item>
      <title>使用terraform利用已有资源创建GKE集群</title>
      <link>https://www.oomkill.com/gke-create-exists-resources/</link>
      <pubDate>Wed, 02 Oct 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/gke-create-exists-resources/</guid>
      <description>近日创建GKE集群，需要使用现有的VPC进行创建，所以需要掌握两个步骤，导入资源，创建集群
terraform 导入命令 GCP中的资源地址和 ID。资源地址是指向配置中的资源实例的标识符。ID 是标识 Google Cloud 中要导入的资源的标识符
资源地址通常为 terraform在定义这类资源时配置的（对应提供商支持），以 GCP 为例 Cloud Storage 存储桶， google_storage_bucket.sample，sample 为 id，定义如下
yaml 1 2 3 4 5 6 resource &amp;#34;google_storage_bucket&amp;#34; &amp;#34;sample&amp;#34; { name = &amp;#34;my-bucket&amp;#34; project = &amp;#34;sample-project&amp;#34; location = &amp;#34;US&amp;#34; force_destroy = true } 示例 - 导入现有GKE集群 语法
bash 1 terraform import &amp;lt;resource_name&amp;gt;.&amp;lt;name&amp;gt; &amp;lt;project&amp;gt;/&amp;lt;locations&amp;gt;/&amp;lt;real_resource_name&amp;gt; 实例
bash 1 terraform import google_container_cluster.gke project20231124/asia-east2/gke-prd-cluster-02 输出结果如下
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ terraform import google_container_cluster.</description>
    </item>
    <item>
      <title>使用rclone工具完成bucket数据同步</title>
      <link>https://www.oomkill.com/rgw-bucket-sync-with-rclone/</link>
      <pubDate>Tue, 24 Sep 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/rgw-bucket-sync-with-rclone/</guid>
      <description>rclone工具的特点 支持增量，配置简单，支持参数调节吞吐量（不同吞吐量使用内存不同，传输差异也不同） copy是复制 source 到 dst sync是根据 src 的内容对比 dst，删除dst不存在的内容 下面是写了一同步的脚本
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 #!</description>
    </item>
    <item>
      <title>Goswagger - Skipping &#39;&#39;, recursion detected</title>
      <link>https://www.oomkill.com/goswagger-skipping-recursion-detected/</link>
      <pubDate>Sat, 21 Sep 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/goswagger-skipping-recursion-detected/</guid>
      <description>问题：当使用的结构体为嵌套格式，会提示 recursion detected 或 cannot find type definition
go 1 2 3 4 5 6 7 8 9 10 11 type Instance struct { metav1.TypeMeta Instances []InstanceItem `json:&amp;#34;instances&amp;#34; yaml:&amp;#34;instances&amp;#34; form:&amp;#34;instances&amp;#34; binding:&amp;#34;required&amp;#34;` ServiceSelector map[string]string `json:&amp;#34;serivce_selector&amp;#34; yaml:&amp;#34;serivce_selector&amp;#34; form:&amp;#34;serivce_selector&amp;#34;` } type InstanceItem struct { Name string `json:&amp;#34;name&amp;#34; yaml:&amp;#34;name&amp;#34; form:&amp;#34;name&amp;#34; binding:&amp;#34;required&amp;#34;` PromEndpoint string `json:&amp;#34;prom_endpoint&amp;#34; yaml:&amp;#34;prom_endpoint&amp;#34; form:&amp;#34;prom_endpoint&amp;#34; binding:&amp;#34;required&amp;#34;` Labels map[string]string `json:&amp;#34;labels&amp;#34; yaml:&amp;#34;labels&amp;#34; form:&amp;#34;labels&amp;#34;` } go swagger 注释为
text 1 2 3 4 5 6 7 8 9 10 // deleteInstance godoc // @Summary Remove prometheus instance.</description>
    </item>
    <item>
      <title>Gin - 参数默认值问题</title>
      <link>https://www.oomkill.com/gin-param-default-value/</link>
      <pubDate>Fri, 20 Sep 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/gin-param-default-value/</guid>
      <description>遇到问题：gin 使用 Bind 时无法填充，改成下面代码可以获取到
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 type User struct { Name string `form:&amp;#34;name,default=user1&amp;#34; json:&amp;#34;name,default=user2&amp;#34;` Age int `form:&amp;#34;age,default=10&amp;#34; json:&amp;#34;age,default=20&amp;#34;` } r := gin.Default() // way1 curl 127.0.0.1:8900/bind?name=aa // way2 curl -X POST 127.0.0.1:8900/bind -d &amp;#34;name=aa&amp;amp;age=30&amp;#34; // way3 curl -X POST 127.0.0.1:8900/bind -H &amp;#34;Content-Type: application/json&amp;#34; -d &amp;#34;{\&amp;#34;name\&amp;#34;: \&amp;#34;aa\&amp;#34;}&amp;#34; r.</description>
    </item>
    <item>
      <title>Gorm - BeforeDelete无法获取正确条目</title>
      <link>https://www.oomkill.com/gorm-before-delete/</link>
      <pubDate>Fri, 20 Sep 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/gorm-before-delete/</guid>
      <description>遇到问题：BeforeDelete 在删除时获取 SQL 不正确
BeforeDelete 代码如下
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func (t *Target) BeforeDelete(tx *gorm.DB) (err error) { // 找到与此 Target 相关的所有 Labels var labels []Label if err := tx.Model(t).Association(&amp;#34;Labels&amp;#34;).Find(&amp;amp;labels); err != nil { klog.V(4).Infof(&amp;#34;Error fetching labels: %v&amp;#34;, err) return err } for _, label := range labels { if err := tx.Delete(&amp;amp;label).Error; err != nil { klog.</description>
    </item>
    <item>
      <title>Kubernetes公有云集群中部署Nacos集群</title>
      <link>https://www.oomkill.com/nacos-deploy-with-gcp-eks/</link>
      <pubDate>Fri, 20 Sep 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/nacos-deploy-with-gcp-eks/</guid>
      <description>nacos-k8s nacos-k8s 是Nacos官方维护的项目，可以使用 helm 直接在 k8s 集群中部署 nacos 集群（包含公有云）
部署步骤 找到数据库表结构 在你要安装的版本号的配置中找到 SQL 文件进行创建库操作，例如 github.com/alibaba/nacos/tree/2.4.1/distribution/conf
自定义 helm 资源和配置 在公有云上部署，还需要修改下对应资源的类型，例如建立 LB
service 增加了自动获取 gcp 预留的 IP，和service改为LB类型
yaml 1 2 3 4 5 6 7 8 9 10 11 12 service: #type: ClusterIP #type: NodePort type: LoadBalancer port: 8848 nodePort: 30000 # 这样可以使用静态IP loadBalancerIP: 192.168.0.1 annotations: # 这个annotation 原自官方创建 load-balancer的方式 cloud.google.com/load-balancer-type: Internal labels: {} cloud.google.com/load-balancer-type GKE 的 service LB 类型的参数 [1]
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type: &amp;ldquo;intranet&amp;rdquo; ACK 的 service LB 类型的参数 [2]</description>
    </item>
    <item>
      <title>Ceph OSD内存优化与建议</title>
      <link>https://www.oomkill.com/ch03-3-ceph-osd-performance-recommendation/</link>
      <pubDate>Fri, 13 Sep 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch03-3-ceph-osd-performance-recommendation/</guid>
      <description>本文记录了在使用 ceph 集群时遭遇到的内存问题，以及引用和参考一些资料用于对在 ceph 集群使用时的内存预估。
OSD的内存需求 如何评估 Ceph OSD 所需的硬件也是对于集群选型，集群优化的一个必要条件，这里主要找到两个可靠的参考资料用于评估 OSD 内存配置大小
IBM Storage Ceph IBM Storage Ceph 提供了一个运行 Ceph 用于预估系统配置的一个最小推荐列表 [1]，个人感觉可以参考这些信息用于自己集群的优化。主要用于容器化的 Ceph 集群
Process Criteria Minimum Recommended ceph-osd-container Processor 1x AMD64 or Intel 64 CPU CORE per OSD container RAM Minimum of 5 GB of RAM per OSD container OS Disk 1x OS disk per host OSD Storage 1x storage drive per OSD container. Cannot be shared with OS Disk.</description>
    </item>
    <item>
      <title>记录一次失败的radosgw问题排查记录</title>
      <link>https://www.oomkill.com/ch02-4-ceph-deploy-offline-rgw/</link>
      <pubDate>Thu, 12 Sep 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch02-4-ceph-deploy-offline-rgw/</guid>
      <description>本文是Ceph集群部署系列第4章 使用cephadm纯离线安装Ceph集群 使用cephadm纯离线安装Ceph集群 2 Ceph集群安装 - ceph-deploy Ceph集群安装 - ceph-deploy下线rgw 记录一次因着急没有检查原因而直接下线 ceph 对象存储的的失败记录
操作流程 ceph 节点内存持续超过90%，因为本身有三个 OSD，检查内存使用情况发现 radosgw
bash 1 2 3 4 5 6 7 8 9 10 11 $ ps aux --sort=-%mem | head -10 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND ceph 1702 0.4 32.9 10128296 4550760 ? Ssl May03 919:18 /usr/bin/radosgw -f --cluster ceph --name client.rgw.node01 --setuser ceph --setgroup ceph ceph 1721 0.</description>
    </item>
    <item>
      <title>GKE强制升级后JAVA Pod无法识别limit限制</title>
      <link>https://www.oomkill.com/gke-invalid-pod-limits/</link>
      <pubDate>Wed, 11 Sep 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/gke-invalid-pod-limits/</guid>
      <description>今日 GKE EOL，kubelet 自动升级至1.28后，Java程序在启动后无法识别资源清单中的限制，被大量OOMKill
Deployment清单中已经配置了资源限制，例如下面的参数
yaml 1 2 3 4 5 resources: limits: memory: &amp;#34;1Gi&amp;#34; requests: memory: &amp;#34;600Mi&amp;#34; JAVA_OPS参数配置是使用百分比
bash 1 -XX:+UseContainerSupport -XX:InitialRAMPercentage=70.0 -XX:MaxRAMPercentage=70.0 但是启动后无法识别参数，使用 gcloud 登录到主机内查看 jvm 运行状态（因为容器使用 distroless）
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 project-20220325-asia-east-2-pool-221ab289-hgnf ~ # nsenter -t 274655 --mount --uts --ipc --net --pid /opt/java/openjdk/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintContainerInfo -version OSContainer::init: Initializing Container Support Detected cgroups v2 unified hierarchy Path to /cpu.</description>
    </item>
    <item>
      <title>Uranus installation</title>
      <link>https://www.oomkill.com/uranus-installation/</link>
      <pubDate>Fri, 23 Aug 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/uranus-installation/</guid>
      <description>What is an Uranus? Uranus is a Linux firewalld central controller. In Greek mythology, Uranus king of gods. The firewall gateway is the Uranus for iptables.
Prerequisites Hardware requirements We recommend these hardware requirements for production systems or for development systems that are designed to demonstrate production use cases:
Item Description Minimum requirements Recommended Per instance You can install on one node but many features require at least one node. 1 instance &amp;gt; 1 instances RAM per instance Defining your RAM size must be part of the capacity planning for your Uranus usage.</description>
    </item>
    <item>
      <title>Spinnaker 基于判断的条件分支流水线</title>
      <link>https://www.oomkill.com/spinnaker-branching-judgment/</link>
      <pubDate>Sat, 27 Jul 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/spinnaker-branching-judgment/</guid>
      <description>Manual Judgment Stage “Manual Judgment Stage” 是 Spinnaker Pipeline 中的一种阶段 (&amp;ldquo;Stage&amp;rdquo;) 类型，该类型可以作为流水线的门户，作为带外 (Out-of-Bound) 流水线检查，等待手动检查，并且判断结果会终止或继续流水线的执行。
创建一个基于Manual Judgment的流水线 创建一个流水线，添加一个新的 Stage，选择 “Manual Judgment”
图：Manual Judgment创建页面 Jugement Inputs 部分添加对应的选项，选项可以带入变量 $judgment 中
图：Manual Judgment 在执行时 Jugement Inputs Option 的展示 或者是不添加任何选项，那么这个时候就会只有 Stop 和 Continue 两个按钮
图：当 Manual Judgment 没有配置Jugement Inputs Option 的展示 如果添加了选项，可以根据 “选项” 来判断执行的分支
判断可以使用每个阶段内的条件表达式 ”Conditional on Expression“，或者 Check Precondition 类型的阶段
图：根据 “Stage Conditional on Expression” 来定义的选项 “Check Precondition” 是 Spinnaker 流水线中的一个阶段，它可以先前条件并且判断是否继续，这里主要检查该流水线之前所有的流水线你定义要检查的内容，并继续执行接下分支或者阶段
图：“Check Precondition” 的三种类型 图：“Check Precondition” 选择添加表达式的页面 这里选择使用 表达式 (Expression) 来判断前置条件，例如我判断前置 Stage 的选择是否为 “aaaa”</description>
    </item>
    <item>
      <title>Spinnaker 自定义Pipeline模板思路</title>
      <link>https://www.oomkill.com/spinnaker-custom-template/</link>
      <pubDate>Sat, 27 Jul 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/spinnaker-custom-template/</guid>
      <description>流水线模板组合思路 官方流水线示例中没有给出完整的流水线模板和完整的字段，只给出了一个大致的 schema [1]，如下所示
json 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 { &amp;#34;schema&amp;#34;: &amp;#34;v2&amp;#34;, &amp;#34;variables&amp;#34;: [ { &amp;#34;type&amp;#34;: &amp;#34;&amp;lt;type&amp;gt;&amp;#34;, &amp;#34;defaultValue&amp;#34;: &amp;lt;value&amp;gt;, &amp;#34;description&amp;#34;: &amp;#34;&amp;lt;description&amp;gt;&amp;#34;, &amp;#34;name&amp;#34;: &amp;#34;&amp;lt;varName&amp;gt;&amp;#34; } ], &amp;#34;id&amp;#34;: &amp;#34;&amp;lt;templateName&amp;gt;&amp;#34;, # The pipeline instance references the template using this &amp;#34;protect&amp;#34;: &amp;lt;true | false&amp;gt;, &amp;#34;metadata&amp;#34;: { &amp;#34;name&amp;#34;: &amp;#34;displayName&amp;#34;, # The display name shown in Deck &amp;#34;description&amp;#34;: &amp;#34;&amp;lt;description&amp;gt;&amp;#34;, &amp;#34;owner&amp;#34;: &amp;#34;example@example.</description>
    </item>
    <item>
      <title>Hugo - 为文章页面增加相关阅读区域</title>
      <link>https://www.oomkill.com/hugo-add-related-content-section/</link>
      <pubDate>Wed, 17 Jul 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/hugo-add-related-content-section/</guid>
      <description>需求 在页面底部增加相关阅读区域：
简单实现与文章相同 tag 的文章列出到文章底部 实验步骤 新增 related 模板 在 layouts/partials/related.html 新创建一个模板，增加如下内容，本文主题为 PaperModX ，不同的主题，文件在不同目录下
html 1 2 3 4 5 6 7 8 9 {{ $related := .Site.RegularPages.Related . | first 3 }} {{ with $related }} &amp;lt;h3&amp;gt;Related Posts&amp;lt;/h3&amp;gt; &amp;lt;ul&amp;gt; {{ range . }} &amp;lt;li&amp;gt;&amp;lt;a href=&amp;#34;{{ .RelPermalink }}&amp;#34;&amp;gt;{{ .Title }}&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt; {{ end }} &amp;lt;/ul&amp;gt; {{ end }} 将模板加载到文章列表模板内 然后需要在文章列表页底部包含这个 “模板” _default/single.html 不同主题在不同的目录下
html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 .</description>
    </item>
    <item>
      <title>PromQL复杂使用示例</title>
      <link>https://www.oomkill.com/promql-advanced/</link>
      <pubDate>Wed, 17 Jul 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/promql-advanced/</guid>
      <description>查询结果删除某些指标 without without 属于聚合查询的子句，必须在聚合查询中使用
语法：
bash 1 &amp;lt;aggr-op&amp;gt; [without|by (&amp;lt;label list&amp;gt;)] ([parameter,] &amp;lt;vector expression&amp;gt;) 可以看到属于 &amp;lt;aggr-op&amp;gt;
例如
text 1 sum without(instance) (http_requests_total) ignoring ignoring 属于 “向量匹配” (Vector matching) 关键词，可以在 一对多，和多对多查询中使用
语法
bash 1 &amp;lt;vector expr&amp;gt; &amp;lt;bin-op&amp;gt; ignoring(&amp;lt;label list&amp;gt;) &amp;lt;vector expr&amp;gt; 例如
bash 1 method_code:http_errors:rate5m{code=&amp;#34;500&amp;#34;} / ignoring(code) method:http_requests:rate5m 与查询 可以查询满足多个条件的指标，例如下列是查询 jvm 内存 $\frac{used}{committed} &amp;gt; 80%$ 并且 Pod WSS 使用大于 80% 的指标
promql 1 2 3 4 5 6 sum by(pod) (jvm_memory_used_bytes{}) / sum by(pod) (jvm_memory_committed_bytes{}) &amp;gt; .</description>
    </item>
    <item>
      <title>Hugo - 去除Sitemap中的tags search等页面</title>
      <link>https://www.oomkill.com/hugo-sitemap-without-tag-page/</link>
      <pubDate>Sat, 13 Jul 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/hugo-sitemap-without-tag-page/</guid>
      <description>需求 在不禁用分类的情况下，关闭对应 sitemap.xml 中的条目以优化 SEO
去除所有tag 去除所有分类 去除 search about me 这类页面 实验步骤 sitemap 是通过 go-template 目标进行的，只要可以使用对应语法过滤了相关路径即可以排除对应的页面
首先在配置文件增加 taxonomiesExcludedFromSitemap 选项，这个选项排除了 “hugo中分类法” 中的所有子类；其次使用 if not 来排除所有对应首页面。如下列所示
本文已 PaperModX 为例，修改文件 layouts\sitemap.xml
xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 {{ printf &amp;#34;&amp;lt;?</description>
    </item>
    <item>
      <title>构建集群kubernetes v1.28并使用kine和mysql替换etcd</title>
      <link>https://www.oomkill.com/kubernetes-without-etcd-step-by-step/</link>
      <pubDate>Sun, 30 Jun 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-without-etcd-step-by-step/</guid>
      <description>在本文中，将探讨使用 k3s 的 kine 项目来替换掉 etcd，并通过实验使用 kubeadm 去 run 一个 k8s 集群，并用 k3s 的 kine 项目来替换掉 etcd。
为什么使用 kine etcd 在 Kubernetes 之外基本上没有应用的场景，并且 etcd 迭代也比较慢，由于没有人愿意维护因此一直在衰退 [1]，并且，Kubernetes 集群中，etcd 也是一个影响集群规模的重大因素。并且 K3S 存在一个项目 Kine 可以使用关系型数据库运行，这样对集群维护者来说可以不需要维护复杂的 etcd 集群，由于关系型数据库有很多高可用方案，这将使得 k8s 集群规模变成了无限可能。
Kine 介绍 前文提到，kubernetes (kube-apiserver) 与 etcd 是耦合的，如果我们要使用 RDBMS 去替换 etcd 就需要实现 etcd 的接口，那么这个项目就是 Kine [2]。
Kine 是一个 etcdshim，处于 kube-apiserver 和 RDBMS 的中间层，它实现了 etcdAPI的子集（不是etcd的全部功能），Kine 在 RDBMS 数据库之上实现了简单的多版本并发控制；将所有信息存储在一个表中；每行存储此 key 的修订, key, 当前值, 先前值, 先前修订，以及表示该 Key 是已创建还是已删除的标记，通过这种机制可以作为 shim 层来替换 etcd。</description>
    </item>
    <item>
      <title>Debian网络配置</title>
      <link>https://www.oomkill.com/debian-network-configration/</link>
      <pubDate>Sat, 29 Jun 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/debian-network-configration/</guid>
      <description>设置一个网络接口 debian 中网络接口的配置文件是在 /etc/network/interfaces，可以设置 “静态地址” 或 “DHCP”
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 cat /etc/network/interfaces # This file describes the network interfaces available on your system # and how to activate them. For more information, see interfaces(5). source /etc/network/interfaces.</description>
    </item>
    <item>
      <title>安装Debian12 (Bookworm) Step-by-Step</title>
      <link>https://www.oomkill.com/debian12-install-tutorial-step-by-step/</link>
      <pubDate>Sat, 29 Jun 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/debian12-install-tutorial-step-by-step/</guid>
      <description>Preparation debian12 几乎可以使用任何旧的计算机硬件，因为最小安装的要求非常低。以下是最低要求和推荐要求：
最低要求 推荐要求 存储：10 Gigabytes
内存：512 Megabytes
CPU: 1 GigaHertz 存储：10 Gigabytes内存：2 GigabytesCPU: 1 GigaHertz or more 如何选择下载安装包 offical mirror aliyun mirror 官网提供了安装包的下载，其中CD是网络安装，DVD是离线安装
debian官方下载页面 Notes：CD安装包很小，下载下来是 debian-11.4.0-amd64-netinst.iso 如名所示，这是一个网络安装包，所以推荐下载DVD部分，可以达到离线安装的效果
截至文章编写日期，debian-12.5.0-amd64-DVD-1.iso 大小是 3.7G
Debian12 EOL：June 30th, 2028
安装步骤 在界面中选择“Install”，安装将开始。如果图形化安装可以选择“Graphical install”，这里选择“Install”。
欢迎页面 完成后，系统将提示选择安装时的“语言”。选择喜欢的语言，然后按“Enter”。这里选择英文
选择语言页面 这将是接下来安装步骤
安装步骤概述 选择位置与键盘布局 选择地区，这里选择美国
选择区域 下面部署时选择键盘布局：中国大陆使用的键盘布局是美国-英语，不要选择英国-英语之类，布局是不一样的，会存在按键输出的结果会不同
选择键盘布局 完成上述操作后，将开始加载镜像。等待扫描完成。。。。
等待扫描组件 设置主机名和域名 这步骤中将配置一个“主机名”。与一个“域”名称。
配置主机名 “域” 可以选择留空确定
配置域 完成上述操作后，安装程序将提示需要设置 root 密码。输入您的 root 密码，然后在重新输入以进行验证后继续。
Tips: 这里建议设置密码，不设置密码会导致安装完成后无法进入 root 用户**，**这样就需要根据先登录普通用户，然后通过 sudo切换过去。
设置Root密码 设置Root密码 - 二次确认 设置非ROOT用户名、账户和密码 下一步创建一个非ROOT用户，这个步骤是必须的，并为这个新创建的帐户分配一个密码。以下截图将描述将如何完成此操作。</description>
    </item>
    <item>
      <title>Go每日一库 - 使用 gin &#43; goswagger 构建 REST API 文档</title>
      <link>https://www.oomkill.com/golib-go-swagger/</link>
      <pubDate>Wed, 19 Jun 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/golib-go-swagger/</guid>
      <description>OpenAPI 什么是OpenAPI Swagger 是一套围绕 OpenAPI 规范构建的开源工具，可帮助我们设计，构建，记录和使用 REST API。
OpenAPI 规范（前名称为 Swagger 规范）是 REST API 的 API 描述格式。包括：
可用端点 ( 例如 /users) 以及每个 endpoint 上的操作 (例如 GET /users, POST /users) 操作参数，每个操作的输入和输出 认证方法 联系信息，许可证，使用条款等其他信息。 什么是 Swagger？ Swagger 是一组围绕 OpenAPI 规范构建的开源工具，有助于用户设计，构建，记录和使用 REST API，支持整个 API 生命周期的开发，从设计和文档到测试和部署。
使用 Swagger 的目的 标准化文档格式：Swagger (OpenAPI) 采用了准化 API 文档格式。通过使用 Swaggo（将注释转换为 Swagger2.0文档的包） 生成 Swagger 文档，Swagger 的结构化格式的文档，使开发人员更容易理解产品的 API 交互。 交互式文档体验：Swagger UI 与 Swaggo 集成，提供交互式且用户友好的界面，用于测试 API。Swaggo提供了一个自动生成的界面，允许开发人员浏览 Endpoint，查看请求/响应示例，甚至可以直接从文档执行 API 请求。这种交互式体验可提高开发人员的工作效率并加速 API 的采用。 自动且最新的文档：Swaggo 可自动从用户的 Go 代码生成 API 文档。这种自动化无需手动维护单独的文档文件。Swaggo 直接从用户的代码库中提取信息，包括 endpoint 详细信息，请求/响应模型和注释。使用这种方法可确保用户的 API 文档随着代码的更新而保持最新。 Swagger 与 Gin 的集成 拉取 Swaggo 使用如下命令下载swag</description>
    </item>
    <item>
      <title>使用docker管理谷歌物件仓库gcr上的镜像</title>
      <link>https://www.oomkill.com/docker-push-gcr/</link>
      <pubDate>Sat, 01 Jun 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/docker-push-gcr/</guid>
      <description>创建服务账户 首先可以到「 IAM管理 -&amp;gt; 服务帐户」新增帐户。在新增完成后，会得到一把 key，将它下载后请妥善保管，因为所有相关的身份认证都会用到，这个 key 在下载后就无法继续下载了。
授权 接着到「IAM -&amp;gt; 新增」成员，并且选择角色，这里选择「Cloud Storage -&amp;gt; 储存空间物件检视者」，让此帐户具备有 read（读取） storage 的功能。
登录 bash 1 2 cat KEY-FILE | docker login -u KEY-TYPE --password-stdin \ https://LOCATION-docker.pkg.dev GCP 的 KEY-TYPE 通为 json_key，但这里包含两种类型 _json_key 和 _json_key_base64
KEY-FILE 就是下载的 Service account key 的文件
bash 1 2 cat KEY-FILE | docker login -u _json_key --password-stdin \ https://LOCATION-docker.pkg.dev 通常 Service account key 文件内容如下
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 { &amp;#34;type&amp;#34;: &amp;#34;service_account&amp;#34;, &amp;#34;project_id&amp;#34;: &amp;#34;project2024-0101&amp;#34;, &amp;#34;private_key_id&amp;#34;: &amp;#34;bdfsd612779509406bb8452c3ek12d730ed547e722d&amp;#34;, &amp;#34;private_key&amp;#34;: &amp;#34;-----BEGIN PRIVATE KEY----.</description>
    </item>
    <item>
      <title>深入解析Kubernetes监控体系与prometheus-adapter</title>
      <link>https://www.oomkill.com/prometheus-adapter-intro/</link>
      <pubDate>Fri, 31 May 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/prometheus-adapter-intro/</guid>
      <description>Kubernetes监控架构设计 k8s监控设计背景说明 根据 Kubernetes监控架构 1，Kubernetes 集群中的 metrcis 可以分为 系统指标 (Core Metrics) 和 服务指标 (service metrics) ; 系统指标(System metrics) 是通用的指标，通常可以从每一个被监控的实体中获得（例如，容器和节点的CPU和内存使用情况）。服务指标(Service metrics) 是在应用程序代码中显式定义并暴露的 (例如，API Server 处理的 500 错误数量)。
Kubernetes将系统指标分为两部分：
核心指标 (core metrics) 是 Kubernetes 理解和用于其内部组件和核心工具操作的指标，例如：用于调度的指标 (包括资源估算算法的输入, 初始资源/VPA (vertical autoscaling)，集群自动扩缩 (cluster autoscaling)，水平Pod自动扩缩 (horizontal pod autoscaling ) 除自定义指标之外的指标)；Kube Dashboard 使用的指标，以及 “kubectl top” 命令使用的指标。 非核心指标 (non-core metrics) 是指不被 Kubernetes 解释的指标。我们一般假设这些指标包含核心指标 (但不一定是 Kubernetes 可理解的格式)，以及其他额外的指标。 所以，kubernetes monitoring 的架构被设计拥有如下特点：
通过标准的主 API (当前为主监控 API) 提供关于Node, Pod 和容器的核心系统指标，使得核心 Kubernetes 功能不依赖于非核心组件 kubelet 只导出有限的指标集，即核心 Kubernetes 组件正常运行所需的指标。 &amp;hellip; 监控管道 Kubernetes 监控管道分为两个：</description>
    </item>
    <item>
      <title>StackStorm自动化 - 工作流模型</title>
      <link>https://www.oomkill.com/stackstorm-sensors/</link>
      <pubDate>Fri, 24 May 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/stackstorm-sensors/</guid>
      <description>工作流模型是指 Stackstorm 中 Orquesta 工作流的定义，包含工作流的执行方式，也可以理解为工作流模型就是 Workflow DSL 定义任务执行的有向图
工作流模型 下表是工作流模型 (Workflow Model) 的属性。工作流接受 Input，按预定义顺序执行一组任务 (Task)，并返回输出 (Output)。此处的工作流模型是一个有向图 (directed graph)，其中 Task 是节点，Taskt 之间的转换及其条件形成边。组成工作流的任务将在 DSL 中定义为名为 Task 的字典， 其中 Key 和 Value 分别是任务名称和任务模型。
Attribute Required Description version Yes The version of the spec being used in this workflow DSL. description No The description of the workflow. input No A list of input arguments for this workflow. vars No A list of variables defined for the scope of this workflow.</description>
    </item>
    <item>
      <title>nacos code=403,msg=user not found!</title>
      <link>https://www.oomkill.com/nacos-403-user-not-found/</link>
      <pubDate>Mon, 20 May 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/nacos-403-user-not-found/</guid>
      <description>应用连接 nacos 时报错 403，用户密码均正确，用户存在，并且权限正确
text 1 2 2024-05-20 10:36:11,593 - [ERROR] - [ropertySourceBuilder][main][n.c.NacosPropertySourceBuilder: 101][]: get data from Nacos error,dataId:admin-server.yaml - com.alibaba.nacos.api.exception.NacosException: http error, code=403,msg=user not found!,dataId=admin-server.yaml,group=DEFAULT_GROUP,tenant=cced143f-5adb-4cb8-a580-28802ea8f203 at com.alibaba.nacos.client.config.impl.ClientWorker$ConfigRpcTransportClient.queryConfig(ClientWorker.java:979) 原因：nacos 地址应该和应用连接的不一致，修改一致后恢复正常
nacos 配置文件配置 “/nacos”， 应用直接连接 “/”
bash 1 server.servlet.contextPath=/nacos </description>
    </item>
    <item>
      <title>GCP机器类型</title>
      <link>https://www.oomkill.com/type-of-machine-for-gcp/</link>
      <pubDate>Thu, 02 May 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/type-of-machine-for-gcp/</guid>
      <description>本文档使用以下术语 机器系列：针对特定工作负载优化的一组精选处理器和硬件配置。创建虚拟机时，您可以从首选机器系列中选择预定义或自定义机器类型。
机器系列：机器系列按系列和世代进一步分类。例如，通用机器系列中的 N1 系列是 N2 系列的旧版本。世代编号或系列号越高，表示底层 CPU 平台或技术较新。例如，M3 系列是 M2 系列的较新世代。
机器类型：每个机器类型都有一个预定义机器类型，用于为您的虚拟机提供一组资源。如果预定义机器类型不能满足您的需求，您还可以为某些机器系列创建自定义机器类型。
代 Intel AMD Arm 第 4 代机器系列 N4, C4, X4 N/A C4A 第 3 代机器系列 C3、Z3、H3、M3、A3 C3D N/A 第 2 代机器系列 E2、N2、C2、M2、A2、G2 N2D、C2D、T2D、E2 T2A 第 1 代机器系列 N1、M1 机器系列和系列建议 下表提供了针对不同工作负载的建议。
通用工作负载 E2 N2、N2D、N1 C3、C3D Tau T2D、Tau T2A 以更低的费用进行日常计算 在多种机器类型之间实现均衡的性价比 在各种工作负载中始终如一地保持高性能 最佳每核心性能/费用（适用于横向扩容工作负载） 低流量 Web 服务器
后台应用
容器化的微服务
微服务
虚拟桌面
开发和测试环境 中低流量 Web 和应用服务器
容器化的微服务
商业智能应用
虚拟桌面
CRM 应用</description>
    </item>
    <item>
      <title>GKE - 为GKE集群增加VPC防火墙规则</title>
      <link>https://www.oomkill.com/gke-vpc-firewall/</link>
      <pubDate>Thu, 02 May 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/gke-vpc-firewall/</guid>
      <description>GKE添加VPC防火墙规则有与GCE有一些区别，必须找到GKE的”网络标记“才可以，如下
选择 Kubernetes Engine =&amp;gt; 选择 ”集群“ 进入 GKE 集群主页
随便选择一个集群，进入集群详细页面
选择集群中的任意一个节点池
找到节点池中任意一个节点，点击进入
进入后向下拉找到”网络标记“部分，这个网络标记可以标记这个集群的所有节点
如果想自定义”网络标记“的名称，可以在集群首页选择标记进行修改</description>
    </item>
    <item>
      <title>探索kubectl - kubectl诊断命令集合</title>
      <link>https://www.oomkill.com/kubernetes-kubectl-diagnose/</link>
      <pubDate>Sat, 20 Apr 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-kubectl-diagnose/</guid>
      <description>工具命令集合 长期总结 - Linux日志查询命令 长期总结 - Linux网络命令合集 长期总结 - Linux性能分析命令 awk常用案例 bash shell常用示例 探索kubectl - 巧用jsonpath提取有用数据 探索kubectl - kubectl诊断命令集合 Pod 检查 Pod 就绪探针
bash 1 kubectl get pods &amp;lt;pod-name&amp;gt; -n &amp;lt;namespace&amp;gt; -o jsonpath=&amp;#39;{.status.conditions[?(@.type==&amp;#34;Ready&amp;#34;)].status}&amp;#39; 查看 Pod 事件
bash 1 kubectl get events -n &amp;lt;namespace&amp;gt; --field-selector involvedObject.name=&amp;lt;pod-name&amp;gt; 获取 Pod Affinity 和 Anti-Affinity
bash 1 kubectl get pod &amp;lt;pod-name&amp;gt; -n &amp;lt;namespace&amp;gt; -o=jsonpath=&amp;#39;{.spec.affinity}&amp;#39; 列出 Pod 的 anti-affinity 规则
bash 1 kubectl get pod &amp;lt;pod-name&amp;gt; -n &amp;lt;namespace&amp;gt; -o=jsonpath=&amp;#39;{.</description>
    </item>
    <item>
      <title>批量更新harbor版本 1.10 to 2.10</title>
      <link>https://www.oomkill.com/upgrade-harbor/</link>
      <pubDate>Fri, 29 Mar 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/upgrade-harbor/</guid>
      <description>本文将介绍 Harbor 从 v1.10.7 升级到 v2.10.0，以及如何将 Harbor 从 v2.10 回滚到 v1.10.7。
升级条件 Linux服务器 4 个 CPU 和 8 GB 内存（强要求），100G可用空间（跨多版本时存放备份文件以及镜像文件，这部分要求） Docker-compose &amp;gt; 1.19.0+ 备份现有的 Harbor /data/database 目录 本次升级主要是使用了 harbor 内置的数据库，所以升级步骤比较容易。
官方升级路线 harbor 的升级，是不能跨很多版本进行升级，官方对此有详细说明 [1] ，可以看到路线为：
1.10.0 [1] =&amp;gt; 2.4.0 [2] =&amp;gt; 2.6.0 [3] =&amp;gt; 2.8.0 [4] =&amp;gt; 2.10.0 [5]
模拟升级步骤 github release 页下载对应的安装包
解压
bash 1 2 # 命令主要为将harbor压缩包内文件解压到指定目录中，由于 harbor 解压后文件名无论版本如何都为“harbor” $ mkdir ./harbor-v1.10 &amp;amp;&amp;amp; tar -xf harbor-offline-installer-v1.10.0.tgz -C ./harbor-v1.10 --strip-components 1 备份默认的配置文件（仅限于 v1.</description>
    </item>
    <item>
      <title>Kubernetes维护 - secret批量更新</title>
      <link>https://www.oomkill.com/kubernetes-update-secert/</link>
      <pubDate>Tue, 20 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-update-secert/</guid>
      <description>tls 证书在 k8s 集群上大量使用的话，当到期时会存在批量替换的难度，比如说每个名称空间，多个业务的使用，在这篇博文中，将尝试批量替换整个集群的证书（前提，在没有使用 vault, cert-manager这类组件的集群之上）。
基本操作 步骤1：首先不知道有多少个名称空间使用了这个证书，所以需要遍历所有的名称空间，这里使用 kubectl 的 json path 实现
bash 1 $ kubectl get ns -o jsonpath=&amp;#39;{range $.items[*]}{.metadata.name}{&amp;#34;\n&amp;#34;}{end}&amp;#39; 步骤2：拿到名称空间的名字后，就需要循环这个名称空间下所有的 secret
bash 1 2 3 4 for ns in `kubectl get ns -o jsonpath=&amp;#39;{range $.items[*]}{.metadata.name}{&amp;#34;\n&amp;#34;}{end}&amp;#39;` do kubectl get secret -n $ns -o jsonpath=&amp;#39;{range $.items[*]}{.metadata.name}{&amp;#34;\n&amp;#34;}{end}&amp;#39; done 步骤3：找到与这个匹配的证书进行替换
把步骤3拆解为下面几个步骤：
拿去到符合要求的secret的名字 匹配名称是否为修改的secret 做替换操作 由于步骤2使用的是 jsonpath 拿到的 secret name，由于 kubectl 并不支持高级jsonpath语法，官方推荐使用jq，那么使用jq获取名字
bash 1 kubectl get secret -n $ns -o json|jq -r .</description>
    </item>
    <item>
      <title>使用虚拟机部署nacos</title>
      <link>https://www.oomkill.com/nacos-deploy-with-vm/</link>
      <pubDate>Tue, 20 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/nacos-deploy-with-vm/</guid>
      <description>下载 nacos-server
bash 1 $ tar zxvf nacos-server-2.2.3.tar.gz -C /opt/ 创建nacos用户
bash 1 useradd nacos -s /sbin/nologin -M 修改 java 环境变量
使用openjdk启动，需要配置JAVA_HOME在启动脚本中
bash 1 2 3 4 $ rpm -ql java-1.8.0-openjdk-headless # 找到 jre 根目录配置 JAVA_HOME # /opt/nacos/bin/startup.sh JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre 启动命令
集群模式需要同时启动多个节点
bash 1 2 3 4 5 6 7 启动命令 # 单机 sudo -u nacos /opt/nacos/bin/startup.sh -m standalone # 集群 sudo -u nacos /opt/nacos/bin/startup.sh -m cluster # 停止服务 sudo -u nacos /opt/nacos/bin/shutdown.</description>
    </item>
    <item>
      <title>k8s - jsonnet从入门到放弃</title>
      <link>https://www.oomkill.com/k8s-jsonnet/</link>
      <pubDate>Sun, 18 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/k8s-jsonnet/</guid>
      <description>什么是jsonnet jsonnet是用于app或开发工具的数据模板语言，主要用于json的扩展，具有下面功能：
生成配置数据 无副作用 组织化，简化，统一化 管理无序的配置 jsonnet可以通过面向对象消除重复。或者，使用函数。与现有/自定义应用程序集成。生成 JSON、YAML、INI 和其他格式。
安装jsonnet Jsonnet 有两种实现（C++ 和 Go）
在 Debian/Ubuntu 之上，可以直接使用 apt 源来安装
bash 1 apt install jsonnet -y 安装 go 实现的，可以用下面命令，前提是安装了go
bash 1 go get github.com/google/go-jsonnet/cmd/jsonnet 什么是jsonnet-bundler jsonnet-bundler 是 Jsonnet 的包管理器，用于个简化 jsonnet 项目中依赖关系管理的工具。使用 Jsonnet Bundler 可以带来下面便利之处：
使用 jsonnetfile.json 作为依赖关系管理 自动安装和更新依赖项。 版本选择，使用 jsonnetfile.json 可以确保项目使用正确版本的依赖。 可重复构建， 使用 jsonnetfile.json 管理的项目可以在不同环境中构建并确保结果的一致性。 更方便的与 GitOps 结合， Jsonnet Bundler 提供 与 GitOps 的集成。 jsonnet-bundler 安装 Jsonnet Bundler 有两种安装模式，实际上就是 Go 程序通用的安装方式：</description>
    </item>
    <item>
      <title>记录一次ceph集群故障处理记录</title>
      <link>https://www.oomkill.com/ch10-2-troubeshooting-crash-record/</link>
      <pubDate>Tue, 13 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch10-2-troubeshooting-crash-record/</guid>
      <description>处理记录 Ceph版本：octopus
首先遇到問題是，业务端无法挂在 cephfs 查看内核日志发现是 bad authorize reply ，以为是 ceph keyring被替换了
text 1 2 3 4 5 6 7 8 2019-01-30 17:26:58 localhost kernel: libceph: mds0 10.80.20.100:6801 bad authorize reply 2019-01-30 17:26:58 localhost kernel: libceph: mds0 10.80.20.100:6801 bad authorize reply 2019-01-30 17:26:58 localhost kernel: libceph: mds0 10.80.20.100:6801 bad authorize reply 2019-01-30 17:26:58 localhost kernel: libceph: mds0 10.80.20.100:6801 bad authorize reply 2019-01-30 17:26:58 localhost kernel: libceph: mds0 10.80.20.100:6801 bad authorize reply 2019-01-30 17:26:58 localhost kernel: libceph: mds0 10.</description>
    </item>
    <item>
      <title>深入理解Kubernetes - 基于OOMKill的QoS的设计</title>
      <link>https://www.oomkill.com/ch30-oomkill/</link>
      <pubDate>Tue, 30 Jan 2024 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch30-oomkill/</guid>
      <description>Overview 阅读完本文，您当了解
Linux oom kill Kubernetes oom 算法 Kubernetes QoS 本文只是个人理解，如果有大佬觉得不是这样的可以留言一起讨论，参考源码版本为 1.18.20，与高版本相差不大
什么是OOM Kill 当你的Linux机器内存不足时，内核会调用Out of Memory (OOM) killer来释放一些内存。这经常在运行许多内存密集型进程的服务器上遇到。
OOM Killer是如何选择要杀死的进程的？ Linux内核为每个运行的进程分配一个分数，称为 oom_score，==显示在内存紧张时终止该进程的可能性有多大==。该 Score 与进程使用的内存量成比例。 Score 是进程使用内存的百分比乘以10。因此，最大分数是 $100% \times 10 = 1000$。此外，如果一个进程以特权用户身份运行，那么与普通用户进程相比，它的 oom_score 会稍低。
在主发行版内核会将 /proc/sys/vm/overcommit_memory 的默认值设置为零，这意味着进程可以请求比系统中当前可用的内存更多的内存。这是基于以下启发式完成的：分配的内存不会立即使用，并且进程在其生命周期内也不会使用它们分配的所有内存。如果没有过度使用，系统将无法充分利用其内存，从而浪费一些内存。过量使用内存允许系统以更有效的方式使用内存，但存在 OOM 情况的风险。占用内存的程序会耗尽系统内存，使整个系统陷入瘫痪。当内存太低时，这可能会导致这样的情况：即使是单个页面也无法分配给用户进程，从而允许管理员终止适当的任务，或者内核执行重要操作，例如释放内存。在这种情况下，OOM Killer 就会介入，并将该进程识别为牺牲品，以保证系统其余部分的利益。
用户和系统管理员经常询问控制 OOM Killer 行为的方法。为了方便控制，引入了 /proc/&amp;lt;pid&amp;gt;/oom_adj 来防止系统中的重要进程被杀死，并定义进程被杀死的顺序。 oom_adj 的可能值范围为 -17 到 +15。Score 越高，相关进程就越有可能被 OOM-killer Kill。如果 oom_adj 设置为 -17，则 OOM Killer 不会 Kill 该进程。
oom_score 分数为 1 ~ 1000，值越低，程序被杀死的机会就越小。
oom_score 0 表示该进程未使用任何可用内存。 oom_score 1000 表示该进程正在使用 100% 的可用内存，大于1000，也取1000。 谁是糟糕的进程？ 在内存不足的情况下选择要被终止的进程是基于其 oom_score 。糟糕进程 Score 被记录在 /proc/&amp;lt;pid&amp;gt;/oom_score 文件中。该值是基于系统损失的最小工作量、回收的大量内存、不终止任何消耗大量内存的无辜进程以及终止的进程数量最小化（如果可能限制在一个）等因素来确定的。糟糕程度得分是使用进程的原始内存大小、其 CPU 时间（utime + stime）、运行时间（uptime - 启动时间）以及其 oom_adj 值计算的。进程使用的内存越多，得分越高。进程在系统中存在的时间越长，得分越小。</description>
    </item>
    <item>
      <title>使用keycloak作为grafana的OAuth2认证</title>
      <link>https://www.oomkill.com/grafana-keycloak/</link>
      <pubDate>Tue, 19 Dec 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/grafana-keycloak/</guid>
      <description>本文使用 helm 方式部署 grafana 9 并同样将 keycloak 部署在 kubernetes 集群之上；接下来使用 keycloak 作为 grafana authentication，并实现 oauth2 的用户权限管理。
在Kubernetes 集群之上使用helm部署keycloak 在 kubernetes 集群安装 keycloak 有两种方式：
bitnami helm offical 下面使用 offical 提供的方式进行部署
bash 1 kubectl create -f https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/latest/kubernetes/keycloak.yaml helm 部署完成后默认密码是存储在 secret 中，上面方式安装的密码默认为 admin/admin
Keycloak configuration 创建realm Realm 管理这一组用户(users), 凭据(credentials), 角色(roles) 和 组(groups)，realm之间是相互隔离，一个用户属于并登录到某个 realm，只能管理和验证其控制的用户。
下面为 grafana 创建一个 realm，如果你的环境已经存在通用的 realm，则可以使用这个 realm，默认 keycloak 的 realm 是 master，超级管理员属于这个 realm。
创建 client Client 是可以请求Keycloak对用户进行身份验证的实体。最常见用途是希望使用Keycloak来保护自己并提供单点登录(SSO)解决方案的应用程序和服务。客户端也可以是只希望请求身份信息或访问令牌的实体，以便它们可以安全地调用由 Keycloak 保护的网络上的其他服务。因此，我们需要为 grafana 创建一个 client</description>
    </item>
    <item>
      <title>在隔离网络中的多k8s集群中的实现JProfiler的自动化映射方案的设计与实现</title>
      <link>https://www.oomkill.com/jprofiler-in-k8s-cluster/</link>
      <pubDate>Mon, 11 Dec 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/jprofiler-in-k8s-cluster/</guid>
      <description>背景与架构设计 网络中存在的挑战 挑战1：Kubernetes 的每个 Pod 拥有一个独立的 IP 地址。对外部访问则依赖 NodePort、LoadBalancer 或 Ingress，出于安全考虑不可能对每个 Pod 都暴露其 8849 端口 (NodePort) 或者使用 Ingress 配置大量的域名，这样无法连接到单独的某一个 Pod (通过Service)。 挑战2：网络环境是完全隔离的，用户无法通过 Pod IP 直接访问 Pod，所有的用户流量只能通过对应 IDC 的唯一入口进入。 挑战3：出于安全考虑不可能对每一个 Java 服务 (Pod) 在他的工作周期期间所有时间都暴露对应的 Jprofiler 端口，而仅仅想使用时可以连接，用后关闭。 JProfiler网络需求 JProfiler 可以通过加载 JVM 代理（libjprofilerti.so）与远程 GUI 通信，他的实现原理如下：
JVM 启动时加载 JProfiler 代理，绑定到一个特定端口（如 8849）。 本地 JProfiler GUI 通过该端口连接到远程 JVM。 代理与 GUI 之间通过 TCP 传输性能数据。 在 Kubernetes 中，JProfiler 代理运行在 Pod 内部，但由于网络隔离和动态 IP，GUI 无法直接连接到 Pod。因此，我们需要一种机制将 JProfiler 的端口动态映射到可访问的外部端点。
需要实现的架构 下图是基于上面提到的问题从而设计的集群架构</description>
    </item>
    <item>
      <title>StackStorm自动化 - Sensor</title>
      <link>https://www.oomkill.com/stackstorm-sensors/</link>
      <pubDate>Sat, 02 Dec 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/stackstorm-sensors/</guid>
      <description>什么是传感器 传感器 (Sensor) 是将外部系统和事件与 StackStorm 集成的一种方式。传感器是 Python 代码片段，它们要么定期轮询某些外部系统，要么被动等待入站事件，通常示例用于每隔一段时间去轮询某一个对象，然后他们将 Trigger 注入 StackStorm，可以通过规则进行匹配，以执行潜在的 Action。
Sensor 是用 Python 编写的，并且必须遵循 StackStorm 定义的传感器接口要求。
什么是触发器 触发器 (Trigger) 是 StackStorm 中用于识别 StackStorm 的传入事件。Trigger 是类型（字符串）和可选参数（对象）的元组。编写 Rule 是为了与 Trigger 一起使用。Sensor 通常会记录 Trigger，但这并不是严格要求的。例如，有一个向 StackStorm 注册的通用Webhooks触发器，它不需要自定义传感器。
Stackstorm内置触发器 默认情况下，StackStorm 会发出一些内部 Trigger，您可以在规则中利用它们。这些触发器可以与非系统触发器区分开来，因为它们的前缀为 “st2”。
下面包含每个资源的可用 Trigger 列表：
Action
Reference Description Properties core.st2.generic.actiontrigger 封装 Action 执行完成的触发器 execution_id, status, start_timestamp, action_name, action_ref, runner_ref, parameters, result core.st2.generic.notifytrigger 通知触发器 execution_id, status, start_timestamp, end_timestamp, action_ref, runner_ref, channel, route, message, data core.</description>
    </item>
    <item>
      <title>StackStorm自动化 - 包</title>
      <link>https://www.oomkill.com/stackstorm-pack/</link>
      <pubDate>Thu, 30 Nov 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/stackstorm-pack/</guid>
      <description>什么是包 包 “pack” 是扩展 StackStorm 的集成和自动化的部署单元。通常， pack 是沿着服务或产品边界组织的，例如 AWS、Docker、Sensu 等。 pack 包含Actions、Workflows、Rules、 Sensors和Aliases。StackStorm 内容始终是 pack 的一部分，因此了解如何创建 pack 并使用它们非常重要。
一些 pack 扩展了 StackStorm 以将其与外部系统集成，例如 AWS，GitHub，JIRA。我们称它们为“集成 pack ”。有些 pack 捕获自动化模式：这类 pack 含特定自动化过程的 workflow, Rule 和 Action - 例如st2 演示 pack 。我们称它们为“自动化 pack ”。这种命名主要是一种约定：StackStorm 本身对两者没有区别。
任何使用该 pack 所针对的服务的人都可以共享和重用集成 pack 。您可以在StackStorm Exchange找到许多这样的示例。自动化 pack 通常是特定于站点的，并且在特定团队或公司之外几乎没有用处；它们通常在内部共享。
总结：Packs是StackStorm中组织工作流、动作和传感器的方式。它们是一组相关的动作、工作流和传感器的集合，通常用于实现特定的自动化任务或集成。
包管理 StackStorm pack 通过命令进行管理：将为您提供有用的概述。st2 pack &amp;lt;...&amp;gt; / st2 pack -h 有些（例如core 基本 StackStorm action）是随 StackStorm 预装的。所有其他 pack 都需要您安装。幸运的是，这很容易！ list和get是获取有关本地 pack 信息的主要命令：</description>
    </item>
    <item>
      <title>StackStorm自动化 - Rules</title>
      <link>https://www.oomkill.com/stackstorm-rules/</link>
      <pubDate>Sat, 25 Nov 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/stackstorm-rules/</guid>
      <description>StackStorm 使用 Rules 和 Workflows 来捕获操作模式并进行自动化。rule将 Triggers 映射到 Actions（或 Workflow），应用匹配条件( Criteria)，并将 Triggers payloads 映射到 Actions 的 Input。
注意
rule不按预期工作吗？请查看rule故障排除文档。其中介绍了rule测试、检查执行、记录和故障排除等内容。
Rule 的配置结构 stackstorm 中的 Rule 是以 YAML 格式来定义。以下是 Rule 定义结构以及 “必需”和 “可选” rule 元素的列表：
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 --- name: &amp;#34;rule_name&amp;#34; # required pack: &amp;#34;examples&amp;#34; # optional description: &amp;#34;Rule description.&amp;#34; # optional enabled: true # required trigger: # required type: &amp;#34;trigger_type_ref&amp;#34; criteria: # optional trigger.</description>
    </item>
    <item>
      <title>client-go - Pod使用in-cluster方式访问集群</title>
      <link>https://www.oomkill.com/ch07-in-cluster-pod/</link>
      <pubDate>Wed, 15 Nov 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch07-in-cluster-pod/</guid>
      <description>在我们基于 Kubernetes 编写云原生 GoLang 代码时，通常在本地调试时，使用 kubeconfig 文件，以构建基于 clientSet 的客户端。而在将代码作为容器部署到集群时，则会使用集群 (in-cluster) 内的配置。
clientcmd 模块用于通过传递本地 kubeconfig 文件构建 clientSet。因此，在容器内使用相同模块构建 clientSet 将需要维护容器进程可访问的 kubeconfig 文件，并设置具有访问 Kubernetes 资源权限的 serviceaccount token。
下面是一个基于 kubeconfig 访问集群的代码模式
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var ( k8sconfig *string //使用kubeconfig配置文件进行集群权限认证 restConfig *rest.Config err error ) if home := homedir.HomeDir(); home != &amp;#34;&amp;#34; { k8sconfig = flag.String(&amp;#34;kubeconfig&amp;#34;, fmt.Sprintf(&amp;#34;./admin.conf&amp;#34;), &amp;#34;kubernetes auth config&amp;#34;) } flag.</description>
    </item>
    <item>
      <title>当cephfs和fscache结合时在K8s环境下的全集群规模故障</title>
      <link>https://www.oomkill.com/ch10-1-ceph-fscache/</link>
      <pubDate>Sat, 11 Nov 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch10-1-ceph-fscache/</guid>
      <description>本文记录了在 kubernetes 环境中，使用 cephfs 时当启用了 fscache 时，由于网络问题，或者 ceph 集群问题导致的整个 k8s 集群规模的挂载故障问题。
结合fscache的kubernetes中使用cephfs造成的集群规模故障 在了解了上面的基础知识后，就可以引入故障了，下面是故障产生环境的配置
故障发生环境 软件 版本 Centos 7.9 Ceph nautilus (14.20) Kernel 4.18.16 故障现象 在 k8s 集群中挂在 cephfs 的场景下，新启动的 Pod 报错无法启动，报错信息如下
bash 1 ContainerCannotRun: error while creating mount source path /var/lib/kubelet/pods/5446c441-9162-45e8-0e93-b59be74d13b/volumes/kubernetesio-cephfs/{dir name} mkcir /var/lib/kubelet/pods/5446c441-9162-45e8-de93-b59bte74d13b/volumes/kubernetes.io~cephfs/ip-ib file existe 主要表现的现象大概为如下三个特征
对于该节点故障之前运行的 Pod 是正常运行，但是无法写入和读取数据
无法写入数据 permission denied
无法读取数据
kublet 的日志报错截图如下
彻底解决方法 需要驱逐该节点上所有挂在 cephfs 的 Pod，之后新调度来的 Pod 就可以正常启动了
故障的分析 当网络出现问题时，如果使用了 cephfs 的 Pod 就会出现大量故障，具体故障表现方式有下面几种
新部署的 Pod 处于 Waiting 状态</description>
    </item>
    <item>
      <title>初识Argo cd - 注册/删除k8s集群</title>
      <link>https://www.oomkill.com/ch03-argo-add-cluster/</link>
      <pubDate>Sun, 05 Nov 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch03-argo-add-cluster/</guid>
      <description>登录argo cd bash 1 argocd login argocd_server:argocd_port_here 执行后输入admin/sercert
bash 1 2 3 4 5 6 $ argocd login 10.0.0.5:30908 WARNING: server certificate had error: x509: cannot validate certificate for 10.0.0.5 because it doesn&amp;#39;t contain any IP SANs. Proceed insecurely (y/n)? y Username: admin Password: &amp;#39;admin:login&amp;#39; logged in successfully Context &amp;#39;10.0.0.5:30908&amp;#39; updated argocd cli 登录后的文件保存在 ~/.argocd/config 中
注册一个新集群 argocd 通过 kubectl 来获取集群的信息，所以 argocd 的主机上必须有 kubeconfig 文件
Note: KUBECONFIG 文件地址必须为实际路径，比如 ~/ 这种方式不可以</description>
    </item>
    <item>
      <title>深入Argo - Application resources</title>
      <link>https://www.oomkill.com/ch04-application/</link>
      <pubDate>Sun, 05 Nov 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch04-application/</guid>
      <description>在安装和注册集群完成后，就需要引入第一个概念 “Application”（如何管理所有我的应用程序？）
什么是 Application 什么是 ArgoCD “Application”？ 对于 ArgoCD “Application”的快速解释：它是托管 ArgoCD 部署的 Kubernetes 集群 CRD 包含了应用程序的所有设置，如：
要部署到哪个集群？ 与哪个 Git 存储库进行同步？ 其他部署设置 应用程序的 YAML 包含了部署您的存储库资源所需的所有信息，充当了在 ArgoCD 中管理应用程序的关键控制点。
Reference ​[1] docs/operator-manual/argocd-cm.yaml
​[2] Getting started with multi-cluster K8S deployments using Argo CD
​[3] https://medium.com/notive/managing-argocd-application-resources-1b2b4742ab90</description>
    </item>
    <item>
      <title>nginx中的多路分支 - nginx map</title>
      <link>https://www.oomkill.com/ngx-map/</link>
      <pubDate>Sat, 04 Nov 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ngx-map/</guid>
      <description>引言 在 NGINX 中常用一种 “比较变量” 的手法，在编程语言中称为 “多路分支” (Case statement)，也就是 nginx map，需要注意的一点是，太低版本 NGINX MAP 中只能使用单变量
Before version 0.9.0 only a single variable could be specified in the first parameter. [1]
下面将了解下 nginx map 的具体使用方式
nginx map使用 Nginx 配置主要是声明性的，这同样应用于 MAP 指令，NGINX MAP 是定义在 http{} 级别，最大的特点是仅在引用时进行处理， 如果请求未触及使用 NGINX MAP 变量的配置部分，则不会执行该 map 变量查找。换句话来理解，当在上下文 server, Location, if 等中使用结果变量时（指定的不是计算结果，而是在需要时计算该结果的公式），才会被使用，在 NGINX 需要使用该变量之前，NGINX MAP 不会给请求增加任何开销。
NGINX MAP 用于根据另一个变量的值创建一个变量，如下所示：
text 1 2 3 4 map $variable_to_check $variable_to_set { &amp;#34;check_if_variable_matches_me&amp;#34; &amp;#34;variable_matches_checked_value&amp;#34;; default &amp;#34;no_match&amp;#34;; } 在上面的例子中， 变量 $variable_to_set 的被设置的结果为：如果 $variable_to_check 值为 “check_if_variable_matches_me”， 那么 $variable_to_set 将被设置为值 “variable_matches_checked_value” ， 否则将设置为 “no_match”。</description>
    </item>
    <item>
      <title>GKE标准集群价格选择示例</title>
      <link>https://www.oomkill.com/price-of-gke/</link>
      <pubDate>Thu, 02 Nov 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/price-of-gke/</guid>
      <description>GKE标准机器通常费用组成为 “集群管理费” + 标准GCE主机费用，以香港为例
主机规格 CPU (CORE/Mon) MEM (GB/Mon) E2( E2Balanced: N1, N2)：费用优化 $23.77 $2.99 N1 (旧型号的Intel Sandy Bridge、Ivy Bridge、Haswell、Broadwell、Skylake) $38.45 $4.55 N2 CPU $31.9 $4.01 N2D CPU $27.75 $3.48 选择核心的标准（强要求）
intel 2的公差，例如1, 2, 4, 6, 8, 10 AMD 2, 4, 8, 16, 32 只有 “费用优化” (cose-optimized) 的可以自定义配置，计算优化，内存优化等都是固定配置
新加坡的价格是香港价格的 &amp;ldquo;90%&amp;rdquo;</description>
    </item>
    <item>
      <title>K8S Admission Webhook官方扩展版 - ValidatingAdmissionPolicy</title>
      <link>https://www.oomkill.com/kubernetes-validatingadmissionpolicy/</link>
      <pubDate>Wed, 01 Nov 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-validatingadmissionpolicy/</guid>
      <description>相关阅读：深入理解Kubernetes 4A - Admission Control源码解析
准入 (Admission) 是 Kubernetes 提供 4A 安全认证中的一个步骤，在以前版本中 (1,26-)，官方提供了 webhook 功能，使用户可以自行的定义 Kubernetes 资源准入规则，但这些是有成本的，需要自行开发 webhook，下图是 Kubernetes准入控制流程。
图：Kubernetes API 请求的请求处理步骤图 Source：https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/ 在 Kubernetes 1.26 时 引入了 ValidatingAdmissionPolicy alpha 版，这个功能等于将 Admission Webhook controller 作为了一个官方扩展版，通过资源进行自行扩展，通过这种方式带来下面优势：
减少了准入请求延迟，提高可靠性和可用性 能够在不影响可用性的情况下失败关闭 避免 webhooks 的操作负担 ValidatingAdmissionPolicy 说明 验证准入策略提供一种声明式的、进程内的替代方案来验证准入 Webhook。
验证准入策略使用通用表达语言 (Common Expression Language，CEL) 来声明策略的验证规则。 验证准入策略是高度可配置的，使配置策略的作者能够根据集群管理员的需要， 定义可以参数化并限定到资源的策略
下面是一个 ValidatingAdmissionPolicy 的示例，配置 Deployment 必须拥有的副本数的限制
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 apiVersion: admissionregistration.</description>
    </item>
    <item>
      <title>Kubernetes集群中的IP伪装 - ip-masq-agent</title>
      <link>https://www.oomkill.com/ch24-ip-masq/</link>
      <pubDate>Sat, 28 Oct 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch24-ip-masq/</guid>
      <description>“IP 伪装” 通常应用于云环境中，例如 GKE, AWS, CCE 等云厂商都有使用 “IP伪装” 技术，本文将围绕 “IP伪装” 技术本身，以及这项技术在 Kubernetes 集群中的实现应用 ip-masq-agent 的源码分析，以及 ”IP伪装“ 能为 Kubernetes 带来什么作用，这三个方向阐述。
什么是IP伪装？ IP 伪装 (IP Masquerade) 是 Linux 中的一个网络功能，一对多 (1 to Many) 的网络地址转换 (NAT) 的功能 。
IP 伪装允许一组计算机通过 “伪装” 网关无形地访问互联网。对于互联网上的其他计算机，出站流量将看起来来自于 IP MASQ 服务器本身。互联网上任何希望发回数据包（作为答复）的主机必须将该数据包发送到网关 （IP MASQ 服务器本身）。记住，网关（IP MASQ 服务器本身）是互联网上唯一可见的主机。网关重写目标地址，用被伪装的机器的 IP 地址替换自己的地址，并将该数据包转发到本地网络进行传递。
除了增加的功能之外，IP Masquerade 为创建一个高度安全的网络环境提供了基础。通过良好构建的防火墙，突破经过良好配置的伪装系统和内部局域网的安全性应该会相当困难。
IP Masquerade 从 Linux 1.3.x 开始支持，目前基本所有 Linux 发行版都带有 IP 伪装的功能
什么情况下不需要IP伪装 已经连接到互联网的独立主机 为其他主机分配了多个公共地址 IP伪装在Kubernetes集群中的应用 IP 伪装通常应用在大规模 Kubernetes 集群中，主要用于解决 “地址冲突” 的问题，例如在 GCP 中，通常是一种 IP 可路由的网络模型，例如分配给 Pod service 的 ClusterIP 只能在 Kubernetes 集群内部可用，而分配 IP CIDR 又是一种不可控的情况，假设，我们为 k8s 分配的 IP CIDR 段如下表所示：</description>
    </item>
    <item>
      <title>Linux网络子系统中的计数器</title>
      <link>https://www.oomkill.com/linux-network-conunter/</link>
      <pubDate>Thu, 26 Oct 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/linux-network-conunter/</guid>
      <description>在Prometheus node-exporter中，存在多个网络监控指标指标标志着主机的网络状态，但是大家常常忽略这些指标，而这些指标又很重要，这些指标的来源是根据Linux网络子系统中的多个计数器定义的，本文就解开这些TCP计数器的面目。
TcpExtListenOverflows 和 TcpExtListenDrops 当内核从客户端接收到 SYN 时，如果 TCP 接受队列已满，内核将丢弃 SYN 并将 TcpExtListenOverflows +1。同时内核也会给TcpExtListenDrops +1。当 TCP 套接字处于 LISTEN 状态，并且内核需要丢弃数据包时，内核总是将 TcpExtListenDrops +1。因此，增加 TcpExtListenOverflows 将使 TcpExtListenDrops 同时增加，但在不增加 TcpExtListenOverflows 的情况下，TcpExtListenDrops 也会增加，例如内存分配失败也会导致 TcpExtListenDrops 增加。
以上解释基于内核 4.10 或更高版本，在旧内核上，当 TCP 接受队列已满时，TCP Stack有不同的行为。在旧内核上，TCP Stack不会丢弃 SYN，它会完成 3 次握手。当接受队列已满时，TCP 堆栈会将套接字保留在 TCP 半开队列中。由于处于半开队列中，TCP 堆栈将在指数退避计时器上发送 SYN+ACK，在客户端回复 ACK 后，TCP Stack检查接受队列是否仍满，如果未满，则将套接字移至接受队列如果队列已满，则将套接字保留在半开队列中，下次客户端回复ACK时，该套接字将有另一次机会移至接受队列。
这两个计数器在 node_expoter 中的指标是：
node_netstat_TcpExt_ListenDrops node_netstat_TcpExt_ListenOverflows TcpInSegs 和 TcpOutSegs TcpInSegs 和 TcpOutSegs 都是被定义在 RFC1213 [1]
TcpInSegs 是指 TCP layer 接收到的数据包数量，包括错误接收的数据包，例如校验和错误、无效的TCP头等。只有一个错误不会被包含在内：如果第 2 层目标地址不是 NIC 的第 2 层地址。如果数据包是多播或广播数据包，或者 NIC 处于混杂模式，则可能会发生这种情况。在这些情况下，数据包将被传递到 TCP 层，但 TCP 层将在增加 TcpInSegs 之前丢弃这些数据包。 TcpInSegs 计数器不知道 GRO (Generic Receive Offload)。因此，如果两个数据包被 GRO 合并，TcpInSegs 计数器只会增加 1。</description>
    </item>
    <item>
      <title>初识Argo cd - 在k8s集群上安装argo cd</title>
      <link>https://www.oomkill.com/argo-installtion/</link>
      <pubDate>Tue, 24 Oct 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/argo-installtion/</guid>
      <description>GitOps 最初由 Weaveworks (weave cni的组织) 在 2017 年的博客中提出 [1]，使用 “Git” 作为 CI/CD 的 “单一事实来源”，将代码的更改集成到每个项目的存储库中，并使用拉取请求来管理 infra 和部署。 在理解上就可以理解为 “是一种基于 git 的操作框架”
Argo CD 是一种 kubernetes 之上的 “声明式” (declarative) 的 gitops CD， 在本文作为了解如何在 Kubernetes 集群中安装和配置 Argo CD。
前提准备 想要安装 Argo CD 首先环境需要具备如下：
已经安装好 kubectl 命令行工具 拥有 kubeconfig 文件 一个可供测试的 Kubernetes 集群，如：kind, minikube, kubeadm, binary 等任意的集群 步骤1 - 选择适配 kubernetes 版本的 Argo 根据官方的解释， Argo CD 在任何给定时刻所支持的版本，这些版本是 N 和 N - 1 次要版本的最新修补版本 (x.x.new)。这些 Argo CD 版本与 Kubernetes 项目官方支持的 Kubernetes 版本相一致，通常是 Kubernetes 的最近发布的 3 个版本。</description>
    </item>
    <item>
      <title>初识Argo cd - argo cd架构</title>
      <link>https://www.oomkill.com/ch01-argo-beginning/</link>
      <pubDate>Sun, 22 Oct 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch01-argo-beginning/</guid>
      <description>Argo组件 API Server Repository Server Application Controller API Server：一个 gRPC/REST 服务器，提供了 “Web UI”、“CLI” 和 “CI/CD” 使用的 API
应用管理和状态报告 调用应用操作（例如同步、回滚、用户定义的操作） 存储库和 Cluster credential 管理（作为 kubernetes secret 存储） 为外部提供身份认证和代理授权功能 RBAC 试试 Git webhook 事件的 listener/forwarder Repository Server：内部服务，用于维护 git 中的应用清单 (manifests) 的本地缓存。负责接收生成和返回 kubernetes 清单
仓库URL revision (commit, tag, branch) APP PATH 模板特定的参数 Application Controller：Kubernetes controller，主要做的工作是持续监控运行的 Application，并于当前实时状态和目标所需状态进行对比（与 Kubernetes Controller 功能是相同的），并且不仅仅是 KC 还会和存储库中指定目标状态进行比较，检测到 OutOfSync 状态将进行纠正。
Argo 架构 Argo CD 时最常见的三种架构：单实例方案, 集群级方案，以及折衷方案 (compromise between the two)。</description>
    </item>
    <item>
      <title>CentOS6/7 curl SOCKS5堆溢出漏洞修复 CVE-2023-38545 CVE-2023-38546</title>
      <link>https://www.oomkill.com/update-curl-8-4/</link>
      <pubDate>Fri, 13 Oct 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/update-curl-8-4/</guid>
      <description>10月11日发布的 curl 8.4.0版本，在新版本中修复漏洞 CVE-2023-38545 和 CVE-2023-38546
CVE-2023-38545: This flaw makes curl overflow a heap based buffer in the SOCKS5 proxy handshake. [1] CVE-2023-38546: This flaw allows an attacker to insert cookies at will into a running program using libcurl, if the specific series of conditions are met. [2] 安装方式有两种，“编译” 与 “更新RPM”，本文以 RPM 方式更新 curl 到 8.4.0 版本
下载curl源码包 升级至少需要更新至 curl 8.4 ，首先从官网下载源码包 [3]
将curl打包为rpm 因为 curl 源码包内没有提供 rpm 的规格文件，所以我们需要自己编写，但是比较麻烦，可以让 chatgpt 生成一个，这里使用 centos7 的 curl.</description>
    </item>
    <item>
      <title>Docker运行PostgreSQL</title>
      <link>https://www.oomkill.com/postgresql-docker-setup/</link>
      <pubDate>Thu, 05 Oct 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/postgresql-docker-setup/</guid>
      <description>在本文，尝试使用 Docker 运行 PostgreSQL ，为了适配 goalert 项目，因为从来没有尝试过使用 PostgreSQL
了解PostgreSQL数据库 在我们继续运行 PostgreSQL 数据库的 Docker 容器之前，我们先来了解一下 PostgreSQL 数据库。 PostgreSQL 是一个开源 RDMS，类似于 MySQL。它是一个面向对象的数据库，但我们可以处理结构化和非结构化数据。
PostgreSQL 数据库可以运行在各种平台上，包括 Windows、Mac OS X 和 Linux。它还提供高级数据类型和性能优化功能来存储和扩展复杂的数据库工作负载。
一些常见的 postgres 镜像
镜像 说明 postgres:latest 最新的一个稳定版本 postgres:17 PostgreSQL version 14.x （x为最近的一次 patch） postgres:17.4 17.4 一个具体的版本 postgres:bookworm 使用 Debian Bookworm (12) 构建的 PostgreSQL postgres:15-bookworm 使用 Debian Bookworm (12) 构建的 PostgreSQL 15 使用公共镜像运行PostgreSQL 要使用 Docker 运行 PostgreSQL，我们首先需要拉取 Docker Hub 上可用的 postgres 公共镜像：
bash 1 docker pull postgres 在上面的命令中，我们拉取了 postgres 最新的稳定版镜像。 如果要指定版本的 postgres 镜像，可以使用以下命令</description>
    </item>
    <item>
      <title>探索kubectl - 巧用jsonpath提取有用数据</title>
      <link>https://www.oomkill.com/kubectl-jsonpath/</link>
      <pubDate>Mon, 25 Sep 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubectl-jsonpath/</guid>
      <description>工具命令集合 长期总结 - Linux日志查询命令 长期总结 - Linux网络命令合集 长期总结 - Linux性能分析命令 awk常用案例 bash shell常用示例 探索kubectl - 巧用jsonpath提取有用数据 探索kubectl - kubectl诊断命令集合 kubernetes集群工具 kubect 提供了一种强大的数据提取的模式，jsonpath，相对于 yaml 来说，jsonpath 拥有高度的自制提取功能，以及一些更便于提取字段的模式，使得过去 kubernetes 资源信息时更便捷，在本文中将解开 jsonpath 的神秘面纱。
什么是jsonpath JSONPath 是一种用于查询 JSON 数据结构中特定元素的查询语言。它类似于 XPath 用于 XML 数据的查询。JSONPath 允许您以一种简单而灵活的方式从 JSON 对象中提取数据，而不需要编写复杂的代码来解析 JSON 结构。
JSONPath 使用路径表达式来指定您要检索的 JSON 数据的位置。这些路径表达式类似于文件系统中的路径，但用于导航 JSON 结构。以下是一些常见的 JSONPath 表达式示例：
$：表示 JSON 根对象。 $.store：表示从根对象中获取名为 &amp;ldquo;store&amp;rdquo; 的属性。 $.store.book：表示从根对象中获取 &amp;ldquo;store&amp;rdquo; 属性中的 &amp;ldquo;book&amp;rdquo; 属性。 $.store.book[0]：表示获取 &amp;ldquo;store&amp;rdquo; 属性中的 &amp;ldquo;book&amp;rdquo; 属性的第一个元素。 $.store.book[?(@.price &amp;lt; 10)]：表示选择 &amp;ldquo;store&amp;rdquo; 属性中的 &amp;ldquo;book&amp;rdquo; 属性中价格小于 10 的所有元素。 Function Description Example Result text the plain text kind is {.</description>
    </item>
    <item>
      <title>Ceph对象存储 - windows上安装s3cmd</title>
      <link>https://www.oomkill.com/ch05-4-s3cmd-in-windows/</link>
      <pubDate>Sun, 24 Sep 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch05-4-s3cmd-in-windows/</guid>
      <description>s3cmd 是为了管理 Linux 服务器上的 S3 存储桶而创建的。 但我们也在 Windows 服务器上使用这个工具。 本文将帮助您在 Windows 系统中设置 s3cmd
Requirment s3cmd 系统要求： s3cmd 需要 Python 2.7 或更高版本才能运行，还需要安装GPG。
步骤1：安装 Python 从 python 官方网站下载并安装 python 2.7 或更高版本并安装。安装python后，将将其加到 PATH 环境变量。
步骤 2： 在 Windows 上安装 GPG Gpg4win (GNU Privacy Guard for Windows) 是一款用于数字加密 (file, email) 的免费软件，可以使用以下链接下载并安装它。
步骤3：配置 s3cmd 下载最新的 s3cmd 源代码 从s3cmd 官方页面 并解压；
提取源代码后，使用以下命令设置 s3 环境。 它会询问您的 对象存储的 AccessKey 和 SecretKey，即 GPG 命令的路径
bat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 C:s3cmd&amp;gt; python s3cmd --configure Enter new values or accept defaults in brackets with Enter.</description>
    </item>
    <item>
      <title>Ceph对象存储 - 使用s3cmd管理对象存储</title>
      <link>https://www.oomkill.com/ch05-3-s3cmd/</link>
      <pubDate>Sun, 24 Sep 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch05-3-s3cmd/</guid>
      <description>s3cmd 是一个 Amazon S3 工具，可以用于创建 s3 bucket、向对象存储中上传，检索和管理数据，在下文将如何在 Linux 上如何安装和使用 “s3cmd” 工具。
在 Linux 上安装 s3cmd s3cmd 在 Ubuntu/Debian, Fedora/CentOS/RHEL 这类发行版上的默认软件包存储库中都是可用的，只需在执行对应发行版的安装命令即可安装。
CentOS/RHEL/Fedora bash 1 2 3 4 # centos 8 $ sudo dnf install s3cmd # centos 7 $ sudo yum install s3cmd Ubuntu/Debian bash 1 sudo apt-get install s3cmd 安装最新版本 通常包管理仓库中的版本比较旧，或者使用的 Linux 没有包管理来获取最新版本的 s3cmd，那么可以使用源代码在系统上安装最新版本的 s3cmd，下载地址可以参考附录1 [1]
下面以 2.2 版本进行安装
bash 1 2 $ wget https://sourceforge.net/projects/s3tools/files/s3cmd/2.2.0/s3cmd-2.2.0.tar.gz $ tar xzf s3cmd-2.2.0.tar.gz 使用以下命令和源文件安装</description>
    </item>
    <item>
      <title>修改ingress-nginx中default backend默认状态码</title>
      <link>https://www.oomkill.com/ingress-nginx-default-backend-status-code/</link>
      <pubDate>Thu, 21 Sep 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ingress-nginx-default-backend-status-code/</guid>
      <description>什么是 default backend default backend 是 ingress-nginx 中的一个服务，主要用于处理 nginx controller 无法识别的而请求的服务
主要提供了两个接口
/healthz that returns 200 /that returns 404 如何改default backend 状态码 需求：修改 default backend 状态码 404 为 403
原理：nginx-controller 启动时指定了一个 default backend 容器，如下所示
bash 1 2 3 4 5 6 7 8 9 10 11 12 containers: - args: - /nginx-ingress-controller # 这里指的是 default-backend 的名称 {namespace_name}/{service_name} - --default-backend-service=$(POD_NAMESPACE)/ingress-nginx-ext-defaultbackend - --publish-service=$(POD_NAMESPACE)/ingress-nginx-ext-controller - --election-id=ingress-controller-leader - --ingress-class=nginx-yewu-ext - --configmap=$(POD_NAMESPACE)/ingress-nginx-ext-controller - --validating-webhook=:8443 - --validating-webhook-certificate=/usr/local/certificates/cert - --validating-webhook-key=/usr/local/certificates/key 通常情况下在通过定义配置文件方式改变是不容易做的，ingress-nginx 提供了一种自定义方式 “custom-error-pages“ 可以完成 ，完成后该 defaultBackend 支持使用 X-code方式自定义任意的错误页即错误码。</description>
    </item>
    <item>
      <title>Ceph对象存储 - 桶策略 Bucket Policy</title>
      <link>https://www.oomkill.com/ch05-2-bucket-policy/</link>
      <pubDate>Mon, 18 Sep 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch05-2-bucket-policy/</guid>
      <description>CEPH RGW 支持 Bucket 的 S3 策略语言，但又不完全类似于 S3 的策略，因为 S3 中策略是基于 AWS 的，某些属性在 CEPH 中并不存在，下面就解开 RGW 关于桶策略的配置。
Bucket Policy (桶策略，下文中统称为 BP) 是对象存储中的管理权限和对象存储访问的机制。
Policy Language 的组成 BP 的格式采用了 JSON 语言，也就是 PL 是基于 JSON 的一种策略语言，他的格式主要为几个元素
json 1 2 3 4 5 6 7 8 9 { &amp;#34;Version&amp;#34;: &amp;#34;2012-10-17&amp;#34;, &amp;#34;Statement&amp;#34;: [{ &amp;#34;Effect&amp;#34;: ..., &amp;#34;Principal&amp;#34;: ..., &amp;#34;Action&amp;#34;: ..., &amp;#34;Resource&amp;#34;: ... }] } 该结构由 ==一个== Version (表示当前版本) 和 ==一个或多个== Statement 数组组成，这些数组定义了希望应用的策略。每个语句数组中都有Effect, Principal, Action, Resource 和可选的 Condition 元素。</description>
    </item>
    <item>
      <title>kube-proxy参数ClusterCIDR做什么</title>
      <link>https://www.oomkill.com/ch26-kube-proxy-clustercidr/</link>
      <pubDate>Fri, 15 Sep 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch26-kube-proxy-clustercidr/</guid>
      <description>我们可以看到，kube-proxy 有一个 &amp;ndash;cluster-cidr 的参数，我们就来解开这个参数究竟有没有用
bash 1 2 $ kube-proxy -h|grep cidr --cluster-cidr string The CIDR range of pods in the cluster. When configured, traffic sent to a Service cluster IP from outside this range will be masqueraded and traffic sent from pods to an external LoadBalancer IP will be directed to the respective cluster IP instead 可以看到，参数说明是说，如果配置，那么从外部发往 Service Cluster IP 的流量将被伪装，从 Pod 发往外部 LB 将被直接发往对应的 cluster IP。但实际上做了什么并不知道，那么就从源码解决这个问题。
首先我们知道，参数是作为 kube-proxy server 的参数，位于 cmd/kube-proxy 下，而对应的逻辑则位于 pkg/kube-proxy 下，参数很明显，就是 clusterCIDR，那么我们就寻找这个参数的调用即可。</description>
    </item>
    <item>
      <title>ceph常用命令</title>
      <link>https://www.oomkill.com/ch11-1-ceph-common-cmd/</link>
      <pubDate>Wed, 13 Sep 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch11-1-ceph-common-cmd/</guid>
      <description>测试上传/下载对象 存取故据时，客户端必须首先连接至RAD05集群上某存储地，而后根据对像名称由相关的中CRUSH规则完成数据对象寻址。于是为了测试集群的数据存储功能，首先创建一个用于测试的存储池mypool，并设定其PG数量为16个。
sh 1 ceph osd pool create mypool 16 16 而后，即可将测试文件上传至存储池中。例如下面的rados put命令将/etc/hosts
rados
lspool 显示存储池
rmpool 删除存储池
mkpool 创建存储池
rados mkpool mypool 32 32
sh 1 2 rados mkpool {name} {pgnum} {pgpnum} rados mkpool test 32 32 sh 1 2 $ ceph osd pool create testpool 32 32 pool &amp;#39;testpool&amp;#39; created 列出存储池
text 1 2 3 4 5 6 7 8 9 $ ceph osd pool ls mypool rbdpool testpool $ rados lspools mypool rbdpool testpool 而后即可将测试文件上传到存储池中，例如将rados put命令将/etc/issue文件上传至testpool存储池，对象名称仍然较保留文件名issue，而rados ls可以列出指定存储池中的数据对象</description>
    </item>
    <item>
      <title>Ceph重新平衡 - Rebalance</title>
      <link>https://www.oomkill.com/ch6-1-ceph-rebalance/</link>
      <pubDate>Sun, 03 Sep 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch6-1-ceph-rebalance/</guid>
      <description>Rebalance 当 Ceph 集群在扩容/缩容后，Ceph会更新 Cluster map, 在更新时会更新 Cluster map 也会更新 “对象的放置” CRUSH 会平均但随机的将对象放置在现有的 OSD 之上，在 Rebalancing 时，只有少量数据进行移动而不是全部数据进行移动，直到达到 OSD 与 对象 之间的平衡，这个过程就叫做 Ceph 的 Rebalance。
需要注意的是，当集群中的 OSD 数量越多，那么在做 Rebalance 时所移动的就越少。例如，在具有 50 个 OSD 的集群中，在添加 OSD 时可能会移动 1/50th 或 2% 的数据。
如下图所示，当前集群有两个 OSD，当在集群中添加一个 OSD，使其数量达到3时，这个时候会触发 Rebalance，所移动的数量为 OSD1 上的 PG3 与 OSD2 上的 PG 6和9
图：Ceph Rebalancing 示意图 Source：https://access.redhat.com/documentation/zh-cn/red_hat_ceph_storage/4/html/architecture_guide/ceph-rebalancing-and-recovery_arch
Balancer 执行 Rebalance 的模块时 Balancer，其可以优化 OSD 上的放置组 (PG) ，以实现平衡分配。
可以通过命令查看 balancer 的状态
bash 1 ceph balancer status https://docs.</description>
    </item>
    <item>
      <title>深入理解kubelet - VolumeManager源码解析</title>
      <link>https://www.oomkill.com/ch29-volumemanager/</link>
      <pubDate>Sun, 20 Aug 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch29-volumemanager/</guid>
      <description>Overview 阅读完本文，您当了解
Kubernetes 卷 CephFS 在 kubernetes 中的挂载 Kubelet VolumeManager 本文只是个人理解，如果有大佬觉得不是这样的可以留言一起讨论，参考源码版本为 1.18.20，与高版本相差不大
VolumeManager VolumeManager VM 是在 kubelet 启动时被初始化的一个异步进程，主要是维护 “Pod&amp;quot; 卷的两个状态，”desiredStateOfWorld“ 和 ”actualStateOfWorld“； 这两个状态用于将节点上的卷 “协调” 到所需的状态。
VM 实际上包含三个 “异步进程” (goroutine)，其中有一个 reconciler 就是用于协调与挂载的，下面就来阐述 VM 的挂载过程。
VM中的重要组件 actualStateOfWorld mountedPod desiredStateOfWorld VolumeToMount podToMount VM的组成 VM 的代码位于，由图可以看出，主要包含三个重要部分：
reconciler：协调器 populator：填充器 cache：包含 ”desiredStateOfWorld“ 和 ”actualStateOfWorld“ 图：VM的目录组成 在代码结构上，volumeManager 如下所示
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 // volumeManager implements the VolumeManager interface type volumeManager struct { // DesiredStateOfWorldPopulator 用来与 API 服务器通信以获取 PV 和 PVC 对象的 API 客户端 kubeClient clientset.</description>
    </item>
    <item>
      <title>记录kubernetes node label的面板实施</title>
      <link>https://www.oomkill.com/kubernetes-node-label-dashboard/</link>
      <pubDate>Sat, 19 Aug 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-node-label-dashboard/</guid>
      <description>背景 目前的 Kubernetes 集群资源面板是基于集群的使用资源，因为是多集群，业务同时运行字啊不同集群上，如果通过 label 来划分业务使用的资源情况，这个才是真的和每个集群的每个业务使用的资源有关。
对于这种场景的划分，Kubernetes 中有一个专门的名词是 Pod 的拓扑域；基于这些需要做的事情就如下步骤
首先确定node label可以搜集到，如果不存在需要收集 当收集到node label 时，需要根据对应的 label 将一个域中的 根据域（label）做变量注入到 对应的查询语句中以生成图表 收集 node label 在使用 kube-prometheus-stack 中收集 kubernetes 的 node label 需要手动启动参数 - --metric-labels-allowlist=nodes=[*] 才可以收集到 node label，手动给Node 打上标签，test 拓扑域 为 aaaa bbbb两个
在 helm 中直接增加如下：
bash 1 - nodes=[*] 查看 label
bash 1 2 3 4 $ kubectl get node --show-labels NAME STATUS ROLES AGE VERSION LABELS node01 Ready &amp;lt;none&amp;gt; 13d v1.16.10 beta.</description>
    </item>
    <item>
      <title>存储概念 - 存储类型对比</title>
      <link>https://www.oomkill.com/acquaintance-stroage/</link>
      <pubDate>Tue, 15 Aug 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/acquaintance-stroage/</guid>
      <description>存储选择需要考虑的问题：不同的文件访问方式? 在关注存储之前，需要关注下面一些问题：
“应用” 访问数据的方式是什么？
一次读取 或 分块读取 一个连续的“流”传输最好的方式是什么 有序的 或 随机的 “数据的类型是什么”？
数据库，Text，视频/音频，图像&amp;hellip; 静态 / 固定 / 动态 是否需要数据共享？
由应用共享 / 由存储共享 读 / 写 共享方面关注的问题？
Narrow (只需要更新部分内容，这可以共享特定部分内容，这将不是一个广泛共享) / Broad 安全和访问控制：
应用什么级别的的安全性？ 访问性会影响存储的选择：
Local / Network 介质：光纤，以太网，SAS，SATA，PCIe&amp;hellip; 有了这些问题，就可以引入存储的类型，以便选择最佳的存储（Balance performance and cost ）
DAS Direct Attached Storage (DAS) 直接附加存储是指，直接连接到服务器存储系统，通俗来讲就是直接连接磁盘，服务器与存储系统之间“没有经过网络设备” (如交换机等)，服务器与存储直接由专用的“连接技术”进行连接，如 SCSI, 但现在更常见的是 “eSATA”, “SAS”, 或 “光纤通道”。
图：DAS结构图 Source：https://www.pcmag.com/encyclopedia/term/direct-attached-storage
图：DAS接口类型 Source：https://ramsaihan.wordpress.com/2017/10/16/the-sas-sata-scsi-and-ata-in-storage-and-peripheral-communication/
外部连接 直连存储也可以通过连接电缆从服务器连接到存储设备，但服务器中必须存在 SAS、以太网或 FC 控制器，只有该服务器可以使用外部磁盘空间。因此直连存储也可以作为是服务器的扩展
SAS 作为连接介质价格低廉，但距离仅限于几米（最大 5 或 10 米，具体取决于制造商）；光纤通道的传输距离可达数公里，因此也可用作灾备系统。</description>
    </item>
    <item>
      <title>picgo &#43; github 给typora做图床</title>
      <link>https://www.oomkill.com/github-and-picgo-img-beg/</link>
      <pubDate>Tue, 08 Aug 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/github-and-picgo-img-beg/</guid>
      <description>在配置好 github 仓库后，需要将对应的信息填写在 picgo 中，可以按照如下进行配置
仓库名：xxxx/xxx 无需写 github.com/xxx/xxx
分支名：直接填写分支名即可
Token：在 github 上面配置的仓库 token
设定存储路径：这里填写 github 仓库上传到的路径
设置自定义域名：https://cdn.jsdelivr.net/gh/&amp;lt;github_username&amp;gt;@&amp;lt;branch_name&amp;gt;/&amp;lt;repo_name&amp;gt;/&amp;lt;path&amp;gt;
例如：https://cdn.jsdelivr.net/gh/cylonchau/blogs@img/img/image-20241129232645456.png</description>
    </item>
    <item>
      <title>使用cephadm纯离线安装Ceph集群</title>
      <link>https://www.oomkill.com/ch02-1-install-ceph-with-cephadm-part1/</link>
      <pubDate>Sun, 30 Jul 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch02-1-install-ceph-with-cephadm-part1/</guid>
      <description>本文是Ceph集群部署系列第1章 使用cephadm纯离线安装Ceph集群 使用cephadm纯离线安装Ceph集群 2 Ceph集群安装 - ceph-deploy Ceph集群安装 - ceph-deploy下线rgw 开篇常例 - 概述 Ceph 是一个广泛使用的开源存储平台。 它提供高性能、可靠性和可扩展性。 Ceph 分布式存储系统提供了对象存储、块存储和文件级存储。 Ceph 旨在提供无单点故障的分布式存储系统。
在本教程中，将通过 ceph-adm 方式在 CentOS 7 上安装和构建 Ceph 集群。该实验的 Ceph 集群需要以下 Ceph 组件：
Ceph OSD (ceph-osd) - 处理数据存储、数据复制和恢复；通常一个Ceph集群至少需要两台 OSD 服务器 。 Ceph Monitor (ceph-mon) - 监视集群状态、OSD 映射和 CRUSH 映射，我们在这里与 cephadm 或 OSD 公用一个节点 Ceph 元数据服务器 (ceph-mds) - 这是使用 CephFS 所需的组件。 有了上面的条件，我们实验环境所需要的节点如下：
三台服务器节点，CentOS 7 注：CentOS 7 可安装最高级别的 ceph 版本就是 O 版</description>
    </item>
    <item>
      <title>使用cephadm纯离线安装Ceph集群2</title>
      <link>https://www.oomkill.com/ch02-2-install-ceph-with-cephadm-part2/</link>
      <pubDate>Sun, 30 Jul 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch02-2-install-ceph-with-cephadm-part2/</guid>
      <description>本文是Ceph集群部署系列第2章 使用cephadm纯离线安装Ceph集群 使用cephadm纯离线安装Ceph集群 2 Ceph集群安装 - ceph-deploy Ceph集群安装 - ceph-deploy下线rgw 离线安装 - ceph-mds ceph-mds (metadata server daemon) 是 cephfs 功能中所需要的组件，是用于收集和管理文件系统名称空间，协调和共享 OSD 集群的组件。
cephadm 部署集群所有组件都打包在 ceph 镜像内，只需要修改一遍就可以全局离线安装了 要部署 cephfs 就需要有一个或多个 ceph-mds
使用 cephadm 部署 mds bash 1 2 ceph orch apply mds *&amp;lt;fs-name&amp;gt;* --placement=&amp;#34;*&amp;lt;num-daemons&amp;gt;* [*&amp;lt;host1&amp;gt;* ...]&amp;#34; ceph orch apply mds kubernetes01 --placement=&amp;#34;hostname01,hostname02,hostname03&amp;#34; 删除 mds bash 1 2 ceph config set mon mon_allow_pool_delete true ceph fs volume rm kubernetes01 --yes-i-really-mean-it 离线安装 - Ceph Object Gateway Ceph 从 0.</description>
    </item>
    <item>
      <title>在 Kubernetes 集群中使用 blackbox exporter监控外部IP</title>
      <link>https://www.oomkill.com/blackbox_exporter-in-k8s/</link>
      <pubDate>Wed, 12 Jul 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/blackbox_exporter-in-k8s/</guid>
      <description>背景 在云原生环境中，特别是基于 Kubernetes，集群中的 “服务” 在与外部交互时，例如，一个外部的第三方 Web 服务/API 等，而监控这些不同的 endpoint 诊断服务可用性的一个关键点，这里将阐述基于 Kube-prometheus-stacks 如果做到可以监控外部 IP/URL，例如，HTTP/TCP/ICMP 等。
blackbox_exporter 是 Prometheus 官方维护的 exporter之一，是提供一种用于检测 HTTP/S、DNS、TCP 和 ICMP 端点的可用性。
基于 kube-prometheus-stack 安装 blackbox 本文使用了 helm 安装的 prometheus-community/prometheus-blackbox-exporter ，在安装前，需要自行修改要启动的 prober，与是否开启默认的 servicemonitor
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 secretConfig: false config: modules: ping: prober: icmp timeout: 5s icmp: preferred_ip_protocol: &amp;#34;ip4&amp;#34; http_2xx: prober: http timeout: 5s http: valid_http_versions: [&amp;#34;HTTP/1.1&amp;#34;, &amp;#34;HTTP/2.</description>
    </item>
    <item>
      <title>无互联网环境下安装Spinnaker - Offline Install Spinnaker</title>
      <link>https://www.oomkill.com/offline-installtation/</link>
      <pubDate>Mon, 10 Jul 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/offline-installtation/</guid>
      <description>Prerequisites 具有一个 Kubernetes 集群 以部署 Spinnaker 可运行 Docker 的环境 (1 vCPU, 3.75 GB) 或者是 Ubuntu，用以安装 Halyard (用于 spinnaker 的服务) 对象存储 (MinIO)，用于持久化 Spinnaker 的数据 对象存储的 Bucket 的访问账号 安装执行步骤 安装 Halyard 可以直接使用 Docker 方式安装，这个没什么必要性，就是管理工具而已，参考附录1 [1]
首先创建映射目录
bash 1 2 mkdir ~/.hal -pv mkdir ~/.kubeconfig -pv 然后执行 docker run 运行容器
bash 1 2 3 4 5 6 7 docker run -d -p 8084:8084 -p 9000:9000 \ --name halyard --rm \ -v ~/.hal:/home/spinnaker/.hal \ -v ~/.</description>
    </item>
    <item>
      <title>使用Thanos强化Prometheus</title>
      <link>https://www.oomkill.com/using-thanos-improve-prometheus.md/</link>
      <pubDate>Sun, 02 Jul 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/using-thanos-improve-prometheus.md/</guid>
      <description>背景 Prometheus 是目前云原生架构中监控解决方案中的基石，而对于 “metrics”，“traces” 和 “logs” 是组成云原生架构中“可观测性”的一个基础，当在扩展 Prometheus，那么 Prometheus 提供的基础架构是无法满足需求的（高可用性和可扩展性）， 而高可用性与可扩展性是满足不断增长基础设施的一个基本条件。而 Prometheus 本身并没有提供“弹性”的集群配置，也就是说，多个副本的 Prometheus 实例，对于分布在每个 Pod 上的数据也会不一致，这时也需要保证指标的归档问题。
并且在一定的集群规模下，问题的出现远远大于 Prometheus 本身的能力，例如：
如何经济且搞笑的存储历史数据（TB, PB）？如何快速的查询历史数据？ 如何合并 Promehtues 多个实例收集来的副本数据？ 以及多集群间的监控？ 由于 TSDB 的块同步，Prometheus 严重依赖内存，使得 Prometheus 监控项的扩展将导致集群中的CPU/MEM 的使用加大 .. 解决 Thanos 是一款可以使 Prometheus 获得 ”长期存储“，并具体有”高可用性“ 的 Prometheus 的功能扩展，“Thanos” 源自希腊语“ Athanasios”，英文意思是”不朽“。这也正是 ”Thanos“ 提供的功能：”无限制的对象存储“，并与原生 Prometheus API 高度兼容，你可以理解为 Thanos API 就是 Prometheus API。
Cortexmetrics 与 Thanos 类似，是用通过将 Prometheus 实例的”存储“和”查询“等功能分离到独立的组件中，实现水平扩展。它使用对象存储来持久化历史指标，块存储（TSDB）是他的存储后端；此外，Cortex 还提供了多租户与多租户隔离等功能
联邦集群，联邦集群是 Prometheus 官方提供的一个概念，使用了联邦将允许 Prometheus 从另一个 Prometheus 中抓取选定的指标。可以使用的一些模型如下：
分层联邦：大规模的集群中，Prometheus 部署模型如一个”树形“，高级别的从多个低级实例中抓取指标，并存储聚合 跨服务联邦：Prometheus 从另一个 Prometheus 只抓取指定的数据 图：Prometheus 联邦 Source：https://www.</description>
    </item>
    <item>
      <title>Spinnaker接入keycloak认证</title>
      <link>https://www.oomkill.com/spinnaker-auth-with-keycloak/</link>
      <pubDate>Wed, 21 Jun 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/spinnaker-auth-with-keycloak/</guid>
      <description>Spinnaker的认证 spinnaker 中提供了认证 ( Authentication) 的机制流为 Deck &amp;lt;=&amp;gt; Gate &amp;lt;=&amp;gt; Identity Provider
Deck 是 spinnaker 的 WEB UI (由 apache server服务的一组静态文件) Gate 是 API Gateway，所有的进入 Spinnaker 的流量都会通过 Gate 处理，这里完成 authentication 和 authorization。 Identity Provider：用于用户身份认证的外部服务或系统，例如 LDAP, OAuth 2.0(行业标准鉴权协议), SAML, X.509 等。 更多 spinnaker Authentication 工作流可以参考
Spinnaker 认证配置 启动配置
bash 1 hal config security authn oauth2 enable --no-validate 使用 hal 命令配置 redirect URI
bash 1 hal config security authn oauth2 edit --pre-established-redirect-uri https://my-real-gate-address.</description>
    </item>
    <item>
      <title>在Kubernetes集群上安装 Calico cni 的注意事项</title>
      <link>https://www.oomkill.com/calico-cni-deplyment/</link>
      <pubDate>Wed, 21 Jun 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/calico-cni-deplyment/</guid>
      <description>开始前的实验环境 Resources controller worker-1 worker-2 OS CentOS 7.9 CentOS 7.9 CentOS 7.9 Storage 20GB 20GB 20GB vCPU 2 2 2 RAM 4GB 4GB 4GB NIC 10.0.0.4 10.0.0.4 10.0.0.4 Kubernetes Version 1.19.10 1.19.10 1.19.10 选择匹配 Kubernetes 版本的 Calico 版本 通常情况下，查看 Calico 所支持的 Kubernetes 版本，可以通过路径 Install Calico ==&amp;gt; Kubernetes ==&amp;gt; System requirements 可以找到自己的 Kubernetes 集群所支持的 Calico 版本。
例如在实验环境中，Kubernetes 1.19 版本所支持的版本有 Calico 3.20，这个时候直接 apply 这个版本提供的资源清单即可
如何开启纯 BGP 模式 默认情况下下，Calico 使用的是 full mesh 和 IPIP， 如果想通过在部署时就修改关闭 IPIP 模式，可以通过修改资源清单中的环境变量来关闭 CALICO_IPV4POOL_IPIP: Never。</description>
    </item>
    <item>
      <title>Spinnaker template</title>
      <link>https://www.oomkill.com/spinnaker-template/</link>
      <pubDate>Tue, 20 Jun 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/spinnaker-template/</guid>
      <description>spinnaker 的模板是通过 spin 命令行去创建的，spin 是 spinnaker 的套件，可以使用 spin 获取到存在的pipeline与 template，还可以创建一个新的模板或者替换就得；cli获取到的数据是 json 类型
配置spin bash 1 2 3 4 5 6 7 mkdir ~/spin # Inside the dir, setup ‘config’ file using the sample # https://github.com/spinnaker/spin/blob/master/config/example.yaml #Sample ~/.spin/config gate: endpoint: http://demospin.net:9000/gateauth: enabled: false spin 配置文件 spin 默认从 ~/spin/config 读取配置，可以通过 &amp;ndash;config 指定 spin 的配置文件。下面是一个官方给的一个 spin config 的 example，在配置时只需要选择一个认证方式即可 iap/x.509/oauth2 这个选择的是 oauth2
json 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 # NOTE: Copy this file to ~/.</description>
    </item>
    <item>
      <title>Kubernetes中的资源限制 - Request&amp;Limit</title>
      <link>https://www.oomkill.com/kubernetes-limit-request/</link>
      <pubDate>Sat, 17 Jun 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-limit-request/</guid>
      <description>原作者 Javier Martínez
背景 在学习 Kubernetes 调度时，有两个重要的概念，&amp;ldquo;request &amp;ldquo;与 &amp;ldquo;limit&amp;rdquo;，而对应的资源就是“内存” 与 “CPU” ，而这两个决定了 Pod 将如何调度；&amp;ldquo;request &amp;ldquo;与 &amp;ldquo;limit&amp;rdquo; 也是整个调度系统中的基数因子。
什么是 request 和 limit 在 Kubernetes 中，Limit 是容器可以使用的最大资源量，这表示 “容器” 的内存或 CPU 的使用，永远不会超过 Limit 配置的值。
而另一方面，Request 则是为 “容器” 保留的最低资源保障；换句话来说，Request 则是在调度时，容器被允许所需的配置。
图：Kubernetes 中Limit 和 Request 图示 Source：https://sysdig.com/blog/kubernetes-limits-requests/ 如何配置 request 和 limit 下列清单是 Deployment 的部署清单，他将部署一个 redis 与 一个 busybox
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 kind: Deployment apiVersion: extensions/v1beta1 … template: spec: containers: - name: redis image: redis:5.</description>
    </item>
    <item>
      <title>我在Prometheus监控中高基数问题中的优化之路</title>
      <link>https://www.oomkill.com/impove-prometheus-performance/</link>
      <pubDate>Wed, 14 Jun 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/impove-prometheus-performance/</guid>
      <description>背景 对于整个 Kubernetes 集群来说，随着业务不断地打磨，新增指标，那么对于 Prometheus 特性来说，那么内存 与 存储的使用势必是增加。这是对于存储压力是很重的，通常情况下，使用 Prometheus，都会是用于 Kubernetes 集群中，而 应用于 Kubernetes 集中的存储势必是 PVC 之类的网络存储。
这种场景中，我将尝试拆解如何分析和配置 Prometheus 以显著的减少其资源使用并解决高基数问题
高基数 基数 (cardinality) 通俗来说是一个集合中的元素数量 [1] 基数的来源通常为：
label 的数量 series(指标) 的数量 时间：label 或者 series 随时间而流失或增加，通常是增加 那么这么看来高基数就是，label, series, 时间这三个集合的笛卡尔积，那么高基数的情况就很正常了。
而高基数带来的则是 Prometheus 资源使用，以及监控的性能。下图是 Grafana Lab 提到的一张图，很好的阐述了高基数这个问题
图：Prometheus中的基数 Source：https://grafana.com/blog/2022/02/15/what-are-cardinality-spikes-and-why-do-they-matter
如图所示：一个指标 server_responses 他的 label 存在两个 status_code 与 environment ，这代表了一个集合，那他的 label value 是 1~5xx，这个指标的笛卡尔积就是10。
那么此时存在一个问题，如何能定位 基数高不高，Grafana Lab 给出了下面的数据 [1]，但是我不清楚具体的来源或者如何得到的这些值。也就是 label:value
低基数：1: 5 标准基数：1: 80 高基数：1: 10000 为什么指标会指数级增长 在以 Kubernetes 为基础的架构中，随着抽象级别的提高（通常为Pod, Label, 以及更多抽象的拓扑），指标的时间序列也越来越多。因为在这种基础架构中，在传统架构中运行的一个应用的单个裸机，被许多运行分散在许多不同节点上的许多不同微服务的 Pod 所取代。在这些抽象层中的每一个都需要一个标签，以便可以唯一地标识它们，并且这些组件中的每一个都会生成自己的指标，从而创建其独特的时间序列集。</description>
    </item>
    <item>
      <title>踩坑nginx proxy_pass GET 参数传递</title>
      <link>https://www.oomkill.com/nginx-proxy_pass/</link>
      <pubDate>Sat, 20 May 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/nginx-proxy_pass/</guid>
      <description>场景 在配置代理后，GET 请求的变量全部失效，配置如下
text 1 2 3 location /fw { proxy_pass http://127.0.0.1:2952; } 我的需求是，/fw/ 的都发往 2952端口，但实际情况是404，原因为“在没有指定 URI 的情况下，在1.12版本后会传递原有的URI” 这时会导致一个404错误，因为我的后端接口本身就是 /fw/xxx/ 会出现重复
接下来做了一个变量传递
text 1 2 3 location ~* /fw/(?&amp;lt;section&amp;gt;.*) { proxy_pass http://127.0.0.1:2952/fw/$section; } 这时存在一个问题，就是 GET 请求的变量无法传递过去
解决 nginx 官方给出一个样例，说明了，存在某种情况下，nginx 不会确定请求 URI 中的部分参数
使用正则表达式时 在 localtion 名称内 例如，在这个场景下，proxy_pass 就会忽略原有的请求的URI，而将拼接后的请求转发
text 1 2 3 4 location /name/ { rewrite /name/([^/]+) /users?name=$1 break; proxy_pass http://127.0.0.1; } 那么这服务我遇到的问题，nginx官方给出了使用方式
当在 proxy_pass 中需要变量，可以使用 $request_uri;
另外也可以使用 $is_args$args 参数 来保证原有的请求参数被传递</description>
    </item>
    <item>
      <title>Docker中的多进程管理 s6-overlay</title>
      <link>https://www.oomkill.com/multi-process-management/</link>
      <pubDate>Thu, 18 May 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/multi-process-management/</guid>
      <description>什么是容器中的多进程管理 在容器中的主进程 (main running process) 是指 Dockerfile中 ENTRYPOINT 或 CMD 指定运行的命令，通常情况下一个进程（服务）为一个容器；也存在一种场景，就是主进程会fork多个子进程，例如nginx，不过这种多进程通常为nginx主进程进行管理。而一些场景下，我们的业务本身就需要多个启用独立的多个进程。
在Docker官方提到了在容器中运行多个服务的方式，官方提出，应该避免这种情况
but to get the most benefit out of Docker, avoid one container being responsible for multiple aspects of your overall application.
但也给出了如何管理多进程的一种思路，
Use a wrapper script Use Bash job controls Use a process manager 下面就通过官方给出的这三种方式阐述容器中的多进程管理
Use a wrapper script 对于使用脚本来管理多进程来说，本质上是可以实现多进程的启动，但是你没法去监控(管理)多个进程的运行时，例如 Nginx + PHP 模式， PHP或nginx全部挂掉，只要脚本还在运行，那么这个容器的生命周期还是处于Running
Use Bash job controls 这种模式是利用了Bash的后台模式进行短暂的切换进程，但有些镜像不提供Bash这时应该怎么办
Use a process manager 进程管理器，通常情况下大家想到的就是顶顶大名的 supervisor 和 systemd，但这两个程序运行的环境十分苛刻，例如 supervisor 是Python开发的程序，运行需要依赖 Python；而 systemd 的运行条件更为苛刻，例如需要额外运行dbus-damon进行注册到dbus总线之上，这种进程管理器可能运行的进程比我们要管理的进程都要多。在这种场景下，有一个部署简单，配置简单，无依赖的轻量级容器多进程管理器 s6-overlay</description>
    </item>
    <item>
      <title>StackStorm自动化 - 包配置</title>
      <link>https://www.oomkill.com/stackstorm-pack-configuaration/</link>
      <pubDate>Thu, 18 May 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/stackstorm-pack-configuaration/</guid>
      <description>基本概念 从版本 2.4 开始，如果包包含.config.yaml ，可以使用包配置，包配置可以使用配置文件来设置包中资源通用的值，例如 API 凭证、连接详细信息、限制和阈值。这些值在运行时可供操作和传感器使用。
包配置和 Action 参数之间的区别在于，配置通常包含包中所有资源通用的值，并且很少更改。动作参数是随每个动作调用动态提供的，并且可能会发生变化 - 例如，它们可能来自映射某些输入事件的规则。
包配置遵循基础架构即代码方法，并存储在特殊目录中的 YAML 格式文件中（默认情况下 /opt/stackstorm/configs）。每个包都为此配置文件定义自己的架构。
配置 Schema 配置文件的结构是一个 YAML 格式的文件，它定义了该包的配置文件。该配置由包作者自行编写，包含有关每个可用配置项的信息，例如名称, Secret等）。该文件已命名 config.schema.yaml 并位于包目录 /opt/stackstorm/packs/&amp;lt;mypack&amp;gt; 的根目录中。
这是一个示例包配置文件：
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 --- api_key: description: &amp;#34;API key&amp;#34; type: &amp;#34;string&amp;#34; required: true api_secret: description: &amp;#34;API secret&amp;#34; type: &amp;#34;string&amp;#34; secret: true required: true region: description: &amp;#34;API region to use&amp;#34; type: &amp;#34;string&amp;#34; required: true default: &amp;#34;us-east-1&amp;#34; private_key_path: description: &amp;#34;Path to the private key file to use&amp;#34; type: &amp;#34;string&amp;#34; required: false 在该示例中，配置文件由 4 项 配置组成 (api_key, api_secret, region, private_key_path)</description>
    </item>
    <item>
      <title>解决nginx在docker中报错 [rewrite or internal redirection cycle while internally redirecting to &#34;/index.html]</title>
      <link>https://www.oomkill.com/ngx-in-docker-500/</link>
      <pubDate>Thu, 18 May 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ngx-in-docker-500/</guid>
      <description>vue项目部署在裸机Linux上运行正常，部署在docker中nginx出现下列错误
text 1 Nginx &amp;#34;rewrite or internal redirection cycle while internally redirecting to &amp;#34;/index.html&amp;#34; 表现在用户界面 500 Internal Server Error
原因：nginx配置路径不对，改成正确的后恢复</description>
    </item>
    <item>
      <title>Awesome kubernetes</title>
      <link>https://www.oomkill.com/awesome-kubernetes/</link>
      <pubDate>Wed, 03 May 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/awesome-kubernetes/</guid>
      <description>Deployment Recommended Cluster Architecture - rancher Hardware recommendations - etcd A simple shell script for backing up etcd v2 and v3 datastores Considerations for large clusters - kubernetes cluster Operating etcd clusters for Kubernetes Recommended performance and scalability practices Binary deploy script pure shell Managing Kubernetes Traffic with F5 NGINX Eraser - Cleaning up Images from Kubernetes Nodes 对于不同规模的 Kubernetes 集群所需要的 etcd 规模推荐 datree: allowing you to scan your k8s configs during development Performance etcd: getting 30% more write/s 蚂蚁集团万级规模 K8s 集群 etcd 高可用建设之路 各组件参数配置调优 万级K8s集群背后etcd稳定性及性能优化实践 K8s 集群稳定性：LIST 请求源码分析、性能评估与大规模基础服务部署调优 Comparing comparing Kubernetes ingress controller Troubleshooting 一次Etcd集群宕机引发的思考 Stern: allows you to tail multiple pods on Kubernetes Diagnosis Kubernetes 自动化诊断工具：k8sgpt-operator ktop: displays useful metrics information about kubernetes cluster Dashboard KDash - A fast and simple dashboard for Kubernetes Security Kubernetes 加固指南 Popeye 扫描实时 Kubernetes 集群并报告已部署资源和配置的潜在问题 Test kube-monkey It randomly deletes Kubernetes (k8s) pods in the cluster encouraging and validating the development of failure-resilient services.</description>
    </item>
    <item>
      <title>firewalld去除polkit验证</title>
      <link>https://www.oomkill.com/firewalld-without-polkit/</link>
      <pubDate>Wed, 19 Apr 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/firewalld-without-polkit/</guid>
      <description>为什么去除polkit验证 在2021年询问过firewalld项目组，firewalld在dbus通讯时，会进行两部认证 policy kit 和 UID checking，正是因为这种情况，使得firewalld不能够通过TCP/IP连接，如果你需要连接，因为存在 UID checking ，这时会因为没有UID会报错。
firewalld needs to do some authorization on the dbus request. It currently tries two ways, in order of preference:
policy kit UID checking Neither of these are available over a TCP/IP dbus connection. [1]
如何去除polkit 首选需要确定你的firewalld版本，例如Centos7系列，那么你的 firewalld 版本为 0.6.3，那么你需要修改的包为 python-firewall-0.6.3, 在 debian11 上 firewalld版本默认为 0.9.3，那么需要关注的版本为：python3-firewall_0.9.3
在确定版本后直接从github仓库进行拉去修改就可以
bash 1 2 git fetch v0.9.3 git checkout v0.9.3 对于 python-firewall-0.6.3 来说。直接注释掉 slip.dbus.polkit.require_auth 就可以了</description>
    </item>
    <item>
      <title>删除github上面的历史提交记录</title>
      <link>https://www.oomkill.com/delete-github-commit/</link>
      <pubDate>Sun, 02 Apr 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/delete-github-commit/</guid>
      <description>如果不小心提交github提交错了，而 --amend 也不能修改提交者的信息，可以通过尝试下面的方式
Checkout
bash 1 git checkout --orphan &amp;lt;latest_branch&amp;gt; Add all the files
bash 1 git add -A Commit the changes
bash 1 git commit -am &amp;#34;commit message&amp;#34; Delete the branch
bash 1 git branch -D main Rename the current branch to main
bash 1 git branch -m main Finally, force update your repository
bash 1 git push -f origin main 缺点是：所有该分支的提交记录都将被删除
Reference
how to delete all commit history in github?</description>
    </item>
    <item>
      <title>Unix归档模式Unix ar - 深入剖析与构建deb包</title>
      <link>https://www.oomkill.com/deb-package/</link>
      <pubDate>Wed, 29 Mar 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/deb-package/</guid>
      <description>deb 概述 deb包（.deb）是 Debian 和基于 Debian衍生操作系统（如Ubuntu）中使用的一种软件包的格式。deb是一种基于 Unix ar [3] (Unix archiver) 的归档文件。其中包含二进制文件、配置文件和其他软件所需的资源。deb包可用于安装、升级和卸载软件包。通常，Debian操作系统的用户使用apt（Advanced Package Tool）等软件包管理器工具来管理deb包。通过这些工具，用户可以轻松下载、安装和管理软件包，而无需手动编译、安装和解决软件包之间的依赖关系。
deb VS rpm 包的归档格式不同：deb是基于 ar 的归档模式，而RPM是基于 cpio 的归档模式 包的结构不同：deb包要求必须包含一个 DEBIAN 目录；而RPM不需要以来额外的目录结构 包的依赖机制不同： Deb使用epoch，而RPM使用build number：在Deb中，epoch是一个可选的字段，它允许呈现基准日期之前的先前版本。而在RPM中，build number表示软件包编译的次数。因此，在Deb中，为了解决版本控制问题，epoch是非常重要的，而在RPM中，则更关注build number。 Deb使用逆向依赖关系，而RPM使用依赖关系：在Deb中，依赖项是从包本身向外扩展，在解决依赖问题时可以通过逆向依赖关系进行。而在RPM中，则更喜欢使用依赖关系直接指向其他包。 Deb允许代理软件包，而RPM则不允许代理软件包：Deb中，软件包可以使用另一种软件包的代理来提供功能。在RPM中，软件包需要直接引用相关的软件包。这意味着在Deb中，对于版本控制，可以用另一种代理软件包来解决问题，而在RPM中必须直接引用包。 Deb允许多重依赖关系，RPM则不允许：Deb允许使用多个依赖项列表，以便包与不同版本的库兼容。在RPM中，需要在每个包中定义依赖项和其版本，不能使用多重依赖。 deb包的分析 deb包的结构 deb 最重要的是 控制文件 Control ，该文件记录了deb包与其安装的程序的信息。
在deb包内部包含一组模拟 Linux 文件系统的文件夹，例如 /usr, /usr/bin, /opt等等。 放置在其中一个目录中的文件将在安装期间复制到实际文件系统中的相同位置。 因此，例如将二进制文件放入 &amp;lt;.deb&amp;gt;/usr/local/bin/binaryfile 将被安装到 /usr/local/bin/binaryfile.
对于deb 包的命名是遵循着一个特定的格式：
text 1 &amp;lt;name&amp;gt;_&amp;lt;version&amp;gt;-&amp;lt;revision&amp;gt;_&amp;lt;architecture&amp;gt;.deb &amp;lt;name&amp;gt; 构建的deb包名称，如nginx &amp;lt;version&amp;gt; 程序的版本号 ，如1.20 &amp;lt;revision&amp;gt; 当前 deb 包的版本号 &amp;lt;architecture&amp;gt; 表示构建出的包的操作系统架构，如，amd64、i386 如果你构建一个nginx-1.20的arm操作系统下的，那么deb包名格式则为 nginx_1.20-1_arm64.deb
control文件 [2] Deb软件包（.</description>
    </item>
    <item>
      <title>alpine安装网络工具</title>
      <link>https://www.oomkill.com/alpine-network-tools/</link>
      <pubDate>Wed, 22 Mar 2023 23:00:36 +0800</pubDate>
      <guid>https://www.oomkill.com/alpine-network-tools/</guid>
      <description> telnet：busybox-extras net-tools: net-tools tcpdump: tcpdump wget: wget dig nslookup: bind-tools curl: curl nmap: nmap wget ifconfig nc traceroute.. : busybox ssh: openssh-client ss iptables: iproute2 ethtool: ethtool yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 FROM alpine MAINTAINER RUN sed -i &amp;#39;s@http://dl-cdn.alpinelinux.org/@https://mirrors.aliyun.com/@g&amp;#39; /etc/apk/repositories RUN apk add --no-cache --virtual .persistent-deps \ curl \ tcpdump \ iproute2 \ bind-tools \ ethtool \ busybox-extras \ libressl \ openssh-client \ busybox CMD [ &amp;#34;tail&amp;#34;, &amp;#34;-f&amp;#34; ] </description>
    </item>
    <item>
      <title>Linux Dbus中的ACL策略</title>
      <link>https://www.oomkill.com/dbus-security-policy/</link>
      <pubDate>Wed, 22 Mar 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/dbus-security-policy/</guid>
      <description>D-Bus 是 Linux 系统中的一种通信机制，用于在进程之间进行通信。D-Bus 配置文件则是一种用于配置 D-Bus 的文件，其中包含有关系统总线 (system bus)，会话总线 (session bus) 和各种系统服务的详细信息。
本文将解析 D-Bus 配置文件，侧重点则为权限的配置
配置文件的基本结构 D-Bus 配置文件使用 XML 格式进行编写，具有以下基本结构：
xml 1 2 3 4 5 6 7 8 9 10 11 12 &amp;lt;!DOCTYPE busconfig PUBLIC &amp;#34;-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN&amp;#34; &amp;#34;http://www.freedesktop.org/standards/D-Bus/1.0/busconfig.dtd&amp;#34;&amp;gt; &amp;lt;busconfig&amp;gt; &amp;lt;policy group=&amp;#34;wheel&amp;#34;&amp;gt; &amp;lt;!-- policy rules go here --&amp;gt; &amp;lt;/policy&amp;gt; &amp;lt;policy context=&amp;#34;default&amp;#34;&amp;gt; &amp;lt;!-- policy rules go here --&amp;gt; &amp;lt;/policy&amp;gt; &amp;lt;include filename=&amp;#34;other-config.xml&amp;#34;/&amp;gt; &amp;lt;listen&amp;gt;unix:path=/var/run/D-Bus/system_bus_socket&amp;lt;/listen&amp;gt; &amp;lt;/busconfig&amp;gt; 什么是D-Bus Policy？ D-Bus Policy是D-Bus配置文件中最重要的字段之一，用于定义D-Bus服务的访问控制策略。D-Bus Policy包含了一组规则，用于限制D-Bus服务的使用者对D-Bus服务的访问，确保D-Bus服务的安全性。</description>
    </item>
    <item>
      <title>Go设计模式</title>
      <link>https://www.oomkill.com/design-patterns/</link>
      <pubDate>Fri, 10 Mar 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/design-patterns/</guid>
      <description>创建型模式 工厂模式 概念说明 工厂模式 (factory pattern) 是在父类中提供一个创建对象的方法，是用于创建不同类型的对象，而无需指定对象的真实的类
工厂模式的特点：
对客户端隐藏对象创建的复杂逻辑 可以通过修改工厂类来创建对象而不影响客户端代码 提供创建对象的单一来源。 单个工厂类用以各组件保持一致性。 允许子类创建对象类型 图：工厂设计模式的示意图 Source：https://www.techcrashcourse.com/2015/10/factory-design-pattern.html
图片说明： Owl, Eagle, Sparrow 类都必须实现 Brid 接口， 该接口声明了一个名为 fly() 的方法。 每个类都将以不同的方式实现该方法。而使用工厂模式后的代码机构则为图所示，当 Owl, Eagle, Sparrow 实现了共同的接口，就可以将其对象传递给客户代码， 而无需提供额外数据。
而 “调用工厂方法的代码” 称为 “客户端代码”，这样可以做到 “不需要了解不同子类返回实际对象之间的差别”。客户端代码将所有 Brid Sanctuary 视为抽象的 Brid ，这样 ”客户端代码“ 知道所有鸟类对象都提供 fly() 方法， 但是并不关心其实现方式。
代码实现 brid.go
go 1 2 3 4 5 package main type Brid interface { Fly() } Owl.go
go 1 2 3 4 5 type Owl struct {} func (g *Owl) Fly() { fmt.</description>
    </item>
    <item>
      <title>kube-proxy如何保证规则的一致性</title>
      <link>https://www.oomkill.com/ch24-kube-proxy-performance/</link>
      <pubDate>Thu, 09 Mar 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch24-kube-proxy-performance/</guid>
      <description>本文是关于Kubernetes service解析的第5章 深入理解Kubernetes service - 你真的理解service吗? 深入理解Kubernetes service - EndpointSlices做了什么？ 深入理解Kubernetes service - kube-proxy架构分析 深入理解Kubernetes service - 如何扩展现有的kube-proxy架构 kube-proxy如何保证规则的一致性 所有关于Kubernetes service 部分代码上传至仓库 github.com/cylonchau/kube-haproxy
前景 这里谈 kube-proxy 如何保证规则的一致性以及提升 kube-proxy 性能点的地方，这也是 kubernetes 使用稳定性的一部分。
kube-proxy 如何做到的CRUD kube-proxy 实际上与其他内置 controller 架构是相同的，实际上也属于一个 controller ，但它属于一个 service, endpoints 的可读可写的控制器，node的读控制器。对于CRUD方面，kube-proxy，在设计上分为 增/改 两方面。正如下面代码所示 pkg/proxy/ipvs/proxier.go
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func (proxier *Proxier) OnServiceAdd(service *v1.Service) { proxier.OnServiceUpdate(nil, service) } // OnServiceUpdate is called whenever modification of an existing service object is observed.</description>
    </item>
    <item>
      <title>扫盲Kubernetes负载均衡 - 从Ingress聊到LB</title>
      <link>https://www.oomkill.com/kubernetes-lb/</link>
      <pubDate>Sun, 26 Feb 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-lb/</guid>
      <description>概述 在之前有一个系列提到了扩展proxier，但可能细心的同学注意到，作为一个外部的LB，市场上存在一些开源的为kubernetes集群提供的LB，这不是舍近求远吗？而 Google工程师 Adam Dunstan 的 文章 [1] 对比了这些LB的区别（中文翻译备份 [2] ），例如：
MetalLB：最流行的 负载均衡控制器 PureLB：新产品 (文章作者 Adam Dunstan 参与了 PureLB的开发工作) OpenELB：相对较新的产品，最初该LB仅关注路由方向 文章提出了一个LB实现的基本目标为：必要的简单网络组件，与可扩展的集群操作
启动受控的集群service/应用的外部访问 外部资源的预配置 易于整合自动化的工作流程（CI/CD） 那么这些LB与 kube-proxy 甚至于 IPVS/IPTables 有什么区别呢？
这些LB的核心是为集群service提供一个外部IP，而service功能本身还是由 kube-proxy,IPVS 提供，在这点 MetalLB 介绍中提到了这个问题
In layer 2 mode, all traffic for a service IP goes to one node. From there, kube-proxy spreads the traffic to all the service’s pods. [3]
After the packets arrive at the node, kube-proxy is responsible for the final hop of traffic routing, to get the packets to one specific pod in the service.</description>
    </item>
    <item>
      <title>红米手机安装 Pixel Experience</title>
      <link>https://www.oomkill.com/xiaomi-install-pixelexperience/</link>
      <pubDate>Sat, 25 Feb 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/xiaomi-install-pixelexperience/</guid>
      <description>前言 MIUI13 石锤了内置反诈APP后，我的是MIUI12, 接到公安的私人电话，系统直接弹出国家反诈的弹窗，关键我是印度版的Rom，一身冷汗，估计当局审查是通过系统组件更新了，直接装Pixel Experience，以后换设备永远不换最新的，让网友们踩坑吧
注：隐私是一种权利，电信诈骗请问 骗子怎么知道我的金融信息，怎么知道我的出入境信息。上海公安10亿信息泄露是怎么情况，当公权力无法保证用户隐私时，请不要实名制，参考韩国。隐私权参考欧洲
操作 进入fastboot(power button + volume button up)，然后使用数据线连接至PC(windows),然后下载MiFlash 首次弹出时需要安装驱动，以便PC可以识别到手机
给手机安装TWRP [1]，通过搜索找到你的手机型号 例如 Redmi Note5。(可以去小米ROM网上对照下你的手机代号时什么例如 Note7 Pro 代号为 紫罗兰 violet)
在下载时TWRP网站上会提示你先安装 Play Stroe(这是包含了adb fastboot等工具的工具包，有的话可以不装) 安装步骤可以参考 [2]
选择 Wipe – Advance Wipe – 选上 System, Data, Dalvik, Cache 四个擦除
下载 firmware 与 PixelExperience
去 https://download.pixelexperience.org/ 下载 PixelExperience 找到自己的手机型号，参考1 去 https://xiaomifirmwareupdater.com/firmware/ 下载 fireware 找到自己的手机型号，参考1 注：建议直接搜代号如violet，搜型号太多不好找 向手机复制 firmware [3] 和固件
fw_violet_miui_VIOLET_9.9.3_79d3ccd33b_9.0.zip PixelExperience_violet-10.0-20191021-1744-BETA-OFFICIAL.zip 复制命令参考 [10] 按先后顺序安装后，重启就安装好google pixel experience了 enjoy 🤞</description>
    </item>
    <item>
      <title>深入理解Kubernetes service - EndpointSlices做了什么？</title>
      <link>https://www.oomkill.com/ch18-endpointslices/</link>
      <pubDate>Sat, 25 Feb 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch18-endpointslices/</guid>
      <description>本文是关于Kubernetes service解析的第2章 深入理解Kubernetes service - 你真的理解service吗? 深入理解Kubernetes service - EndpointSlices做了什么？ 深入理解Kubernetes service - kube-proxy架构分析 深入理解Kubernetes service - 如何扩展现有的kube-proxy架构 kube-proxy如何保证规则的一致性 所有关于Kubernetes service 部分代码上传至仓库 github.com/cylonchau/kube-haproxy
Endpoint Endpoints 就是 service 中后端的server，通常来说 endpoint 与 service是关联的，例如下面的一个endpoints 资源。
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 apiVersion: v1 kind: Endpoints metadata: name: nginx subsets: - addresses: - ip: 172.17.0.2 - ip: 172.17.0.3 ports: - port: 80 name: &amp;#34;111&amp;#34; # 多个端口需要用name - port: 88 name: &amp;#34;222&amp;#34; 而 Endpoints 资源是由控制平面的 Endpoints controller 进行管理的，主要用于将外部server引入至集群内时使用的，例如Kube-apiserver 在集群外的地址，以及external service所需要创建的。</description>
    </item>
    <item>
      <title>深入理解Kubernetes service - 如何扩展现有的kube-proxy架构？</title>
      <link>https://www.oomkill.com/ch23-extend-kube-proxy/</link>
      <pubDate>Sun, 12 Feb 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch23-extend-kube-proxy/</guid>
      <description>本文是关于Kubernetes service解析的第4章 深入理解Kubernetes service - 你真的理解service吗? 深入理解Kubernetes service - EndpointSlices做了什么？ 深入理解Kubernetes service - kube-proxy架构分析 深入理解Kubernetes service - 如何扩展现有的kube-proxy架构 kube-proxy如何保证规则的一致性 所有关于Kubernetes service 部分代码上传至仓库 github.com/cylonchau/kube-haproxy
Overview 在前两部分中，学习了一些 service,于kube-proxy在设计架构，但存在扩展问题将引入了一些问题：
为什么需要了解这部分内容呢？ 与传统架构有什么区别呢？ 于eBPF 的 cilium又有什么区别呢？ 既然eBPF可以做到，那为什么要这部分内容呢？ 接下来的内容将围绕这四个问题展开来讲，而不是代码的讲解，代码可以看置顶
IPVS与iptables在kubernetes中应用时的问题 对于在使用了kubernetes用户以及了解 kube-proxy 架构后，知道当集群规模过大时，service必将增多，而一个service未必是一条iptables/ipvs规则，对于kubernetes这种分布式架构来说，集群规模越大，集群状态就越不可控，尤其时kube-proxy。
为什么单指kube-proxy呢？想想可以知道，pod的故障 或 node 的故障对于kubernetes集群来说却不是致命的，因为 这些资源集群中存在 避免方案，例如Pod的驱逐。而kube-proxy或iptables/IPVS问题将导致服务的不可控 『抖动』例如规则生成的快慢和Pod就绪的快慢不一致，部分节点不存在 service 此时服务必然抖动。
再例如 iptables/IPVS 排查的难度对于普通运维工程师或开发工程师的技术水平有很高的要求，网上随处可见分析该类问题的帖子：
kube-proxy源码分析与问题定位
案例分析：怎么解决海量IPVS规则带来的网络延时抖动问题？
ipvs 连接复用引发的系列问题
Investigating Causes of Jitter in Container Networking
ContainerNative network LoadBalancer IPVS jitter
对于上述问题，相信遇到了很难定位处理，虽然现在已fixed，并有eBPF技术的加入减少了此类问题的发生，但是eBPF实际同理于IPVS 都是需要对Linux内核有一定了解后才可以，这也就是为什么需要了解这部分
如果需要自定义proxier为什么会解决这个问题 这里就是放大到kubernetes意外的传统架构中，当直接部署于Linux系统上使用nginx等传统LB时就很少有人提到这些问题了，而这些问题存在一个关键字「Container」；而引发这个问题的则是 service。去除 service 的功能，传统架构于Kubernetes架构部署的应用则是相同的，只是区分了名称空间。</description>
    </item>
    <item>
      <title>深入理解Kubernetes service - kube-proxy架构分析</title>
      <link>https://www.oomkill.com/ch19-kube-proxy-code/</link>
      <pubDate>Mon, 06 Feb 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch19-kube-proxy-code/</guid>
      <description>本文是关于Kubernetes service解析的第3章 深入理解Kubernetes service - 你真的理解service吗? 深入理解Kubernetes service - EndpointSlices做了什么？ 深入理解Kubernetes service - kube-proxy架构分析 深入理解Kubernetes service - 如何扩展现有的kube-proxy架构 kube-proxy如何保证规则的一致性 所有关于Kubernetes service 部分代码上传至仓库 github.com/cylonchau/kube-haproxy
前提概述 kubernetes集群中运行在每个Worker节点上的组件 kube-proxy，本文讲解的是如何快速的了解 kube-proxy 的软件架构，而不是流程的分析，专注于 proxy 层面的设计讲解，而不会贴大量的代码
kube-proxy软件设计 kube-proxy 在设计上分为三个模块 server 于 proxy：
server: 是一个常驻进程用于处理service的事件 proxy: 是 kube-proxy 的工作核心，实际上的角色是一个 service controller，通过监听 node, service, endpoint 而生成规则 proxier: 是实现service的组件，例如iptables, ipvs&amp;hellip;. 如何快速读懂kube-proxy源码 要想快速读懂 kube-proxy 源码就需要对 kube-proxy 设计有深刻的了解，例如需要看 kube-proxy 的实现，我们就可以看 proxy的部分，下列是 proxy 部分的目录结构
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 $ tree -L 1 .</description>
    </item>
    <item>
      <title>深入理解Kubernetes service - 你真的理解service吗？</title>
      <link>https://www.oomkill.com/ch17-service-controller/</link>
      <pubDate>Mon, 06 Feb 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch17-service-controller/</guid>
      <description>本文是关于Kubernetes service解析的第1章 深入理解Kubernetes service - 你真的理解service吗? 深入理解Kubernetes service - EndpointSlices做了什么？ 深入理解Kubernetes service - kube-proxy架构分析 深入理解Kubernetes service - 如何扩展现有的kube-proxy架构 kube-proxy如何保证规则的一致性 所有关于Kubernetes service 部分代码上传至仓库 github.com/cylonchau/kube-haproxy
前景 对于了解kubernetes架构时，已知的是 service 是kubernetes在设计时为了避免Pod在频繁创建和销毁时IP变更问题，从而给集群内服务（一组Pod）提供访问的一个入口。而Pod在这里的角色是 『后端』( backend ) ，而 service 的角色是 『前端』( frontend )。本文将阐述service的生命周期
为什么需要了解这部分内容呢 对于 without kube-proxy来说，这部分是最重要的部分，因为service的生成不是kube-proxy来完成的，而这部分也就是service ip定义的核心。
控制器 service的资源创建很奇妙，继不属于 controller-manager 组件，也不属于 kube-proxy 组件，而是存在于 apiserver 中的一个被成为控制器的组件；而这个控制器又区别于准入控制器。更准确来说，准入控制器是位于kubeapiserver中的组件，而 控制器 则是存在于单独的一个包，这里包含了很多kubernetes集群的公共组件的功能，其中就有service。这也就是在操作kubernetes时 当 controller-manager 于 kube-proxy 未工作时，也可以准确的为service分配IP。
首先在构建出apiserver时，也就是代码 cmd/kube-apiserver/app/server.go
go 1 2 3 4 serviceIPRange, apiServerServiceIP, err := master.ServiceIPRange(s.PrimaryServiceClusterIPRange) if err !</description>
    </item>
    <item>
      <title>haproxy 中 http 代理的连接模式</title>
      <link>https://www.oomkill.com/haproxy-http-connection-mode/</link>
      <pubDate>Tue, 31 Jan 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/haproxy-http-connection-mode/</guid>
      <description>haproxy作为一个『代理软件』如果当工作与 HTTP 模式下，所有经由haproxy的的连接的请求和响应都取决于 frondend 中配置的 『http_connection_mode』 即 haproxy 中 frontend 与 backend 的组合，而haproxy 支持 3 种连接模式：
KAL keep alive: frontend 中配置为 http-keep-alive ; 这是默认模式，这也是http中的keepalive 表示所有请求和响应都得到处理，连接保持打开状态，但在响应和新请求之间处于空闲状态。 SCL server close : frontend 中配置为 http-server-close ; 接收到响应结束后，面向服务器的连接关闭，但面向客户端的连接保持打开状态 CLO close: frontend 中配置为 httpclose ；连接在响应结束后关闭，并在两个方向上附加 &amp;ldquo;Connection: close&amp;rdquo; 。 下列矩阵表示的是通过 frondend 与 backend 之间两端的代理模式，这个模式是对称的
text 1 2 3 4 5 6 7 | KAL | SCL | CLO ----+-----+-----+---- KAL | KAL | SCL | CLO ----+-----+-----+---- mode SCL | SCL | SCL | CLO ----+-----+-----+---- CLO | CLO | CLO | CLO 对于http选项的说明 选项 说明 forwardfor 这个选项同时存在于backend 与 frontend端，但backend中的优先级超过frontend 如果同时设置了这个参数，那么 backend段的子参数将优先与 frontend 一端 httpchk 启用http协议检查来检测server的健康状态，默认情况下状态检查是仅建立一个tcp连接 httpclose 这个选项代表了haproxy 对于http协议持久连接方便的配置 Reference：configuration.</description>
    </item>
    <item>
      <title>git在windows上常用配置</title>
      <link>https://www.oomkill.com/awesome-git-configration-in-windows/</link>
      <pubDate>Tue, 24 Jan 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/awesome-git-configration-in-windows/</guid>
      <description>Windows git &amp;ldquo;warning: LF will be replaced by CRLF&amp;rdquo; [1] bash 1 git config --global core.autocrlf false Disable Credential Manager bash 1 2 3 4 5 git config --global credential.modalprompt false git credential-manager remove -force git credential-manager uninstall --force Multi account management [2] step1: clean globle setting
bash 1 2 git config --global --unset user.name git config --global --unset user.email step2： change config file only ssh
bash Do not Pop-ups authtication [3] This question is the git shell prompt input user and password in an openssh popup on windows plateform</description>
    </item>
    <item>
      <title>Go中的类型断言与类型转换</title>
      <link>https://www.oomkill.com/go-type-assertion/</link>
      <pubDate>Tue, 24 Jan 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-type-assertion/</guid>
      <description>类型断言 类型断言 type assertion 并不是真正的将 interface 类型转换为另一种确定的类型，只是提供了对 interface 类型的值的访问，通常情况下，这是常见的需求
类型断言通过 语法 x.(T) ，这将会确定 x 变量中存储的值是否属于 T 类型，通常场景有两种：
如果 T 不是 interface 类型，而是一个具体的类型，那么这次断言将断言 x 的 动态类型是否与 T 相同 如果 T 是 interface 类型，这次断言 x 的动态类型是否实现了 T go 1 2 3 4 5 6 7 8 9 10 11 12 var x interface{} = &amp;#34;foo&amp;#34; var s string = x.(string) fmt.Println(s) // &amp;#34;foo&amp;#34; s, ok := x.(string) fmt.Println(s, ok) // &amp;#34;foo true&amp;#34; n, ok := x.</description>
    </item>
    <item>
      <title>如何使用go语言来检查端口可用性</title>
      <link>https://www.oomkill.com/goskill-port-is-available/</link>
      <pubDate>Fri, 06 Jan 2023 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/goskill-port-is-available/</guid>
      <description>方法1：dial 使用 net.DialTimeout 去检查端口的技巧：
在通过Dial检查端口占用时，需要知道网络中常见的报错状态，而不是 err != nil 都为可用
Connection reset by peer connection reset by peer 这种错误情况下有以下几种场景：
基于包过滤的防火墙给予 RST；对于此情况，基于网络模型来说处于网络层与传输层之间的netfilter，如果是防火墙拒绝那么未到应用层无法确认端口 对端应用资源限制而reset，通常为负载过高；对于此场景是已到达应用层 客户端关闭了连接，而服务器还在给客户端发送数据；对于端口检查来说不会到这步 由上面可知，这种错误一定为占用
Connection timed out Connection timed out 这种场景根本就dial不成功，go中给出了一个专门的事件 opErr.Timeout() 来说明这个错误，故此错误将不能确认端口是否占用
Connection refused Connection refused 这种场景催在两种情况
对于 local 场景来说，这将表示端口未监听 对于远端场景来说，这种基本上表示 client 发往 remote ，remote不能接受 host:port 这个连接 通常对于存在两种情况，但多数为端口为监听
Misconfiguration, such as where a user has mistyped the port number, or is using stale information about what port the service they require is running on.</description>
    </item>
    <item>
      <title>haproxy v1 与 haproxy v2</title>
      <link>https://www.oomkill.com/haproxy2/</link>
      <pubDate>Wed, 14 Dec 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/haproxy2/</guid>
      <description>haproxy1 VS haproxy2 haproxy2由 2019-06-16 被发布，对于与haproxy1版本来说，haproxy 2.0 增加了对云原生的支持，这使得haproxy 2.0 更适用于云原生环境，对比于 haproxy1.0 在2001年发布来，到 1.9.16 在 2020/07/31 最后一次更新也代表haproxy1.0的结束维护
为什么选择haproxy2.0 haproxy2.0的核心功能就是集成了云原生架构的支持。包含L7重试, Prometheus metrics, 流量镜像 (traffic shadowing), 多语言可扩展性, gRPC 。haproxy2.0 还增加 基于haproxy2.0 的 Kubernetes Ingress Controller 和强大的 HAProxy Data Plane API，这提供了用于配置和管理 HAProxy 的 REST API
安装haproxy2.0 对于 Ubuntu/Debian 来说，社区版haproxy提供了更友好的安装方式，用户直接添加对应仓库可以直接安装最新版本的haproxy Debian/Ubuntu HAProxy packages
对于 CentOS/Fedora 来说，只有Fedora 仓库提供了较为新版的haproxy，通常来在这类平台的Linux都是通过编译安装haproxy
下载haproxy2.6源码 [ haproxy下载 ]
安装依赖包
bash 1 yum install gcc pcre-devel openssl-devel tar make -y 编译程序
bash 1 2 3 4 5 6 7 8 9 tar xf haproxy-2.</description>
    </item>
    <item>
      <title>长期总结 - Linux性能分析命令</title>
      <link>https://www.oomkill.com/performance-command/</link>
      <pubDate>Mon, 12 Dec 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/performance-command/</guid>
      <description>工具命令集合 长期总结 - Linux日志查询命令 长期总结 - Linux网络命令合集 长期总结 - Linux性能分析命令 awk常用案例 bash shell常用示例 探索kubectl - 巧用jsonpath提取有用数据 探索kubectl - kubectl诊断命令集合 perf [1] perf 是基于内核子系统的Linux的性能计数器，也被称为 perf_events，它提供了为所有事件进行性能分析的框架，perf 由两部分组成：
内核系统调用，用于提供对这些性能数据的访问 用户空间工具，用于提供收集，显示分析这些性能数据的用户空间程序 由于 perf 是内核的一部分，但要想使用 perf 还需要安装另外一部分，通常情况下安装的版本是Linux内核版本，如操作系统内核版本为 5.10 那么安装 linux-tool 后则为 5.10
bash 1 2 3 4 $ apt-get install linux-perf $ perf --version perf version 5.10.149 各系统下的包名与安装
Ubuntu/Debian: linux-perf | linux-tools ；apt-get install linux-perf CentOS/Fedora: perf ；yum install -y perf list - 列出可用事件描述符 使用 perf 子命令 list 可以列出所有的 perf 可测量事件</description>
    </item>
    <item>
      <title>debian11更新内核版本</title>
      <link>https://www.oomkill.com/debian-update-kernel/</link>
      <pubDate>Sun, 11 Dec 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/debian-update-kernel/</guid>
      <description>搜索linux 内核 image
bash 1 apt-cache search linux-image 然后安装对应image
bash 1 sudo apt install linux-image-&amp;lt;flavour&amp;gt; 安装完成后可以看到对应的image
bash 1 2 3 4 $ dpkg -l|grep linux-image ri linux-image-5.10.0-16-amd64 5.10.127-2 amd64 Linux 5.10 for 64-bit PCs (signed) ii linux-image-5.10.0-16-amd64-dbg 5.10.127-2 amd64 Debug symbols for linux-image-5.10.0-16-amd64 ii linux-image-amd64 5.10.127-2 amd64 Linux for 64-bit PCs (meta-package) 可以通过命令查看拥有的内核启动项
bash 1 grep -e &amp;#34;menuentry &amp;#34; -e submenu -e linux /boot/grub/grub.cfg 需要修改至新内核可以修改 /etc/default/grub 下的 GRUB_DEFAULT=
这里要填的值为上面命令查询出的，例如 menuentry &#39;Debian GNU/Linux, with Linux 5.</description>
    </item>
    <item>
      <title>理解Kubernetes驱逐核心 - Pod QoS</title>
      <link>https://www.oomkill.com/kubernetes-pod-qos/</link>
      <pubDate>Thu, 01 Dec 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-pod-qos/</guid>
      <description>服务质量 Quality of Service (QoS)，在Kubernetes是用于解决资源抢占，延迟等方向的一种技术，是服务于调度与抢占之间的条件。
QoS 级别 QoS 与 资源限制紧密相关，正如下属展示，是一个Pod资源限制部分的配置
yaml 1 2 3 4 5 6 7 resources: limits: cpu: 200m memory: 1G requests: cpu: 500m memory: 1G 而Kubernetes 将Pod QoS 根据 CPU 与 内存的配置，将QoS分为三个等级：
Guaranteed：确保的，只设置 limits 或者 requests 与 limits 为相同时则为该等级 Burstable：可突发的，只设置 requests 或 requests 低于 limits 的场景 Best-effort： 默认值，如果不设置则为这个等级 为什么要关心Pod QoS级别 在Kubernetes中，将资源分为两类：可压缩性资源 “CPU”，不可压缩性资源 “内存”。当可压缩性资源用尽时，不会被终止与驱逐，而不可压缩性资源用尽时，即Pod内存不足，此时会被OOMKiller杀掉，也就是被驱逐等操作，而了解Pod 的QoS级别可以有效避免关键Pod被驱逐。
图：Pod QoS分类 Source：https://doc.kaas.thalesdigital.io/docs/BestPractices/QOS
有上图可知，BestEffort 级别的 Pod 能够使用节点上所有资源，浙江导致其他 Pod 出现资源问题。所以这类 Pod 优先级最低，如果系统没有内存，将首先被杀死。
Pod是如何被驱逐的 当节点的计算资源不足时，kubelet 会发起驱逐，这个操作是为了避免系统OOM事件，而QoS的等级决定了驱逐的优先级，没有限制资源的 BestEffort 类型的Pod最先被驱逐，接下来资源使用率低于 Requests 的 Guaranteed 与 Burstable 将不会被其他Pod的资源使用量而驱逐，其次对于此类Pod而言，如果Pod使用了比配置（Requests）更多的资源时，会根据这两个级别Pod的优先级进行驱逐。 BestEffort 与 **Burstable **将按照先优先级，后资源使用率顺序进行驱逐</description>
    </item>
    <item>
      <title>kubernetes概念 - 理解Kubernetes的驱逐机制</title>
      <link>https://www.oomkill.com/kubernetes-eviction/</link>
      <pubDate>Tue, 29 Nov 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-eviction/</guid>
      <description>驱逐 (eviction) 是指终止在Node上运行的Pod，保证workload的可用性，对于使用Kubernetes，了解驱逐机制是很有必要性的，因为通常情况下，Pod被驱逐是需要解决驱逐背后导致的问题，而想要快速定位就需要对驱逐机制进行了解。
Pod被驱逐原因 Kubernetes官方给出了下属Pod被驱逐的原因：
抢占驱逐 (Preemption and Eviction) [1] 节点压力驱逐 (Node-pressure) [2] 污点驱逐 (Taints) [3] 使用API发起驱逐 (API-initiated) [4] 排出Node上的Pod (drain) [5] 被 controller-manager 驱逐 抢占和优先级 抢占是指当节点资源不足以运行新添加的Pod时，kube-scheduler 会检查低优先级Pod而后驱逐掉这些Pod以将资源分配给优先级高的Pod。这个过程称为 “抢占” 例如这个实例是 kube-proxy 被驱逐的场景
节点压力驱逐 节点压力驱逐是指，Pod所在节点的资源，如CPU, 内存, inode等，这些资源被分为可压缩资源CPU (compressible resources) 与不可压缩资源 (incompressible resources) 磁盘IO, 内存等，当不可压缩资源不足时，Pod会被驱逐。对于此类问题的驱逐 是每个计算节点的 kubelet 通过捕获 cAdvisor 指标来监控节点的资源使用情况。
被 controller-manager 驱逐 kube-controller-manager 会定期检查节点的状态，如节点处于 NotReady 超过一定时间，或Pod部署长时间失败，这些Pod由控制平面 controller-manager 创建新的Pod已替换存在问题的Pod
通过API发起驱逐 Kubernetes为用户提供了驱逐的API，用户可以通过调用API来实现自定义的驱逐。
对于 1.22 以上版本，可以通过API policy/v1 进行驱逐
bash 1 2 3 4 5 6 7 8 9 10 11 curl -v \ -H &amp;#39;Content-type: application/json&amp;#39; \ https://your-cluster-api-endpoint.</description>
    </item>
    <item>
      <title>深入理解Kubernetes 4A - Audit源码解析</title>
      <link>https://www.oomkill.com/ch34-auditing/</link>
      <pubDate>Thu, 24 Nov 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch34-auditing/</guid>
      <description>本文是关于Kubernetes 4A解析的第4章 深入理解Kubernetes 4A - Authentication源码解析 深入理解Kubernetes 4A - Authorization源码解析 深入理解Kubernetes 4A - Admission Control源码解析 深入理解Kubernetes 4A - Audit源码解析 TLS Everywhere - 解密kubernetes集群的安全认证 所有关于Kubernetes 4A部分代码上传至仓库 github.com/cylonchau/hello-k8s-4A
Overview 审计是信息系统中非常重要的一部分，Kubernetes 1.11中也增加了审计 (Auditing) 功能，通过审计功能获得 deployment, ns,等资源操作的事件。
objective：
从设计角度了解Auditing在kubernets中是如何实现的 了解kubernetes auditing webhook 完成实验，通过webhook来收集审计日志 如有错别字或理解错误地方请多多担待，代码是以1.24进行整理，实验是以1.19环境进行，差别不大。
Kubernetes Auditing 根据Kubernetes官方描述审计在kubernetes中是有控制平面 kube-apiserver 中产生的一个事件，记录了集群中所操作的资源，审计围绕下列几个维度来记录事件的：
发生了什么 发生的事件 谁触发的 发生动作的对象 在哪里检查到动作的 从哪触发的 处理行为是什么 审计生命周期开始于组件 kube-apiserver 准入控制阶段，在每个阶段内都会产生审计事件并经过预处理后写入后端，目前后端包含webhook与日志文件。
审计日志功能增加了 kube-apiserver 的内存消耗，因为会为每个请求存储了审计所需的上下文。内存的消耗取决于审计日志配置 [1]。
审计事件设计 审计的schema不同于资源API的设计，没有 metav1.ObjectMeta 属性，Event是一个事件的结构体，Policy是事件配置，属于kubernetes资源，在代码 k8s.io/apiserver/pkg/apis/audit/types.go 可以看到
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 type Event struct { metav1.</description>
    </item>
    <item>
      <title>深入理解Kubernetes 4A - Authorization源码解析</title>
      <link>https://www.oomkill.com/ch32-authorization/</link>
      <pubDate>Thu, 24 Nov 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch32-authorization/</guid>
      <description>本文是关于Kubernetes 4A解析的第2章 深入理解Kubernetes 4A - Authentication源码解析 深入理解Kubernetes 4A - Authorization源码解析 深入理解Kubernetes 4A - Admission Control源码解析 深入理解Kubernetes 4A - Audit源码解析 TLS Everywhere - 解密kubernetes集群的安全认证 所有关于Kubernetes 4A部分代码上传至仓库 github.com/cylonchau/hello-k8s-4A Overview 在 Kubernetes 中，当一个访问请求通过了登录阶段（Authentication），必须还需要请求拥有该对象的访问权限，而授权部分也是Kubernetes API 访问控制中的第二个部分 Authorization .
Authorization 在 Kubernetes中是以评估发起请求的用户，根据其身份特性评估这次请求是被 ”拒绝“ 还是 “允许”，同访问控制三部曲中其他两个插件 (Authentication, Adminssion Control) 一样，Authorization 也可以同时配置多个，当收到用户的请求时，会依次检查这个阶段配置的所有模块，如果任何一个模块对该请求授予权限（拒绝或允许），那么该阶段会直接返回，当所有模块都没有该用户所属的权限时，默认是拒绝，在Kubernetes中，被该插件拒绝的用户显示为HTTP 403。
如有错别字或理解错误地方请多多担待，代码是以1.24进行整理，实验是以1.19环境进行，差别不大
objective：
了解kubernetes Authorization机制 了解授权系统的设计 完成实验，使用 OPA 作为 Kubernetes 外部用户，权限认证模型 RBAC 的替代品 Kubernetes是如何对用户授权的 kubernetes对用户授权需要遵守的shema必须拥有下列属性，代码位于pkg\apis\authorization\types.go
go 1 2 3 4 5 6 7 8 9 type SubjectAccessReview struct { // API必须实现的部分 metav1.</description>
    </item>
    <item>
      <title>深入理解Kubernetes 4A - Authentication源码解析</title>
      <link>https://www.oomkill.com/ch31-authentication/</link>
      <pubDate>Wed, 16 Nov 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch31-authentication/</guid>
      <description>本文是关于Kubernetes 4A解析的第1章 深入理解Kubernetes 4A - Authentication源码解析 深入理解Kubernetes 4A - Authorization源码解析 深入理解Kubernetes 4A - Admission Control源码解析 深入理解Kubernetes 4A - Audit源码解析 TLS Everywhere - 解密kubernetes集群的安全认证 所有关于Kubernetes 4A部分代码上传至仓库 github.com/cylonchau/hello-k8s-4A
Overview 本章主要简单阐述kubernetes 认证相关原理，最后以实验来阐述kubernetes用户系统的思路
objective：
了解kubernetes 各种认证机制的原理 了解kubernetes 用户的概念 了解kubernetes authentication webhook 完成实验，如何将其他用户系统接入到kubernetes中的一个思路 如有错别字或理解错误地方请多多担待，代码是以1.24进行整理，实验是以1.19环境进行，差别不大。
Kubernetes 认证 在Kubernetes apiserver对于认证部分所描述的，对于所有用户访问Kubernetes API（通过任何客户端，客户端库，kubectl 等）时都会经历 验证 (Authentication) , 授权 (Authorization), 和准入控制 (Admission control) 三个阶段来完成对 “用户” 进行授权，整个流程正如下图所示
图：Kubernetes API 请求的请求处理步骤图 Source：https://www.armosec.io/blog/kubernetes-admission-controller/
其中在大多数教程中，在对这三个阶段所做的工作大致上为：
Authentication 阶段所指用于确认请求访问Kubernetes API 用户是否为合法用户，拒绝为401
Authorization 阶段所指的将是这个用户是否有对操作的资源的权限，拒绝为403
Admission control 阶段所指控制对请求资源进行控制，通俗来说，就是一票否决权，即使前两个步骤完成</description>
    </item>
    <item>
      <title>理解ldap - 使用SSSD接入OpenLDAP实现身份验证</title>
      <link>https://www.oomkill.com/ch11-sssd/</link>
      <pubDate>Tue, 15 Nov 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch11-sssd/</guid>
      <description>openldap合集 ch1 理解ldap - 什么是ldap ch2 理解ldap - OpenLDAP安装 ch3 理解ldap - OpenLDAP客户端命令行使用 ch4 理解ldap - OpenLDAP架构与Schema设计 ch5 理解ldap - OpenLDAP使用SSL/TLS通信安全 ch6 理解ldap - OpenLDAP中的4种复制机制 ch7 理解ldap - OpenLDAP访问控制(ACL) ch8 理解ldap - OpenLDAP备份与恢复策略 ch9 理解ldap - openldap中的一些高级配置 ch10 理解ldap - Linux系统接入OpenLDAP做认证后端 ch11 理解ldap - 使用SSSD接入OpenLDAP实现身份验证 Overview SSSD (System Security Services Daemon) 是一套用于远程身份验证的套件服务，为使用SSSD服务的客户端提供了远程访问身份认证服务来获取权限，其后端包括AD, LDAP等，本文将围绕下列方向来阐述SSSD：
为什么需要SSSD，以及使用SSSD来解决什么 使用SSSD的好处 SSSD服务工作原理及架构 如何在Linux上配置SSSD+LDAP 为什么需要SSSD SSSD设计主要是为了传统使用身份认证服务，例如PAM+NSS架构中存在的一些问题：
PAM+NSS扩展性差，并配置较为复杂，尽管提供了 authconfig ，通常在大多数教程中以及不同的系统中配置都不相同 PAM+NSS不是真正意义上的离线身份认证，如果当 nslcd 或者 slapd 等服务异常时，无法完成用户认证 以及越来越多的后端，例如LDAP, AD, IPA, IdM,Kerberos等无法做到很好的适配 SSSD就是为了解决上述的问题，对于Linux平台中，SSSD拥有比传统PAM+NSS更好的优势：</description>
    </item>
    <item>
      <title>ipset性能测试</title>
      <link>https://www.oomkill.com/ipset-preformance/</link>
      <pubDate>Fri, 04 Nov 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ipset-preformance/</guid>
      <description>测试方法 基于使用场景，最后⽣成的规则会是按照 ip 或者 ip:port 来进行过滤，测试时将使用10万条 iptables 规则来模拟对性能的压力；为了最大化测试压力情况，10万条 iptables 规则将都是==不会匹配==机房流量，通俗来讲，就是链式匹配会进行所有匹配并最后以无匹配告终。
网络负载的模拟将使用同机房 scp 来模拟，并按照下述条件进行匹配：
查看正常的拷贝速度，cpu负载等 我们建⽴10万条的普通 iptables 规则，查看规则建立速度，拷贝速度，CPU负载，CPU主要耗时操作等 我们建⽴10万的 ipset ，并把普通的 iptables 规则转为结合 ipset 的规则，查看规则建立速度，拷贝速度，CPU负载，CPU主要耗时等。 实验开始 步骤一：在同机房的⼀个机器构造⼀个大文件
同机房拷贝
观察网卡速度，CPU，系统主要耗时操作的等，此场景将在iptables 规则为空的情况下进行观察
使用 sar 观测网卡速度
使用 top 观察CPU负载
使用 perf top -G 观察CPU占用
步骤二：创建10万条iptables，观察⽹卡速度、cpu、系统主要耗时操作的等，会发现cpu利⽤率⼤部分被ipt占⽤，拷⻉速度下降到不到⼗分之⼀
bash 1 2 3 4 5 6 7 8 #!/bin/bash echo *filter for ((i=1;i&amp;lt;=$1;i++)) do echo -I INPUT -S $i -j ACCEPT done echo COMMIT 执行脚本
bash 1 $ time .</description>
    </item>
    <item>
      <title>Linux网络栈</title>
      <link>https://www.oomkill.com/network-stack/</link>
      <pubDate>Fri, 28 Oct 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/network-stack/</guid>
      <description>Linux 架构概述 [1] 本章节简单阐述Linux系统的结构，并讨论子系统中的模块之间以及与其他子系统之间的关系。
Linux内核本身鼓励无用，是作为一个操作系统的一部分参与的，只有为一个整体时他才是一个有用的实体，下图展示了Linux操作系统的分层
图：Linux子系统分层图 Source：https://docs.huihoo.com/linux/kernel/a1/index.html
由图可以看出Linux操作系统由四部分组成：
用户应用 OS服务，操作系统的一部分（例如shell）内核编程接口等 内核 硬件控制器，CPU、内存硬件、硬盘和NIC等都数据这部分 Linux内核阐述 Linux内核将所有硬件抽象为一致的接口，为用户进程提供了一个虚拟接口，使用户无需知道计算机上安装了哪些物理硬件即可编写进程，并且Linux支持用户进程的多任务处理，每个进程都可以视作为操作系统的唯一进程独享硬件资源。内核负责维护多个用户进程，并协调其对硬件资源的访问，使得每个进程都可以公平的访问资源，并保证进程间安全。
Linux内核主要为五个子系统组成：
进程调度器(SCHED)， 控制进程对 CPU 的访问。调度程序执行策略，确保进程可以公平地访问 CPU。 内存管理器 (MM)， 允许多个进程安全地共享操作系统的内存 虚拟文件系统 (VFS)，向所有设备提供通用文件接口来抽象出各种硬件设备 网络接口 (NET)，提供对多种网络标准与各种网络硬件的访问 进程间通信 (IPC)，在单个操作系统上的多种机制进程间通信机制 网络子系统架构 [2] 网络子系统功能主要是允许 Linux 系统通过网络连接到其他系统。支持多种硬件设备，以及可以使用的多种网络协议。网络子系统抽象了这两个实现细节，以便用户进程和其他内核子系统可以访问网络，而不必知道使用什么物理设备或协议。
子系统模块包含
网络设备驱动层 (Network device drivers)，网络设备驱动程序与硬件设备通信。每个硬件设备都有对应的设备驱动程序模块。 独立设备接口层(device independent interface)，设备独立接口提供了所有硬件设备的统一视图，因此在网络子系统之上的级别无需了解硬件信息 网络协议层 (network protocol)，网络协议实现了网络传输的协议 协议独立/无关接口层 (protocol independent interface)，提供了独立于硬件设备的网络接口，为内核内其他子系统访问网络时不依赖特定的协议和硬件接口。 系统调用层 (system call) 用于限制用户进程导出资源的访问 网络子系统的结构图如下图所示，
图：网络子系统中的上下文 Source：https://docs.huihoo.com/linux/kernel/a1/index.html
当网络子系统转换为网络栈时，如下图所示
图：ISO Stack与TCP/IP Stack Source：https://www.washington.edu/R870/Networking.html
当然Linux网络子系统是类似于TCP/IP栈的一种结构，当发生一个网络传输时，数据包会按照所经过的层进行封装。例如应用层应用提供了REST API，那么应用将要传输的数据封装为HTTP协议，然后传递给向下的传输层。传输层是TCP协议就会被添加对应的TCP包头。整个封装过程原始包保持不变，会根据所经过层的不同增加固定格式的包头。
图：数据包传输在每层被封装的过程 Source：http://www.embeddedlinux.org.cn/linux_net/0596002556/understandlni-CHP-13-SECT-1.html
对于Linux来说TCP/IP 的五层结构则是构成网络子系统的的核心组件，下图是Linux网络栈结构图
图：Linux网络栈的结构图 Source：https://medium.com/geekculture/linux-networking-deep-dive-731848d791c0
图中橙色部分是位于TCP/IP的五层结构中的应用层，应用层向下通讯通过 system call 与 socket接口进行交互 蓝色部分是位于内核空间，socket向下则是传输层与网络层 最底层是物理层包含网卡驱动与NIC 通过图可以看出，NIC是发送与接收数据包的基本单位，当系统启动时内核通过驱动程序向操作系统注册网卡，当数据包到达网卡时，被放入队列中。内核通过硬中断，运行中断处理程序，为网络帧分配内核数据结构(sk_buff)，并将其拷贝到缓冲区中，此为内核与网卡交互的过程。</description>
    </item>
    <item>
      <title>为什么网络是分层的</title>
      <link>https://www.oomkill.com/network-unit-in-osi/</link>
      <pubDate>Fri, 28 Oct 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/network-unit-in-osi/</guid>
      <description>Overview [1] 协议数据单元 Protocol Data Unit (PDU) 是应用于OSI模型中的数据结构，在OSI模型中每一层都会被添加一个header，tailer进行封装，header, tailer加原始报文的组合就是PDU。
在每层中，PDU的名称都是不同的，这也是很多人的疑问，一会数据报文称为数据包，一会数据报文成为数据帧，该文介绍网络中的单元，以了解之间的区别
物理层 物理层数据的呈现方式是以 “位” (bit) 为单位的，即0 1，在该层中数据以二进制形式进行传输
数据链路层 [2] 到达数据链路层，实际上可以说进入了TCP/IP栈对底层，而该层的单位为 ”帧“ (frame)，该层中，MAC地址会被封装到数据包中，比如以太网帧，PPP帧都是指该层的数据包
该层中数据帧包含：
源MAC 目的MAC 数据，由网络层给出的 数据的总长度 校验序列 网络层 [3] 在网络层中协议数据单元被称为数据 “包&amp;quot; (package) ，是网络间节点通讯的基本单位。该层中IP地址会被封装到数据包内。
该层中数据包包含：
标头：源IP，目的IP，协议，数据包编号，帮助数据包匹配网络的位 payload：数据包的主体 标尾：包含几个位，用于告知已到达数据包的末尾与错误检查（循环冗余检查 (CRC)） 图：数据包组成 Source：https://computer.howstuffworks.com/question525.htm
例如一个电子邮件，假设电子邮件大小尾3500bit，发送时使用1024的固定大小数据包进行发送，那么每个数据包标头为 96bits，标尾为 32bit，剩余 896bits 将用于实际的数据大小。这里为3500bits，会被分为4个数据包，前三个数据包为 896bits，最后一个数据包大小为 812bits。接收端会根据包编号进行解包重组
传输层 Segment 在传输层TCP协议的协议数据单元被称为 ”段“ (Segment) ，上面讲到，IP数据包会以固定大小的数据包进行发送，如果超出大小的会被划分为多个数据包，每个数据包的碎片就被称之为Segment。
数据包分割通常会发生在该层，当发生下列场景时会需要分段
数据包大于网络支持的最大传输单元 (MTU) 网络不可靠，将数据包分为更小的包 datagram [4] 在传输层UDP协议的协议数据单元被称为 ”数据报“ (datagram) ，datagram是一种逐层增加的设计，用于无连接通讯
下图是一个UDP数据报被封装位一个IP数据包：IPv4字段值位17 表示udp协议
图：udp的IP包 Source：https://notes.shichao.io/tcpv1/ch10
对于udp数据报的组成包含header与payload，udp的header大小为固定的8字节
源端口：可选 目的端口：识别接收信息的进程 Length：udp header + udp payload的长度，最小值为8 checksum：与lenght一样其实是多余的，因为第三层包含了这两个信息 图：udp数据报组成 Source：https://notes.</description>
    </item>
    <item>
      <title>科普ebpf</title>
      <link>https://www.oomkill.com/what-is-ebpf/</link>
      <pubDate>Sun, 02 Oct 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/what-is-ebpf/</guid>
      <description>eBPF介绍 eBPF是 Extended Berkeley Packet Filter，主要是用于包过滤的。为什么叫Berkeley Packet Filter 是因为论文出自 Lawrence Berkeley Laboratory（相对的论文可以参考 [1]）。“E&amp;quot; 是使BPF不仅仅是包过滤。
eBPF 目前提供的功能不仅仅是包过滤，它是一个允许用户在操作系统内核加载自定义程序的框架，来自于 ”What Is eBPF?“
eBPF is a framework that allows users to load and run custom programs within the kernel of the operating system. That means it can extend or even modify the way the kernel behaves. [2]
eBPF验证器
对于如果想改变Linux内核功能需要合并代码到内核或者编写内核模块。前者需要被社区接受，这需要很长一个周期；而后者可以很好的扩展内核功能，但都存在一个问题 ”==安全运行==“
”安全运行“ 问题包含”漏洞“和“崩溃”，考虑到这些，eBPF为安全运行提供了一个非常不同的方法**：eBPF verifier** ，eBPF verifier 将确保应用只能够在安全情况下被运行。
eBPF verifier 保证了 eBPF 程序运行的 ”安全“ 和 ”验证“</description>
    </item>
    <item>
      <title>ch0 ide</title>
      <link>https://www.oomkill.com/ch0-ide/</link>
      <pubDate>Wed, 28 Sep 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch0-ide/</guid>
      <description>Visual Studio使用 离线安装包 在页面 [4] 下载安装引导命令，下载完成后使用命令（对于C++来说）
bat 1 vs_Professional.exe --layout ‪1111 --add Microsoft.VisualStudio.Workload.NativeDesktop --includeRecommended --lang en-US zh-CN 随后会触发下载，等待下载完成后，在 --layout 指定的目录上点击 vs_setup 开始离线安装。
Note: 对于完全脱离C盘安装可以使用下面的脚本，更改变量为要安装的路径
bat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 :: 关闭终端回显 @echo off SET ROOT_PATH=D:\Program Files\Microsoft Visual Studio SET X86_PATH=%ROOT_PATH%\Program Files (x86) SET X86_VS_PATH=%X86_PATH%\Microsoft Visual Studio SET X86_SDK_PATH=%X86_PATH%\Microsoft SDKs SET X86_KITS_PATH=%X86_PATH%\Windows Kits SET X86_AV_PATH=%X86_PATH%\Application Verifier SET X64_PATH=%ROOT_PATH%\Program Files rem SET X64_VS_PATH=%X64_PATH%\Microsoft Visual Studio SET X64_AV_PATH=%X64_PATH%\Application Verifier SET X64_SQL_PATH=%X64_PATH%\Microsoft SQL Server SET PD_PATH=%ROOT_PATH%\ProgramData SET PD_VS_PATH=%PD_PATH%\Microsoft\VisualStudio SET PD_PC_PATH=%PD_PATH%\Package Cache @echo =======link directory to %ROOT_PATH%=======: SET S_X86_SKD_PATH=C:\Program Files (x86)\Microsoft SDKs SET S_X86_VS_PATH=C:\Program Files (x86)\Microsoft Visual Studio SET S_X86_KITS_PATH=C:\Program Files (x86)\Windows Kits SET S_X86_AV_PATH=C:\Program Files (x86)\Application Verifier SET S_X64_AV_PATH=C:\Program Files\Application Verifier SET S_X64_SQL_PATH=C:\Program Files\Microsoft SQL Server SET S_PD_VS_PATH=C:\ProgramData\Microsoft\VisualStudio SET S_PD_PC_PATH=C:\ProgramData\Package Cache pause @echo =======setting visual studio environment=======: @echo =======check directory exist=======: if not exist %ROOT_PATH% ( echo &amp;#34;%ROOT_PATH%目录不存在，已创建该目录！&amp;#34; md &amp;#34;%ROOT_PATH%&amp;#34; ) if not exist %X86_PATH% ( echo &amp;#34;%X86_PATH%目录不存在，已创建该目录！&amp;#34; md &amp;#34;%X86_PATH%&amp;#34; ) if not exist %X86_VS_PATH% ( echo &amp;#34;%X86_VS_PATH%目录不存在，已创建该目录！&amp;#34; md &amp;#34;%X86_VS_PATH%&amp;#34; ) if not exist %X86_SDK_PATH% ( echo &amp;#34;%X86_SDK_PATH%目录不存在，已创建该目录！&amp;#34; md &amp;#34;%X86_SDK_PATH%&amp;#34; ) if not exist %X86_KITS_PATH% ( echo &amp;#34;%X86_KITS_PATH%目录不存在，已创建该目录！&amp;#34; md &amp;#34;%X86_KITS_PATH%&amp;#34; ) if not exist %X86_AV_PATH% ( echo &amp;#34;%X86_AV_PATH%目录不存在，已创建该目录！&amp;#34; md &amp;#34;%X86_AV_PATH%&amp;#34; ) if not exist %X64_PATH% ( echo &amp;#34;%X64_PATH%目录不存在，已创建该目录！&amp;#34; md &amp;#34;%X64_PATH%&amp;#34; ) if not exist %X64_AV_PATH% ( echo &amp;#34;%X64_AV_PATH%目录不存在，已创建该目录！&amp;#34; md &amp;#34;%X64_AV_PATH%&amp;#34; ) if not exist %X64_SQL_PATH% ( echo &amp;#34;%X64_SQL_PATH%目录不存在，已创建该目录！&amp;#34; md &amp;#34;%X64_SQL_PATH%&amp;#34; ) if not exist %PD_PATH% ( echo &amp;#34;%PD_PATH%目录不存在，已创建该目录！&amp;#34; md &amp;#34;%PD_PATH%&amp;#34; ) if not exist %PD_VS_PATH% ( echo &amp;#34;%PD_VS_PATH%目录不存在，已创建该目录！&amp;#34; md &amp;#34;%PD_VS_PATH%&amp;#34; ) if not exist %PD_PC_PATH% ( echo &amp;#34;%PD_PC_PATH%目录不存在，已创建该目录！&amp;#34; md &amp;#34;%PD_PC_PATH%&amp;#34; ) @echo =======link directory to %ROOT_PATH%=======: :: x86 link mklink /j &amp;#34;%S_X86_SKD_PATH%&amp;#34; &amp;#34;%X86_SDK_PATH%&amp;#34; mklink /j &amp;#34;%S_X86_VS_PATH%&amp;#34; &amp;#34;%X86_VS_PATH%&amp;#34; mklink /j &amp;#34;%S_X86_KITS_PATH%&amp;#34; &amp;#34;%X86_KITS_PATH%&amp;#34; mklink /j &amp;#34;%S_X86_AV_PATH%&amp;#34; &amp;#34;%X86_AV_PATH%&amp;#34; :: x64 link mklink /j &amp;#34;%S_X64_AV_PATH%&amp;#34; &amp;#34;%X64_AV_PATH%&amp;#34; mklink /j &amp;#34;%S_X64_SQL_PATH%&amp;#34; &amp;#34;%X64_SQL_PATH%&amp;#34; :: ProgramData link mklink /j &amp;#34;%S_PD_VS_PATH%&amp;#34; &amp;#34;%PD_VS_PATH%&amp;#34; mklink /j &amp;#34;%S_PD_PC_PATH%&amp;#34; &amp;#34;%PD_PC_PATH%&amp;#34; pause VS快捷键 快捷键 含义 Ctrl + k,Ctrl + f 自动格式化代码 Ctrl + k,Ctrl + c 注释代码 Ctrl + k,Ctrl + u 取消注释代码 F9 设置断点 F5 调试运行 Ctrl + F5 不调试运行 Ctrl + Shift + b 编译，不运行 F10 next调试 F11 step调试 调试 添加行号：工具&amp;ndash;》选项 &amp;ndash;》文本编辑器&amp;ndash;》C/C++ &amp;ndash;》行号</description>
    </item>
    <item>
      <title>ch01 变量和数据类型</title>
      <link>https://www.oomkill.com/ch01-parmeter-and-data-structrue/</link>
      <pubDate>Wed, 28 Sep 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch01-parmeter-and-data-structrue/</guid>
      <description>C语言关键字 [1] ==C语言有32个关键字==
auto：定义自动变量，主要是声明变量的生存周期 break, continue : break 语句在遇到最内层循环时立即终止。还用于终止 switch 语句。 case, switch, default：使用 switch 和 case 语句声明一个switch分支 char：用于声明character 类型的变量 const：声明常量 do&amp;hellip;while： double： double-precision 浮点数变量类型 float：single-precision 浮点数的变量类型 if, else：声明if/else 条件判断 enum：用于声明枚举类型 extern：关键字声明变量或函数在其声明的文件之外具有外部链接。 for：C 语言的三种循环之一，for循环 goto： 用于将程序的控制权转移到指定的标签 int：声明 integer 类型的变量 short, long, signed, unsigned：是类型修饰符，它们改变基本数据类型的含义以产生新类型。 short int： -32768 to 32767 long int： -2147483648 to 214743648 signed int： -32768 to 32767 unsigned int： 0 to 65535 return： 终止函数并返回值 sizeof：评估变量或常量的大小 register：创建比普通变量快得多的寄存器变量。 static：创建一个静态变量。静态变量的值持续到程序结束。 struct：用于声明结构体。结构体可以包含不同类型的变量。 typedef：用于将类型与标识符显式关联。 union：用于将不同类型的变量分组在一个名称下。 void：没有任何意义，函数修饰为没有返回值，参数修饰为没有参数 volatile：提醒编译器它后面所定义的变量随时都有可能改变 C语言控制语句 ==C语言有9种控制语句== (control statements)</description>
    </item>
    <item>
      <title>ch02 格式化与流程控制</title>
      <link>https://www.oomkill.com/ch02-control-statements-and-format/</link>
      <pubDate>Wed, 28 Sep 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch02-control-statements-and-format/</guid>
      <description>格式化 printf printf() 用于打印消息以及变量的值。
c 1 2 3 4 5 6 7 8 #include&amp;lt;stdio.h&amp;gt; int main() { int a = 24; printf(&amp;#34;Welcome! \n&amp;#34;); printf(&amp;#34;The value of a : %d&amp;#34;,a); getchar(); return 0; } sprintf sprintf() 不打印字符串，是将字符值和格式化结构一并存储在一个数组中。
c 1 2 3 4 5 6 7 8 9 10 11 12 13 int main() { char buffer[50]; int a = 10, b = 20, c; c = a + b; sprintf(buffer, &amp;#34;Sum of %d and %d is %d&amp;#34;, a, b, c); // The string &amp;#34;sum of 10 and 20 is 30&amp;#34; is stored // into buffer instead of printing on stdout printf(&amp;#34;%s&amp;#34;, buffer); return 0; } scanf 从标准输入读取用户输入的</description>
    </item>
    <item>
      <title>ch03 数组</title>
      <link>https://www.oomkill.com/ch03-array/</link>
      <pubDate>Wed, 28 Sep 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch03-array/</guid>
      <description>Array [1] 数组是由单个元素组成的一组数据类型的变量 数组的元素存储在连续的内存位置 声明数组时应提及数组的大小 数组的计数从0开始 数组为一位数组与多维数组 数组首元素的地址与数组地址相同 数组包含 int, float, char, double 数据类型 Declaration and Initialization 表达式 说明 int my_array1[20]; 指定大小，来声明一个有20个元素的int数组 char my_array2[5]; 指定大小，来声明一个有5个元素的char数组 int my_array[] = {100, 200, 300, 400, 500} 声明时初始化一个数组（编译器自动求数组元素个数） int my_array1[5] = {100, 200, 300, 400, 500}; 声明时初始化 int my_array2[5] = {100, 200, 300}; 声明时初始化（剩余未初始化的元素，默认 0 值） int my_array2[5] = {0}; 声明时初始化（声明一个全0值的数组） int arr[10]; arr[0] = 5;arr[1] = 6;arr[2] = 7; 声明数组并初始化值（这种方法为初始化部分的默认值为随机数） char str[] = &amp;ldquo;zhangsan&amp;rdquo; 声明一个字符串（字符串是一个char类型数组） Advantages and Disadvantages 缺点**：大小限制**：声明（定义）后是固定的大小，不能通过运行时改变其大小</description>
    </item>
    <item>
      <title>ch04 函数</title>
      <link>https://www.oomkill.com/ch04-function/</link>
      <pubDate>Wed, 28 Sep 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch04-function/</guid>
      <description>concept [1] 函数 (function) 是执行任务的语句块。
函数的作用：
提高代码的可重用性并减少冗余 代码模块化 代码易读性 使代码模块化 函数的分类 C语言中有两种类型的函数：
标准库函数：C中的内置函数，在头文件中定义 #include &amp;lt;stdio.h&amp;gt; 用户自定义函数：用户自定义的函数 #include &amp;quot;stdio.h&amp;quot; 函数三部曲 C语言中函数分为三个方面，声明(declaration)，定义(defining)，调用(calling)
声明 声明是让编译器知道函数的名称、参数信息、参数的返回值的类型。
c 1 (type) function_name({type args...}); 隐式声明(implicit) ：当在main之后定义的函数而未声明，默认编译器会做隐式声明。
ISO/IEC 9899:1990 中 关于函数声明的部分：
函数在调用前必须有一个可用的声明，如果没有被声明，则该函数默认被隐式声明，该隐式声明没有参数，返回值为int [2]
定义 C中函数定义的语法如下
c 1 2 3 4 return_type function_name(arg1, arg2, ... argn) { function body // 函数中要处理任务的逻辑 } return_type：函数返回值的数据类型 function_name：函数名 arg1, arg2, &amp;hellip;argn：参数列表（可选），定义传递给函数的数据类型、顺序和参数的数量。 function body：调用函数时任务处理和执行的语句 调用 调用是指要由编译器执行的函数，可以在任何部分调用
虚函数void 如果函数没有返回值，则使用关键字 void，主要用于两个方面：
打印具体信息供用户阅读的函数 引用参数，函数通常不是用于返回一个内容，而是修改引用参数的，无需返回值 void 关键字使用注意：
void仅用于限定函数返回值，函数参数，不可以修饰变量，因为无法对无类型的变量分配指针</description>
    </item>
    <item>
      <title>ch05 指针</title>
      <link>https://www.oomkill.com/ch05-pointer/</link>
      <pubDate>Wed, 28 Sep 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch05-pointer/</guid>
      <description>指针 指针声明 [1] 指针/指针变量 (pointer) 是用于存储地址的变量
使用 &amp;amp; 运算符 来访问变量的地址。例如
c 1 2 3 4 5 6 7 #include &amp;lt;stdio.h&amp;gt; void main() { int a = 100; printf(&amp;#34;%x&amp;#34;, &amp;amp;a); } 输出结果为 16进制的内存地址
c 1 61fe1c 使用地址运算符 * 可以从变量地址中获取变量的值，这个行为被称为间接引用/解引用(indirection/dereferencing)。例如：
c 1 2 3 4 5 6 7 8 9 #include &amp;lt;stdio.h&amp;gt; void main() { int a = 100; printf(&amp;#34;%d&amp;#34;, *(&amp;amp;a)); // 也可以写为，因为*与&amp;amp;优先级相同，从右到左的顺序，所以有没有()意思是相同的 printf(&amp;#34;%d&amp;#34;, *&amp;amp;a); } 输出结果为 100
指针变量 指针变量是指存储一个变量的地址的变量，可以使用符号 * 来修饰变量，定义语法为：</description>
    </item>
    <item>
      <title>ch06 内存布局</title>
      <link>https://www.oomkill.com/ch06-memory-layout/</link>
      <pubDate>Wed, 28 Sep 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch06-memory-layout/</guid>
      <description>Overview 在编写程序时包含任意指令如，已初始化和未初始化数据，局部变量，函数等都是用于动态分配内存的指令。当程序编译后（默认生成 x.out 文件）这是一个可执行的链接文件( Executable and linking format)。在执行时这些不组织成几部分，包含不同的内存分段 (segments)
ELF：这是系统中标准二进制格式，其一些功能包含，动态链接，动态加载，对程序运行时控制。
可以使用 size {ELF_file} 查看被分配的每个段的大小（Linux操作系统）；
dec 列给出的是这个程序 text + data + bss 段的总大小，用十进制表示 text 段是存储可执行命令的段 data 段包含所有初始化数据，全局与静态变量 BSS 段包含未初始化数据 bash 1 2 3 $ size 1 text data bss dec hex filename 1843 584 8 2435 983 1 Memory Layout in C [1] 在C语言中内存布局模型包含六个部分
命令行参数 (Command Line Arguments) 栈 (Stack) 堆 (Heap) 未初始化数据段 (Uninitialized Data Segment BSS) 已初始化数据段 (Initialized Data Segment) 文本/代码段 (Text/Code Segment) 这6部分结构可以再划分为两种类型：</description>
    </item>
    <item>
      <title>ch07 复合类型</title>
      <link>https://www.oomkill.com/ch07-composite-type/</link>
      <pubDate>Wed, 28 Sep 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch07-composite-type/</guid>
      <description>Overview C语言中复合类型 (composite type) 是指用户自定义类型，通常由多种元素组成的类型，其元素被紧密存储在内存中。C语言常见的复合类型有：
数组 字符串 结构体 联合类型 结构体 [1] 结构体 (structure) 是指用户定义的数据类型，允许将不同类型的多个元素组合在一起，来创建出更复杂的数据类型，类似于数组，但又区别于数组，数组只能保存同类型的元素，而结构体可以保存不同类型的元素。
定义 声明结构体的语法如下
c 1 2 3 4 5 6 struct structureName { dataType memberVariable1; datatype memberVariable2; ... } variable01, variable02...; 这里需要注意的一些地方：
struct是关键字，structureName定义的新数据类型，variable{}是作为使用 structureName 声明的新变量名 每个成员方法结尾都是 “;&amp;quot; 而不是逗号 ”,&amp;quot; 结构体不能递归 变量可以有多个 例如声明一个学生的结构体，而student是作为一个新的数据类型存在
c 1 2 3 4 5 6 struct student { char name[20]; int roll; char gender; }; Notes：在定义（创建）结构体变量前，结构体成员不会占用内存
声明 使用结构体声明变量
也可以一次性定义结构体和声明变量
c 1 2 3 4 5 6 7 8 9 10 11 12 13 struct student { char name[20]; int roll; char gender; } stu1,stu2; // 结构体名称可以省略 struct { char name[20]; int roll; char gender; } stu1,stu2; 赋值 在声明结构体后，student结构体只是自定义数据结构，要使用还需要进行初始化，或者赋值</description>
    </item>
    <item>
      <title>ch08 文件处理</title>
      <link>https://www.oomkill.com/ch08-file-handling/</link>
      <pubDate>Wed, 28 Sep 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch08-file-handling/</guid>
      <description>文件类型 文件是指以字节的形式存储的数据源，使用C语言将文件数据以输出输出的形式处理叫做文件处理。
文件在C语言中以两种形式存在：
文本文件：文本文件是简单的文件类型，这些文件内容以 ASCII 字符格式存储信息。 二进制文件：二进制文件以 0 和 1 的二进制格式存储数据，不是人类可读的文件 文件指针 文件指针 (FILE) 是一种数据类型，是被定义在 stdio.h 中的一种结构体，包含了文件的一些信息
c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 typedef struct { // fill/empty level of buffer int level; // File status flags unsigned flags; // File descripter char fd; // ungetc char if no buffer unsigned char hold; // buffer size int bsize; // data transfer buffer unsigned char *buffer; // Current active pointer unsigned char *curp; //Temporary file indicator unsigned istemp; //Used for validity checking short token; } FILE; // This is FILE object 文件指针通常被用于处理正在访问的文件，fopen() 是用于打开文件并返回文件的 FILE 指针，而后通过文件只恨进行I/O操作。fopen() 会发生下列事件：</description>
    </item>
    <item>
      <title>漏桶算法与令牌桶算法</title>
      <link>https://www.oomkill.com/ch10-token-bucket-algorithm/</link>
      <pubDate>Sun, 28 Aug 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch10-token-bucket-algorithm/</guid>
      <description>Principle of token bucket 随着互联网的发展，在处理流量的方法也不仅仅为 first-come，first-served，而在共享网络中实现流量管理的基本机制就是排队。而公平算法则是实现在优先级队列中基于哪些策略来排队的 “公平队列” 。Token Bucket 则是为公平排队提供了替代方案。Fair Queue 与 Token Bucket的区别主要在，对于Fair Queue来讲，如果请求者目前空闲，Queue会将该请求者的带宽分配给其他请求者；而 Token Bucket 则是分配给请求者的带宽是带宽的上限。
通过例子了解算法原理
假设出站带宽是 4个数据包/ms，此时有一个需求为，为一个特定的发送端 A 来分配 1个数据包/ms的带宽。此时可以使用公平排队的方法分给发送 A 25%的带宽。
此时存在的问题是我们希望可以灵活地允许 A 的数据包以无规则的时间间隔发送。例如假设 A 在每个数据包发送后等待1毫秒后再开始下一个数据包的发送。
sence1：此时假设 A 以 1ms 的间隔去发送数据包，而由于某种原因导致应该在 t=6 到达的数据包却在 t=6.5 到达。随后的数据包在 t=7 准时到达，在这种情况下是否应该保留到t=7.5？ sence2：或者是否允许在 t=6.5 发送一个迟到的数据包，在 t=7 发送下一个数据包，此时理论上平均速率仍然还是 1 个数据包/ms？ 显然sence2是合理的，这个场景的解决方法就是令牌桶算法，规定 A 的配额，允许指定平均速率和突发容量。当数据包不符合令牌桶规范，那么就认为其不合理，此时会做出一下相应：
delay，直到桶准备好 drop mark，标记为不合规的数据包 delay 被称为 整形 shaping , shaping 是指在某个时间间隔内发送超过 Bc（Committed Burst）的大小，Bc 在这里指桶的尺寸。由于数据流量是突发性的，当在一段时间内不活动后，再次激活后的在一个间隔内发送的数量大于 Bc ，那么额外的流量被称为Be （burst excess）。
将流量丢弃或标记超额流量，保持在一个流量速率限制称为 “管制” policing。</description>
    </item>
    <item>
      <title>Kubernetes Pod网络排错思路</title>
      <link>https://www.oomkill.com/pod-network-troubleshooting/</link>
      <pubDate>Wed, 17 Aug 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/pod-network-troubleshooting/</guid>
      <description>本文是关于深入理解Kubernetes网络原理系列第4章 深入理解Kubernetes Pod网络原理 - 网络名称空间 深入理解Kubernetes Pod网络原理 - Linux虚拟网络技术 深入理解Kubernetes Pod网络原理 - CNI 深入理解Kubernetes Pod网络原理 - 跟随 flannel 学习CNI原理 深入理解Kubernetes Pod网络原理 - 跟随 flannel + multus 剖析 Chained Plugins 深入理解Kubernetes Pod网络原理 - 从零实现一个 CNI Plugin part 1 (Shell) 深入理解Kubernetes Pod网络原理 - 从零实现一个 CNI Plugin part 2 (libcni) 深入理解Kubernetes Pod网络原理 - Kubernetes网络模型 1 深入理解Kubernetes Pod网络原理 - Kubernetes网络模型 2 深入理解Kubernetes Pod网络原理 - Pod网络排错思路 Overview 本文将引入一个思路：“在Kubernetes集群发生网络异常时如何排查”。文章将引入Kubernetes 集群中网络排查的思路，包含网络异常模型，常用工具，并且提出一些案例以供学习。
Pod常见网络异常分类 网络排查工具 Pod网络异常排查思路及流程模型 CNI网络异常排查步骤 案例学习 Pod网络异常 网络异常大概分为如下几类：</description>
    </item>
    <item>
      <title>深入理解Kubernetes Pod网络原理 - Kubernetes网络模型 1</title>
      <link>https://www.oomkill.com/kubernetes-network-model-part1/</link>
      <pubDate>Wed, 17 Aug 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-network-model-part1/</guid>
      <description>本文是关于深入理解Kubernetes网络原理系列第4章 深入理解Kubernetes Pod网络原理 - 网络名称空间 深入理解Kubernetes Pod网络原理 - Linux虚拟网络技术 深入理解Kubernetes Pod网络原理 - CNI 深入理解Kubernetes Pod网络原理 - 跟随 flannel 学习CNI原理 深入理解Kubernetes Pod网络原理 - 跟随 flannel + multus 剖析 Chained Plugins 深入理解Kubernetes Pod网络原理 - 从零实现一个 CNI Plugin part 1 (Shell) 深入理解Kubernetes Pod网络原理 - 从零实现一个 CNI Plugin part 2 (libcni) 深入理解Kubernetes Pod网络原理 - Kubernetes网络模型 1 深入理解Kubernetes Pod网络原理 - Kubernetes网络模型 2 深入理解Kubernetes Pod网络原理 - Pod网络排错思路 概述 本文将简述探讨 Kubernetes 中常见的网络模型，以及对这些网络模型的 route path 进行分析。本章节是作为CNI 原理的前置条件，也为后续的练习提供一些基础知识。</description>
    </item>
    <item>
      <title>基于Prometheus的Kubernetes网络调度器</title>
      <link>https://www.oomkill.com/ch22-custom-scheduler/</link>
      <pubDate>Mon, 08 Aug 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch22-custom-scheduler/</guid>
      <description>Overview 本文将深入讲解 如何扩展 Kubernetes scheduler 中各个扩展点如何使用，与扩展scheduler的原理，这些是作为扩展 scheduler 的所需的知识点。最后会完成一个实验，基于网络流量的调度器。
kubernetes调度配置 kubernetes集群中允许运行多个不同的 scheduler ，也可以为Pod指定不同的调度器进行调度。在一般的Kubernetes调度教程中并没有提到这点，这也就是说，对于亲和性，污点等策略实际上并没有完全的使用kubernetes调度功能，在之前的文章中提到的一些调度插件，如基于端口占用的调度 NodePorts 等策略一般情况下是没有使用到的，本章节就是对这部分内容进行讲解，这也是作为扩展调度器的一个基础。
Scheduler Configuration [1] kube-scheduler 提供了配置文件的资源，作为给 kube-scheduler 的配置文件，启动时通过 --onfig= 来指定文件。目前各个kubernetes版本中使用的 KubeSchedulerConfiguration 为，
1.21 之前版本使用 v1beta1 1.22 版本使用 v1beta2 ，但保留了 v1beta1 1.23, 1.24, 1.25 版本使用 v1beta3 ，但保留了 v1beta2，删除了 v1beta1 下面是一个简单的 kubeSchedulerConfiguration 示例，其中 kubeconfig 与启动参数 --kubeconfig 是相同的功效。而 kubeSchedulerConfiguration 与其他组件的配置文件类似，如 kubeletConfiguration 都是作为服务启动的配置文件。
yaml 1 2 3 4 apiVersion: kubescheduler.config.k8s.io/v1beta1 kind: KubeSchedulerConfiguration clientConnection: kubeconfig: /etc/srv/kubernetes/kube-scheduler/kubeconfig Notes: --kubeconfig 与 --config 是不可以同时指定的，指定了 --config 则其他参数自然失效 [2]</description>
    </item>
    <item>
      <title>如何理解kubernetes调度框架与插件？</title>
      <link>https://www.oomkill.com/ch21-scheduling-algorithm/</link>
      <pubDate>Wed, 27 Jul 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch21-scheduling-algorithm/</guid>
      <description>调度框架 [1] 本文基于 kubernetes 1.24 进行分析
调度框架（Scheduling Framework）是Kubernetes 的调度器 kube-scheduler 设计的的可插拔架构，将插件（调度算法）嵌入到调度上下文的每个扩展点中，并编译为 kube-scheduler
在 kube-scheduler 1.22 之后，在 pkg/scheduler/framework/interface.go 中定义了一个 Plugin 的 interface，这个 interface 作为了所有插件的父级。而每个未调度的 Pod，Kubernetes 调度器会根据一组规则尝试在集群中寻找一个节点。
go 1 2 3 type Plugin interface { Name() string } 下面会对每个算法是如何实现的进行分析
在初始化 scheduler 时，会创建一个 profile，profile是关于 scheduler 调度配置相关的定义
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 func New(client clientset.Interface, .</description>
    </item>
    <item>
      <title>kube-scheduler的调度上下文</title>
      <link>https://www.oomkill.com/ch20-schedule-workflow/</link>
      <pubDate>Thu, 21 Jul 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch20-schedule-workflow/</guid>
      <description>Scheduler Scheduler 是整个 kube-scheduler 的一个 structure，提供了 kube-scheduler 运行所需的组件。
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 type Scheduler struct { // Cache是一个抽象，会缓存pod的信息，作为scheduler进行查找，操作是基于Pod进行增加 Cache internalcache.Cache // Extenders 算是调度框架中提供的调度插件，会影响kubernetes中的调度策略 Extenders []framework.Extender // NextPod 作为一个函数提供，会阻塞获取下一个ke&amp;#39;diao&amp;#39;du NextPod func() *framework.QueuedPodInfo // Error is called if there is an error. It is passed the pod in // question, and the error Error func(*framework.</description>
    </item>
    <item>
      <title>kubernetes的决策组件 - kube-scheduler原理分析</title>
      <link>https://www.oomkill.com/ch16-scheduler/</link>
      <pubDate>Mon, 18 Jul 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch16-scheduler/</guid>
      <description>Overview [1] kubernetes集群中的调度程序 kube-scheduler 会 watch 未分配节点的新创建的Pod，并未该Pod找到可运行的最佳（特定）节点。那么这些动作或者说这些原理是怎么实现的呢，让我们往下剖析下。
对于新创建的 pod 或其他未调度的 pod来讲，kube-scheduler 选择一个最佳节点供它们运行。但是，Pod 中的每个容器对资源的要求都不同，每个 Pod 也有不同的要求。因此，需要根据具体的调度要求对现有节点进行过滤。
在Kubernetes集群中，满足 Pod 调度要求的节点称为可行节点 （ feasible nodes FN） 。如果没有合适的节点，则 pod 将保持未调度状态，直到调度程序能够放置它。也就是说，当我们创建Pod时，如果长期处于 Pending 状态，这个时候应该看你的集群调度器是否因为某些问题没有合适的节点了
调度器为 Pod 找到 FN 后，然后运行一组函数对 FN 进行评分，并在 FN 中找到得分最高的节点来运行 Pod。
调度策略在决策时需要考虑的因素包括个人和集体资源需求、硬件/软件/策略约束 （constraints）、亲和性 (affinity) 和反亲和性（ anti-affinity ）规范、数据局部性、工作负载间干扰等。
如何为pod选择节点？ kube-scheduler 为pod选择节点会分位两部：
过滤 (Filtering) 打分 (Scoring) 过滤也被称为预选 （Predicates），该步骤会找到可调度的节点集，然后通过是否满足特定资源的请求，例如通过 PodFitsResources 过滤器检查候选节点是否有足够的资源来满足 Pod 资源的请求。这个步骤完成后会得到一个包含合适的节点的列表（通常为多个），如果列表为空，则Pod不可调度。
打分也被称为优选（Priorities），在该步骤中，会对上一个步骤的输出进行打分，Scheduer 通过打分的规则为每个通过 Filtering 步骤的节点计算出一个分数。
完成上述两个步骤之后，kube-scheduler 会将Pod分配给分数最高的 Node，如果存在多个相同分数的节点，会随机选择一个。
kubernetes的调度策略 Kubernetes 1.21之前版本可以在代码 kubernetes\pkg\scheduler\algorithmprovider\registry.go 中看到对应的注册模式，在1.22 scheduler 更换了其路径，对于registry文件更换到了kubernetes\pkg\scheduler\framework\plugins\registry.go ；对于kubernetes官方说法为，调度策略是用于“预选” (Predicates )或 过滤（filtering ） 和 用于 优选（Priorities）或 评分 (scoring)的</description>
    </item>
    <item>
      <title>深入理解Kubernetes 4A - Admission Control源码解析</title>
      <link>https://www.oomkill.com/ch33-admission-webhook/</link>
      <pubDate>Mon, 11 Jul 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch33-admission-webhook/</guid>
      <description>本文是关于Kubernetes 4A解析的第3章 深入理解Kubernetes 4A - Authentication源码解析 深入理解Kubernetes 4A - Authorization源码解析 深入理解Kubernetes 4A - Admission Control源码解析 深入理解Kubernetes 4A - Audit源码解析 TLS Everywhere - 解密kubernetes集群的安全认证 所有关于Kubernetes 4A部分代码上传至仓库 github.com/cylonchau/hello-k8s-4A
如有错别字或理解错误地方请多多担待，代码是以1.24进行整理，实验是以1.19环境进行，差别不大
BACKGROUND admission controllers的特点：
可定制性：准入功能可针对不同的场景进行调整。 可预防性：审计则是为了检测问题，而准入控制器可以预防问题发生 可扩展性：在kubernetes自有的验证机制外，增加了另外的防线，弥补了RBAC仅能对资源提供安全保证。 下图，显示了用户操作资源的流程，可以看出 admission controllers 作用是在通过身份验证资源持久化之前起到拦截作用。在准入控制器的加入会使kubernetes增加了更高级的安全功能。
图：Kubernetes API 请求的请求处理步骤图 Source：https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/ 这里找到一个大佬博客画的图，通过两张图可以很清晰的了解到admission webhook流程，与官方给出的不一样的地方在于，这里清楚地定位了kubernetes admission webhook 处于准入控制中，RBAC之后，push 之前。
图：Kubernetes API 请求的请求处理步骤图（详细） Source：https://www.armosec.io/blog/kubernetes-admission-controller/ 两种控制器有什么区别？ 根据官方提供的说法是
Mutating controllers may modify related objects to the requests they admit; validating controllers may not
从结构图中也可以看出，validating 是在持久化之前，而 Mutating 是在结构验证前，根据这些特性我们可以使用 Mutating 修改这个资源对象内容（如增加验证的信息），在 validating 中验证是否合法。</description>
    </item>
    <item>
      <title>如何为visio扩展云服务图标</title>
      <link>https://www.oomkill.com/visio-custom-icon/</link>
      <pubDate>Wed, 06 Jul 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/visio-custom-icon/</guid>
      <description>各个云厂商都会为自己的服务提供通用可缩放矢量图形 (SVG) 图标，以便用户为自己的软件绘制架构图，例如Microsoft 为Visio 提供 Azure 服务的图标。文本在这里简单整理了几个关于云服务的图标
Azure-Design 提供了大量并完整的azure的一些图标 AWS-Architecture-Icons 提供了一些关于AWS的图标，不过图标为2019年时的 Microsoft-Integration-and-Azure 整合了一些关于微软的图标，并附带了矢量图 更多的图标可以在github或google搜索相关关键词 visio stencil 网络上还是有很多相关的图标库
将图标导入到visio中 为了能使下载的图标在Visio 中可用，只需要简单的一个步骤即可。
将下载下来的图标放置到 C:\Users\&amp;lt;UserName&amp;gt;\Documents\My Shapes 中文系统为 用户目录\文档\我的图形 我的图形需要安装visio后才会有这个文件夹
如图所示：
测试导入后的效果，我们在这里导入了aws与azure的图标库，故可以看到有两个，但是两个中又包含很多，已经足够使用了
最后再附上一个大神制作的 VISIO Protable 版本，匿名网盘，失效不补</description>
    </item>
    <item>
      <title>使nginx支持分布式追踪</title>
      <link>https://www.oomkill.com/opentracing-nginx/</link>
      <pubDate>Sat, 02 Jul 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/opentracing-nginx/</guid>
      <description>Background NGINX 是一个通用且流行的应用程序。也是最流行的 Web 服务器，它可用于提供静态文件内容，但也通常与其他服务一起用作分布式系统中的组件，在其中它用作反向代理、负载均衡 或 API 网关。
分布式追踪 distributed tracing 是一种可用于分析与监控应用程序的机制，将追踪在从源到目的的整个过程中的单个请求，这与仅通过单个应用程序域来追踪请求的形式不同。
换句话说，我们可以说分布式追踪是对跨多个系统的多个请求的拼接。拼接通常由一个或多个相关 ID 完成，并且跟踪通常是一组记录的、跨所有系统的结构化日志事件，存储在一个中心位置。
在这种背景的情况下， OpenTracing 应运而生。OpenTracing 是一个与应用供应商无关的 API，它可帮助开发人员轻松地跟踪单一请求的域。目前有多种开源产品都支持 OpenTracing（例如，Jaeger, skywalking 等），并将其作为一种检测分布式追踪的标准化方法。
本文将围绕，从0到1实现在nginx配置分布式追踪的架构的简单实例说明。本文实例使用的组件为
nginx v1.22 jaeger-all-in-on v1.38 nginx-opentracing v1.22 jaeger-client-cpp v0.9 源码构建nginx-opentracing 准备nginx-opentracing nginx-opentracing 仓库中可以看到，官方为每个nginx版本都提供了一个编译好的动态库（Nginx1.19.13+），我们可以直接拿来使用这个动态库，如果你想将这个利用Nginx 提供的编译参数 --add-module=/path/to/module 构建为nginx的内置功能的话，可能会出现一些问题，例如下面的一些错误：
text 1 ngx_http_opentracing_module.so/config was found bash 1 2 3 /root/nginx-opentracing-0.25.0/opentracing//src/ngx_http_opentracing_module.cpp In file included from /root/nginx-opentracing-0.25.0/opentracing//src/ngx_http_opentracing_module.cpp:1:0: /root/nginx-opentracing-0.25.0/opentracing//src/load_tracer.h:3:38: fatal error: opentracing/dynamic_load.h: No such file or directory 根据 issue 中查询得知 nginx-opentracing 需要嵌入到nginx中，是需要一些 opentracing-cpp 因为对c++不熟，尝试调试很久还是上面的错误，故直接使用了官方提供的动态库。</description>
    </item>
    <item>
      <title>利用kubernetes中的leader选举机制自定义HA应用</title>
      <link>https://www.oomkill.com/ch28-leader-election-eg/</link>
      <pubDate>Wed, 29 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch28-leader-election-eg/</guid>
      <description>Backgroud 前一章中，对kubernetes的选举原理进行了深度剖析，下面就通过一个example来实现一个，利用kubernetes提供的选举机制完成的高可用应用。
对于此章需要提前对一些概念有所了解后才可以继续看下去
leader election mechanism RBCA Pod runtime mechanism Implementation 代码实现 如果仅仅是使用Kubernetes中的锁，实现的代码也只有几行而已。
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 package main import ( &amp;#34;context&amp;#34; &amp;#34;flag&amp;#34; &amp;#34;fmt&amp;#34; &amp;#34;os&amp;#34; &amp;#34;os/signal&amp;#34; &amp;#34;syscall&amp;#34; &amp;#34;time&amp;#34; metav1 &amp;#34;k8s.</description>
    </item>
    <item>
      <title>源码分析Kubernetes HA机制 - leader election</title>
      <link>https://www.oomkill.com/ch27-leader-election/</link>
      <pubDate>Tue, 28 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch27-leader-election/</guid>
      <description>Overview 在 Kubernetes的 kube-controller-manager , kube-scheduler, 以及使用 Operator 的底层实现 controller-rumtime 都支持高可用系统中的leader选举，本文将以理解 controller-rumtime （底层的实现是 client-go） 中的leader选举以在kubernetes controller中是如何实现的。
Background 在运行 kube-controller-manager 时，是有一些参数提供给cm进行leader选举使用的，可以参考官方文档提供的 参数 来了解相关参数。
bash 1 2 3 4 5 6 7 --leader-elect Default: true --leader-elect-renew-deadline duration Default: 10s --leader-elect-resource-lock string Default: &amp;#34;leases&amp;#34; --leader-elect-resource-name string Default: &amp;#34;kube-controller-manager&amp;#34; --leader-elect-resource-namespace string Default: &amp;#34;kube-system&amp;#34; --leader-elect-retry-period duration Default: 2s ... 本身以为这些组件的选举动作时通过etcd进行的，但是后面对 controller-runtime 学习时，发现并没有配置其相关的etcd相关参数，这就引起了对选举机制的好奇。怀着这种好奇心搜索了下有关于 kubernetes的选举，发现官网是这么介绍的，下面是对官方的说明进行一个通俗总结。simple leader election with kubernetes
通过阅读文章得知，kubernetes API 提供了一中选举机制，只要运行在集群内的容器，都是可以实现选举功能的。
Kubernetes API通过提供了两个属性来完成选举动作的
ResourceVersions：每个API对象唯一一个ResourceVersion Annotations：每个API对象都可以对这些key进行注释 注：这种选举会增加APIServer的压力。也就对etcd会产生影响</description>
    </item>
    <item>
      <title>源码分析Kubernetes controller组件 - controller-runtime</title>
      <link>https://www.oomkill.com/ch15-controller-runtime/</link>
      <pubDate>Mon, 27 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch15-controller-runtime/</guid>
      <description>Overview controller-runtime 是 Kubernetes 社区提供可供快速搭建一套 实现了controller 功能的工具，无需自行实现Controller的功能了；在 Kubebuilder 与 Operator SDK 也是使用 controller-runtime 。本文将对 controller-runtime 的工作原理以及在不同场景下的使用方式进行简要的总结和介绍。
controller-runtime structure controller-runtime 主要组成是需要用户创建的 Manager 和 Reconciler 以及 Controller Runtime 自己启动的 Cache 和 Controller 。
Manager：是用户在初始化时创建的，用于启动 Controller Runtime 组件 Reconciler：是用户需要提供来处理自己的业务逻辑的组件（即在通过 code-generator 生成的api-like而实现的controller中的业务处理部分）。 Cache：一个缓存，用来建立 Informer 到 ApiServer 的连接来监听资源并将被监听的对象推送到queue中。 Controller： 一方面向 Informer 注册 eventHandler，另一方面从队列中获取数据。controller 将从队列中获取数据并执行用户自定义的 Reconciler 功能。 图：controller-runtime structure 图：controller-runtime flowchart 由图可知，Controller会向 Informer 注册一些列eventHandler；然后Cache启动Informer（informer属于cache包中），与ApiServer建立监听；当Informer检测到资源变化时，将对象加入queue，Controller 将元素取出并在用户端执行 Reconciler。
Controller引入 我们从 controller-rumtime项目的 example 进行引入看下，整个架构都是如何实现的。
可以看到 example 下的实际上实现了一个 reconciler 的结构体，实现了 Reconciler 抽象和 Client 结构体</description>
    </item>
    <item>
      <title>扩展Kubernetes API的另一种方式 - APIServer aggregation</title>
      <link>https://www.oomkill.com/ch04-apiserver-aggregation/</link>
      <pubDate>Wed, 22 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch04-apiserver-aggregation/</guid>
      <description>Overview What is Kubernetes aggregation Kubernetes apiserver aggregation AA 是Kubernetes提供的一种扩展API的方法，目前并没有GA
Difference between CRD and AA 众所周知，kubernetes扩展API的方法大概为三种：CRD、AA、手动扩展源码。根据CNCF分享中Min Kim说的AA更关注于实践，而用户无需了解底层的原理，这里使用过 kubebuilder， code-generator 的用户是很能体会到这点。官方也给出了CRD与AA的区别
API Access Control Authentication CR: All strategies supported. Configured by root apiserver. AA: Supporting all root apiserver&amp;rsquo;s authenticating strategies but it has to be done via authentication token review api except for authentication proxy which will cause an extra cost of network RTT. Authorization CR: All strategies supported. Configured by root apiserver.</description>
    </item>
    <item>
      <title>kubernetes代码生成器 - code-generator</title>
      <link>https://www.oomkill.com/ch14-code-generator/</link>
      <pubDate>Mon, 20 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch14-code-generator/</guid>
      <description>Overview Kubernetes中提供了多种自定义控制器的方式：
code-generator kubebuilder Operator Controller 作为CRD的核心，这里将解释如何使用 code-generator 来创建自定义的控制器，作为文章的案例，将完成一个 Firewalld Port 规则的控制器作为描述，通过 Kubernetes 规则来生成对应节点上的 iptables规则。
Prerequisites CRD yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: ports.firewalld.fedoraproject.org spec: group: firewalld.fedoraproject.org scope: Namespaced names: plural: ports singular: port kind: PortRule shortNames: - fp versions: - name: v1 served: true storage: true schema: openAPIV3Schema: type: object properties: spec: type: object properties: name: type: string port: type: integer host: type: string isPermanent: type: boolean code-generator 需要预先下载 code-generator 。因为这个工具不是必需要求的。</description>
    </item>
    <item>
      <title>手写一个kubernetes controller</title>
      <link>https://www.oomkill.com/ch12-controller/</link>
      <pubDate>Mon, 20 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch12-controller/</guid>
      <description>Overview 根据Kuberneter文档对Controller的描述，Controller在kubernetes中是负责协调的组件，根据设计模式可知，controller会不断的你的对象（如Pod）从当前状态与期望状态同步的一个过程。当然Controller会监听你的实际状态与期望状态。
Writing Controllers go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 package main import ( &amp;#34;flag&amp;#34; &amp;#34;fmt&amp;#34; &amp;#34;os&amp;#34; &amp;#34;time&amp;#34; v1 &amp;#34;k8s.</description>
    </item>
    <item>
      <title>使用CRD扩展Kubernetes API</title>
      <link>https://www.oomkill.com/ch13-crd/</link>
      <pubDate>Sun, 19 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch13-crd/</guid>
      <description>Kubernetes的主节点或控制面板当中主要有三个组件，其中apiserver是整个系统的数据库，借助于Cluster Store（etcd）服务，来实现所有的包括用户所期望状态的定义，以及集群上资源当前状态的实时记录等。
etcd是分布式通用的K/V系统 KV Store ，可存储用户所定义的任何由KV Store所支持的可持久化的数据。它不仅仅被apiserver所使用，如flannel、calico二者也需要以etcd来保存当前应用程序对应的存储数据。 任何一个分布式应用程序几乎都会用到一个高可用的存储系统。
apiserver将etcd所提供的存储接口做了高度抽象，使用户通过apiserver来完成数据存取时，只能使用apiserver中所内建支持的数据范式。在某种情况之下，我们所期望管理的资源或存储对象在现有的Kubernetes资源无法满足需求时。
Operator本身是建构在StatefulSet以及本身的基本Kubernetes资源之上，由开发者自定义的更高级的、更抽象的自定义资源类型。他可借助于底层的Pod、Service功能，再次抽象出新资源类型。更重要的是，整个集群本身可抽象成一个单一资源。
为了实现更高级的资源管理，需要利用已有的基础资源类型，做一个更高级的抽象，来定义成更能符合用户所需要的、可单一管理的资源类型，而无需去分别管理每一个资源。
在Kubernetes之上自定义资源一般被称为扩展Kubernetes所支持的资源类型，
自定义资源类型 CRD Custom Resource Definition 自定义apiserver 修改APIServer源代码，改动内部的资源类型定义 CRD是kubernetes内建的资源类型，从而使得用户可以定义的不是具体的资源，而是资源类型，也是扩展Kubernetes最简单的方式。
Intorduction CRD 什么是CRD 在 Kubernetes API 中，resources 是存储 API 对象集合的endpoint。例如，内置 Pod resource 包含 Pod 对象的集合。当我们想扩展API，原生的Kubernetes就不能满足我们的需求了，这时 CRD (CustomResourceDefinition) 就出现了。在 Kubernetes 中创建了 CRD 后，就可以像使用任何其他原生 Kubernetes 对象一样使用它，从而利用 Kubernetes 的所有功能、如安全性、API 服务、RBAC 等。
Kubernetes 1.7 之后增加了对 CRD 自定义资源二次开发能力来扩展 Kubernetes API，通过 CRD 我们可以向 Kubernetes API 中增加新资源类型，而不需要修改 Kubernetes 源码来创建自定义的 API server，该功能大大提高了 Kubernetes 的扩展能力。
创建 CRD 前提条件： Kubernetes 服务器版本必须不低于版本 1.</description>
    </item>
    <item>
      <title>OSI模型与IP协议</title>
      <link>https://www.oomkill.com/osi-network-basics/</link>
      <pubDate>Sat, 18 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/osi-network-basics/</guid>
      <description>OSI Model OSI 七层网络模型如下（由下到上）：
应用层 Application layer ：直接接触用户数据的层。软件应用程序依靠应用层发起通信。这里的应用值得是协议而不是客户端软件；应用层协议包括 HTTP, SMTP, FTP, DNS,Telnet, etc.. 表示层 Presentation layer：表示层充当角色为网络数据转换器，负责完成数据转换，加密和压缩 会话层 Session layer：负责建立、管理和终止两个设备之间的通信 传输层 Transport layer：负责两个设备间的端到端通信。包括从会话层提取数据，将数据分解为多个区块（称为数据段）；传输层协议包括，TCP, UDP 网络层 Network layer：负责管理网络地址，定位设备，决定路由，通俗来讲是负责*&amp;ldquo;不同&amp;rdquo;*网络之间的传输，也就是路由功能；网络层协议包括 IP,ARP,ICMP；代表设备 3 layer swtich, router, firewall。相应就代表对应网络协议也是三层的，如RIP, OSPF, BGP 数据链路层 Data link layer：数据链路层负责*&amp;ldquo;同一&amp;rdquo;*网络上设备之间的数据传输；该层协议包括 Ethernet, PPP(Point-to-Point Protocol)；代表设备 Switch,Bridges，同样的MAC地址也是该层的 物理层 Physical layer：该层表示参与数据传输的物理设备，如网线，同时还负责将数据转换为位流，也就是由 1 和 0 构成的字符串。 图：OSI七层模型 Source：https://www.cloudflare.com/zh-cn/learning/ddos/glossary/open-systems-interconnection-model-osi/ MAC MAC地址介绍 MAC (Media Access Control) 地址用来定义网络设备的位置，由48比特长，12位的16进制组成，其中从左到右，0-23bit为厂商想IETF等机构申请用来标识厂商的代码OUI Organizationally-Unique Identifier，24-47bit由厂商自行分配，是厂商制造所有网卡的唯一编号。如00-50-56-C0-00-08
MAC地址类型 MAC地址分为三种类型：
物理MAC地址：Mac地址唯一的标识了以太网的一个终端，该地址为全球唯一的硬件地址。 广播(broadcast) MAC地址：每个比特都是 1 的 MAC 地址。广播 MAC 地址是组播 MAC 地址的一个特例。11111111-11111111-11111111-11111111-11111111-11111111 16进制表示为 FF-FF-FF-FF-FF-FF。 组播(multicast) MAC地址：第一个字节的最低位是 1 的 MAC 地址。二进制表示为 xxxxxxx1-xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx ；16进制表示为01-00-00-00-00-00。如 a5-a9-a6-aa-5a-a6 这个mac地址的第一个字节的最低位 16进制a5 转换为二进制为10100101 最后一位为1就是组播MAC地址。 单播 (unicast) MAC 地址：第一个字节的最低位是 0 的 MAC 地址 xxxxxxx0-xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx。 静态MAC地址 由用户通过命令配置的静态转发的MAC地址，静态MAC地址和动态MAC地址的功能不同，静态地址一旦被加入，该地址在删除之前将一直有效，不受最大老化时间的限制</description>
    </item>
    <item>
      <title>源码分析client-go架构 - queue</title>
      <link>https://www.oomkill.com/ch09-queue/</link>
      <pubDate>Fri, 17 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch09-queue/</guid>
      <description>通用队列 在kubernetes中，使用go的channel无法满足kubernetes的应用场景，如延迟、限速等；在kubernetes中存在三种队列通用队列 common queue ，延迟队列 delaying queue，和限速队列 rate limiters queue
Inferface Interface作为所有队列的一个抽象定义
go 1 2 3 4 5 6 7 8 type Interface interface { Add(item interface{}) Len() int Get() (item interface{}, shutdown bool) Done(item interface{}) ShutDown() ShuttingDown() bool } Implementation go 1 2 3 4 5 6 7 8 9 10 11 12 13 type Type struct { // 一个work queue queue []t // queue用slice做存储 dirty set // 脏位，定义了需要处理的元素，类似于操作系统，表示已修改但为写入 processing set // 当前正在处理的元素集合 cond *sync.</description>
    </item>
    <item>
      <title>KNN算法</title>
      <link>https://www.oomkill.com/knn/</link>
      <pubDate>Wed, 01 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/knn/</guid>
      <description>Overview K近邻值算法 KNN (K — Nearest Neighbors) 是一种机器学习中的分类算法；K-NN是一种非参数的惰性学习算法。非参数意味着没有对基础数据分布的假设，即模型结构是从数据集确定的。
它被称为惰性算法的原因是，因为它**不需要任何训练数据点来生成模型。**所有训练数据都用于测试阶段，这使得训练更快，测试阶段更慢且成本更高。
如何工作 KNN 算法是通过计算新对象与训练数据集中所有对象之间的距离，对新实例进行分类或回归预测。然后选择训练数据集中距离最小的 K 个示例，并通过平均结果进行预测。
如图所示：一个未分类的数据（红色）和所有其他已分类的数据（黄色和紫色），每个数据都属于一个类别。因此，计算未分类数据与所有其他数据的距离，以了解哪些距离最小，因此当K= 3 （或K= 6 ）最接近的数据并检查出现最多的类，如下图所示，与新数据最接近的数据是在第一个圆圈内（圆圈内）的数据，在这个圆圈内还有 3 个其他数据（已经用黄色分类），我们将检查其中的主要类别，会被归类为紫色，因为有2个紫色球，1个黄色球。
KNN算法要执行的步骤 将数据分为训练数据和测试数据 选择一个值 K 确定要使用的距离算法 从需要分类的测试数据中选择一个样本，计算到它的 n 个训练样本的距离。 对获得的距离进行排序并取 k最近的数据样本。 根据 k 个邻居的多数票将测试类分配给该类。 影响KNN算法性能的因素 用于确定最近邻居的距离的算法
用于从 K 近邻派生分类的决策规则
用于对新示例进行分类的邻居数
如何计算距离 测量距离是KNN算法的核心，总结了问题域中两个对象之间的相对差异。比较常见的是，这两个对象是描述主题（例如人、汽车或房屋）或事件（例如购买、索赔或诊断）的数据行。
汉明距离 汉明距离（Hamming Distance）计算两个二进制向量之间的距离，也简称为二进制串 binary strings 或位串 bitstrings ；换句话说，汉明距离是将一个字符串更改为另一个字符串所需的最小替换次数，或将一个字符串转换为另一个字符串的最小错误数。
示例：如一列具有类别 “红色”、“绿色” 和 “蓝色”，您可以将每个示例独热编码为一个位串，每列一个位。
注：独热编码 one-hot encoding：将分类数据，转换成二进制向量表示，这个二进制向量用来表示一种特殊的bit（二进制位）组合，该字节里，仅容许单一bit为1，其他bit都必须为0
如：
apple banana pineapple 1 0 0 0 1 0 0 0 1 100 表示苹果，100就是苹果的二进制向量 010 表示香蕉，010就是香蕉的二进制向量</description>
    </item>
    <item>
      <title>决策边界算法</title>
      <link>https://www.oomkill.com/decision-boundary/</link>
      <pubDate>Wed, 01 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/decision-boundary/</guid>
      <description>决策边界 (decision boundary)
支持向量机获取这些数据点并输出最能分离标签的超平面。这条线是决策边界
决策平面 （ decision surface ），是将空间划分为不同的区域。位于决策平面一侧的数据被定义为与位于另一侧的数据属于不同的类别。决策面可以作为学习过程的结果创建或修改，它们经常用于机器学习、模式识别和分类系统。
环境空间 ( Ambient Space)，围绕数学对象即对象本身的空间，如一维 Line ，可以独立研究，这种情况下L则是L；再例如将L作为二维空间 $R^2$ 的对象进行研究，这种情况下 L 的环境空间是 $R^2$。
超平面（Hyperplane）是一个子空间， N维空间的超平面是其具有维数的平面的子集。就其性质而言，它将空间分成两个半空间，其维度比其环境空间的维度小 1。如果空间是三维的，那么它的超平面就是二维维平面，而如果空间是 2 维的，那么它的超平面就是一维线。支持向量机 (SVM) 通过找到使两个类之间的边距最大化的超平面来执行分类。
法向量 （Normal） 是垂直于该平面、另一个向量的 90° 角倾斜
什么是支持向量 支持向量 （Support vectors），靠近决策平面（超平面）的数据点。
如图所示，从一维平面来看，哪个是分离的超平面？
一般而言，会有很多种解决方法（超平面），支持向量机就是如何找到最佳方法的解决方案。
转置运算
矩阵的转置是原始矩阵的翻转版本，可以通过转换矩阵的行和列来转置矩阵。我们用 $A^T$ 表示矩阵 A 的转置。例如，
$$A=\left[ \begin{matrix} 1 &amp; 2 &amp; 3 \\ 4 &amp; 5 &amp; 6 \\ \end{matrix} \right]$$ ；那么 A 的转置就为 $$A=\left[ \begin{matrix} 1 &amp; 4 \\ 2 &amp; 5 \\ 3 &amp; 6 \\ \end{matrix} \right]$$ ；</description>
    </item>
    <item>
      <title>决策树</title>
      <link>https://www.oomkill.com/decision-tree/</link>
      <pubDate>Wed, 01 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/decision-tree/</guid>
      <description>熵和基尼指数 信息增益 信息增益 information gain 是用于训练决策树的指标。具体来说，是指这些指标衡量拆分的质量。通俗来说是通过根据随机变量的给定值拆分数据集来衡量熵。
通过描述一个事件是否&amp;quot;惊讶&amp;quot;，通常低概率事件更令人惊讶，因此具有更大的信息量。而具有相同可能性的事件的概率分布更&amp;quot;惊讶&amp;quot;并且具有更大的熵。
定义：熵 entropy是一组例子中杂质、无序或不确定性的度量。熵控制决策树如何决定拆分数据。它实际上影响了决策树如何绘制边界。
熵 熵的计算公式为：$E=-\sum^i_{i=1}(p_i\times\log_2(p_i))$ ；$P_i$ 是类别 $i$ 的概率。我们来举一个例子来更好地理解熵及其计算。假设有一个由三种颜色组成的数据集，红色、紫色和黄色。如果我们的集合中有一个红色、三个紫色和四个黄色的观测值，我们的方程变为：$E=-(p_r \times \log_2(p_r) + p_p \times \log_2(p_p) + p_y \times \log_2(p_y)$
其中 $p_r$ 、$p_p$ 和 $p_y$ 分别是选择红色、紫色和黄色的概率。假设 $p_r=\frac{1}{8}$，$p_p=\frac{3}{8}$ ，$p_y=\frac{4}{8}$ 现在等式变为变为：
$E=-(\frac{1}{8} \times \log_2(\frac{1}{8}) + \frac{3}{8} \times \log_2(\frac{3}{8}) + \frac{4}{8} \times \log_2(\frac{4}{8}))$ $0.125 \times log_2(0.125) + 0.375 \times log_2(0.375) + 0.5 \times log_2(0.375)$ $0.125 \times -3 + 0.375 \times -1.415 + 0.5 \times -1 = -0.375+-0.425 +-0.5 = 1.</description>
    </item>
    <item>
      <title>逻辑回归</title>
      <link>https://www.oomkill.com/logistic-regression/</link>
      <pubDate>Wed, 01 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/logistic-regression/</guid>
      <description>Overview 逻辑回归通常用于分类算法，例如预测某事是 true 还是 false（二元分类）。例如，对电子邮件进行分类，该算法将使用电子邮件中的单词作为特征，并据此预测电子邮件是否为垃圾邮件。用数学来讲就是指，假设因变量是 Y，而自变量集是 X，那么逻辑回归将预测因变量 $P(Y=1)$ 作为自变量集 X 的函数。
逻辑回归性能在线性分类中是最好的，其核心为基于样本属于某个类别的概率。这里的概率必须是连续的并且在 (0, 1) 之间（有界）。它依赖于阈值函数来做出称为 Sigmoid 或 Logistic 函数决定的。
学好逻辑回归，需要了解逻辑回归的概念、优势比 (OR) 、Logit 函数、Sigmoid 函数、 Logistic 函数及交叉熵或Log Loss
Prerequisite odds ratio explain odds ratio是预测变量的影响。优势比取决于预测变量是分类变量还是连续变量。
连续预测变量：$OR &amp;gt; 1$ 表示，随着预测变量的增加，事件发生的可能性增加。$OR &amp;lt; 1$ 表示随着预测变量的增加，事件发生的可能性较小。 分类预测变量：事件发生在预测变量的 2 个不同级别的几率；如 A,B，$OR &amp;gt; 1$ 表示事件在 A 级别的可能性更大。$OR&amp;lt;1$ 表示事件更低的可能是在A。 例如，假设 X 是受影响的概率，Y 是不受影响的概率，则 $OR= \frac{X}{Y}$ ，那么 $OR = \frac{P}{(1-P)}$ ，P是事件的概率。
让概率的范围为 [0,1] ，假设 $P(success)=0.8$ ，$Q(failure) = 0.2$ ；$OR$ 则是 成功概率和失败概率的比值，如：$O(success)=\frac{P}{Q} = \frac{0.</description>
    </item>
    <item>
      <title>朴素贝叶斯算法</title>
      <link>https://www.oomkill.com/naive-bayes/</link>
      <pubDate>Wed, 01 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/naive-bayes/</guid>
      <description>什么是naive bayes 朴素贝叶斯 naive bayes，是一种概率类的机器学习算法，主要用于解决分类问题
为什么被称为朴素贝叶斯？
为什么被称为朴素，难道仅仅是因为贝叶斯很天真吗？实际上是因为，朴素贝叶斯会假设数据属性之间具有很强的的独立性。即该模型中的所有属性彼此之间都是独立的，改变一个属性的值，不会直接影响或改变算法中其他的属性的值
贝叶斯定理 了解朴素贝叶斯之前，需要掌握一些概念才可继续
条件概率 Conditional probability：在另一个事件已经发生的情况下，另外一个时间发生的概率。如，==在多云天气，下雨的概率是多少？== 这是一个条件概率 联合概率 Joint Probability：计算两个或多个事件同时发生的可能性 边界概率 Marginal Probability：事件发生的概率，与另一个变量的结果无关 比例 Proportionality 贝叶斯定理 Bayes&#39; Theorem：概率的公式；贝叶斯定律是指根据可能与事件的先验概率描述了事件的后验概率 边界概率 边界概率是指事件发生的概率，可以认为是无条件概率。不以另一个事件为条件；用公式表示为 $P(X)$ 如：抽到的牌是红色的概率是 $P(red) = 0.5$ ；
联合概率 联合概率是指两个事件在同一时间点发生的可能性，公式可以表示为 $P(A \cap B)$
A 和 B 是两个不同的事件相同相交，$P(A \and B)$ $P(A,B)$ = A 和 B 的联合概率
概率用于处理事件或现象发生的可能性。它被量化为介于 0 和 1 之间的数字，其中 0 表示不可能发生的机会，1 表示事件的一定结果。
如，从一副牌中抽到一张红牌的概率是 $\frac{1}{2}$。这意味着抽到红色和抽到黑色的概率相同；因为一副牌中有52张牌，其中 26 张是红色的，26 张是黑色的，所以抽到一张红牌与抽到一张黑牌的概率是 50%。
而联合概率是对测量同时发生的两个事件，只能应用于可能同时发生多个情况。例如，从一副52张牌扑克中，拿起一张既是红色又是6的牌的联合概率是 $P(6\cap red) = \frac{2}{52} = \frac{1}{26}$ ；这个是怎么得到的呢？因为抽到红色的概率为50%，而一副牌中有两个红色6（红桃6，方片6），而6和红色是两个独立的概率，那么计算公式就为：$P(6 \cap red) = P(6) \times P(red) = \frac{4}{52} \times \frac{26}{52} = \frac{1}{26}$</description>
    </item>
    <item>
      <title>安装Debian11 (bullseye) Step-by-Step</title>
      <link>https://www.oomkill.com/debian11-install-tutorial/</link>
      <pubDate>Wed, 25 May 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/debian11-install-tutorial/</guid>
      <description>Preparation debian11几乎可以使用任何旧的计算机硬件，因为最小安装的要求非常低。以下是最低要求和推荐要求：
最低要求 推荐要求 存储：10 Gigabytes
内存：512 Megabytes
CPU: 1 GigaHertz 存储：10 Gigabytes内存：2 GigabytesCPU: 1 GigaHertz or more Debian11 EOL：August 31st, 2026
如何选择下载安装包 offical mirror aliyun mirror 官网提供了安装包的下载，其中CD是网络安装，DVD是离线安装
debian官方下载页面 Notes：CD安装包很小，下载下来是 debian-11.4.0-amd64-netinst.iso 如名所示，这是一个网络安装包，所以推荐下载DVD部分，可以达到离线安装的效果
安装步骤 在界面中选择“Install”，安装将开始。如果图形化安装可以选择“Graphical install”，这里选择“Install”。
欢迎页面 完成后，系统将提示选择安装时的“语言”。选择喜欢的语言，然后按“Enter”。这里选择英文
选择语言页面 这将是接下来安装步骤
安装步骤概述 选择位置与键盘布局 选择区域
选择区域 下面部署时选择键盘布局：中国大陆使用的键盘布局是美国-英语，不要选择英国-英语之类，布局是不一样的，会存在按键输出的结果会不同
选择键盘布局 完成上述操作后，将开始加载镜像。等待扫描完成。。。。
等待扫描组件 设置主机名和域名 这步骤中将配置一个“主机名”。与一个“域”名称。
配置主机名 “域” 可以选择留空确定
配置域 完成上述操作后，安装程序将提示需要设置 root 密码。输入您的 root 密码，然后在重新输入以进行验证后继续。
设置Root密码 设置非ROOT用户名、账户和密码 下一步创建一个非ROOT用户，这个步骤是必须的，并为这个新创建的帐户分配一个密码。以下截图将描述将如何完成此操作。
配置普通用户 为这个用户配置密码
为普通用户配置密码 为普通用户配置密码——二次确认 设置时钟时区 Eastern 美东时间
Central 北美中部</description>
    </item>
    <item>
      <title>源码分析client-go架构 - 什么是informer</title>
      <link>https://www.oomkill.com/ch08-informer/</link>
      <pubDate>Wed, 25 May 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch08-informer/</guid>
      <description>之前了解了client-go中的架构设计，也就是 tools/cache 下面的一些概念，那么下面将对informer进行分析
Controller 在client-go informer架构中存在一个 controller ，这个不是 Kubernetes 中的Controller组件；而是在 tools/cache 中的一个概念，controller 位于 informer 之下，Reflector 之上。code
Config 从严格意义上来讲，controller 是作为一个 sharedInformer 使用，通过接受一个 Config ，而 Reflector 则作为 controller 的 slot。Config 则包含了这个 controller 里所有的设置。
go 1 2 3 4 5 6 7 8 9 type Config struct { Queue // DeltaFIFO ListerWatcher // 用于list watch的 Process ProcessFunc // 定义如何从DeltaFIFO中弹出数据后处理的操作 ObjectType runtime.Object // Controller处理的对象数据，实际上就是kubernetes中的资源 FullResyncPeriod time.Duration // 全量同步的周期 ShouldResync ShouldResyncFunc // Reflector通过该标记来确定是否应该重新同步 RetryOnError bool } controller 然后 controller 又为 reflertor 的上层</description>
    </item>
    <item>
      <title>Kubernetes组件核心 - client-go</title>
      <link>https://www.oomkill.com/ch06-client-go/</link>
      <pubDate>Sun, 22 May 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch06-client-go/</guid>
      <description>Prepare Introduction 从2016年8月起，Kubernetes官方提取了与Kubernetes相关的核心源代码，形成了一个独立的项目，即client-go，作为官方提供的go客户端。Kubernetes的部分代码也是基于这个项目的。
client-go 是kubernetes中广义的客户端基础库，在Kubernetes各个组件中或多或少都有使用其功能。。也就是说，client-go可以在kubernetes集群中添加、删除和查询资源对象（包括deployment、service、pod、ns等）。
在了解client-go前，还需要掌握一些概念
在客户端验证 API 使用证书和使用令牌，来验证客户端 kubernetes集群的访问模式 使用证书和令牌来验证客户端 在访问apiserver时，会对访问者进行鉴权，因为是https请求，在请求时是需要ca的，也可以使用 -k 使用insecure模式
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 $ curl --cacert /etc/kubernetes/pki/ca.crt https://10.0.0.4:6443/version \{ &amp;#34;major&amp;#34;: &amp;#34;1&amp;#34;, &amp;#34;minor&amp;#34;: &amp;#34;18+&amp;#34;, &amp;#34;gitVersion&amp;#34;: &amp;#34;v1.18.20-dirty&amp;#34;, &amp;#34;gitCommit&amp;#34;: &amp;#34;1f3e19b7beb1cc0110255668c4238ed63dadb7ad&amp;#34;, &amp;#34;gitTreeState&amp;#34;: &amp;#34;dirty&amp;#34;, &amp;#34;buildDate&amp;#34;: &amp;#34;2022-05-17T12:45:14Z&amp;#34;, &amp;#34;goVersion&amp;#34;: &amp;#34;go1.16.15&amp;#34;, &amp;#34;compiler&amp;#34;: &amp;#34;gc&amp;#34;, &amp;#34;platform&amp;#34;: &amp;#34;linux/amd64&amp;#34; } $ curl -k https://10.</description>
    </item>
    <item>
      <title>H3C Cloud与WSL2共存</title>
      <link>https://www.oomkill.com/h3c-hcl-preparation/</link>
      <pubDate>Wed, 18 May 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/h3c-hcl-preparation/</guid>
      <description>背景 由于Windows10 开启WSL2后无法和 eNSP 做到兼容，但是 H3C HCL 在版本 HCL_v2.1.2.1 提供了 VirtualBox 6.0.14 作为虚拟化后端，理论上来说可以做到 WSL2 与 HCL 共存。
并且开启了WSL2后并于其他虚拟化平台（VirtualBox, Vmvare）做到兼容的情况下，这种情况大部分禁止套娃（虚拟化下在虚拟化），通过安装虚拟机的方式再安装 eNSP 发现启动不报错，但是很长时间起不来。
Notes [1]：HCL官方给的建议是，对于windows7装的版本为HCL_v2.1.1；对于Windows10 并且开启了 Hype-v 或者 Dokcer-Desktop，推荐使用 HCL_v3.0.1.1
下载地址：HCL Download
安装过程 下载好安装时，直接下一步直至完成即可，VirtualBox已被内嵌至安装包内了。
图：HCL安装界面 Notes：如果需要抓包，自行安装Wireshark，安装好后，在HCL设置中配置 wireshark.exe 的路径即可
VirtualBox启用hyper-v支持 [2] 进入VirtualBox安装目录, 确定当前目录下存在VBoxManage.exe文件, 在当前目录打开powershell. 或者你将VBoxManage.exe所在目录加入环境变量, 任意路径下打开powershell.
powershell 1 2 # 或指定vbox所有虚拟系统开启 ./VBoxManage.exe setextradata global &amp;#34;VBoxInternal/NEM/UseRing0Runloop&amp;#34; 0 开启后，HCL所有的设备就工作正常了，这种情况下也不用牺牲WSL2或者Dokcer-Desktop。因为eNSP官方没有再更新，导致hype-v与VirtualBox无法兼容，暂时无解。
Reference ​[1] H3C Cloud Lab
​[2] Windows 10 (2004) 启用wsl2, 并与VirtualBox 6.0+共存</description>
    </item>
    <item>
      <title>PC端利用google翻译实现同声翻译</title>
      <link>https://www.oomkill.com/google-interpretation/</link>
      <pubDate>Wed, 18 May 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/google-interpretation/</guid>
      <description>疫情期间上网课，对于英语听力较差或者需要观看英文视频，但实际上并没有双语字幕的这种情况下需要找一个实时的翻译工具。虽然说手机上此类软件比较多，但电脑上没有特别合适的应用可以做为一个免费实时翻译。哪怕是收费翻译工具实际上翻译效果也是很差，并且语种比较单一。
电脑端有一个 speechlogger，可以做到实时翻译，但实际上也是使用的Google翻译，那么实际上我们就可以直接使用Google翻译作为一个同声翻译电脑的声音。
此时就遇到一个问题，就是Google翻译无法识别到电脑的声音，只能识别到麦克风的声音。这里就需要将电脑输出的作为麦克风的输出。使用Windows电脑的可以尝试以下操作。
以windows电脑为例：
Step 1：电脑右下角调整音量图标，右键选择声音
Step2：选择录音设备，立体声混音，将其启动并设置为默认设备（可选）
Step3：右键属性，选择侦听，通过此设备播放选择扬声器对应的设备。
Tips：注意，无用选择侦听此设备，这个选项勾选后的意思是，你可以通过扬声器听到扬声器声音，此时会发生混音。影响我们听到的效果。
Step4：可选步骤，如果Step2没有设置为默认设备，可以在浏览器选择对应的设备作为麦克风，如使用了立体声混音作为电脑的输入设备，那么不是默认设备情况下在浏览器选择该设备作为输入设备即可。
Tips：Google翻译的语音翻译功能貌似只能在Chrome里使用，其他有可能会出现无法使用语音设备的功能
这样就做到了一个免费，无杂音，多语种的同声翻译，不管是上网课学习，还是说做笔记（同语言下还可以作为声音转换为文字）都是一个很不错的选择。
后面再说下，科大讯飞的录音设备实际上翻译功能很差，语种也少，并且专业术语翻译的很烂，最便宜的小2000块钱，大量依赖云服务，实际上可以不用买这种产品，我是已经买过体验的，翻译结果实际上比Google翻译要差。如果不是在现场，没有网络或者声音很嘈杂（他的十几个麦克风其实效果也不咋地）的情况下可以选择其他方案，例如Google的同声翻译。
如果你需要对翻译的结果划分角色的话，还是可以使用 speechlogger，这个也是使用的Google翻译作为翻译引擎的
Reference 如何将电脑的输出作为电脑麦克风的输入
免费的实时翻译工具</description>
    </item>
    <item>
      <title>如何通过源码编译Kubernetes</title>
      <link>https://www.oomkill.com/ch11-code-compile/</link>
      <pubDate>Mon, 16 May 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch11-code-compile/</guid>
      <description>本地构建 选择要构建的版本 text 1 git checkout tags/v1.19.5 将依赖包复制到对应路径下 text 1 cp staging/src/k8s.io vendor/ 调整makefile 在windows上编译的克隆下可能文件编码变了，需要手动修改下文件编码。比如说出现 \r not found 类似关键词时
这里转换编码使用了 dos2unix，需要提前安装下
text 1 apt install dos2unix 转换原因是因为对于bash 脚本执行识别不了windows的换行
text 1 find . -name &amp;#39;*.sh&amp;#39; -exec dos2unix {} \; 然后将 build/root/ 的文件复制到项目根目录
text 1 cp build/root/Makefile* ./ 编译 查看帮助 make help
编译 make all WHAT=cmd/kube-apiserver GOFLAGS=-v
WHAT=cmd/kube-apiserver 为仅编译单一组件，all 为所有的组件
还可以增加其他的一些环境变量 KUBE_BUILD_PLATFORMS= 如编译的平台
更多的可以 make help 查看帮助
编译中问题 Makefile:93: recipe for target &amp;lsquo;all&amp;rsquo; failed</description>
    </item>
    <item>
      <title>深入理解kubernetes API</title>
      <link>https://www.oomkill.com/ch02-kubernetes-api/</link>
      <pubDate>Mon, 16 May 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch02-kubernetes-api/</guid>
      <description>APIServer 在kubernetes架构概念层面上，Kubernetes由一些具有不同角色的服务节点组成。而master的控制平面由 Apiserver Controller-manager 和 Scheduler 组成。
Apiserver 从概念上理解可以分为 api 和 object 的集合，api 可以理解为，处理读写请求来修改相应 object 的组件；而 object 可以表示为 kubernetes 对象，如 Pod， Deployment 等 。
基于声明式的API 在命令式 API 中，会直接发送要执行的命令，例如：运行、停止 等命令。在声明式API 中，将声明希望系统执行的操作，系统将不断将自身状态朝希望状态改变。
为什么使用声明式 在分布式系统中，任何组件随时都可能发生故障，当组件故障恢复时，需要明白自己需要做什么。在使用命令式时，出现故障的组件可能在异常时错过调用，并且在恢复时需要其他外部组件进行干预。而声明式仅需要在恢复时确定当前状态以确定他需要做什么。
External APIs 在kubernetes中，控制平面是透明的，及没有internal APIs。这就意味着Kubernetes组件间使用相同的API交互。这里通过一个例子来说明外部APIs与声明式的关系。
例如，创建一个Pod对象，Scheduler 会监听 API来完成创建，创建完成后，调度程序不会命令被分配节点启动Pod。而在kubelet端，发现pod具有与自己相同的一些信息时，会监听pod状态。如改变kubelet则修改状态，如果删除掉Pod（对象资源不存在与API中），那么kubelet则将终止他。
为什么不使用Internal API 使用External API可以使kubernetes组件都使用相同的API，使得kubernetes具有可扩展性和可组合性。对于kubernetes中任何默认组件，如不足满足需求时，都可以更换为使用相同API的组件。
另外，外部API还可轻松的使用公共API来扩展kubernetes的功能
API资源 从广义上讲，kubernetes对象可以用任何数据结构来表示，如：资源实例、配置（审计策略）或持久化实体（Pod）；在使用中，常见到的就是对应YAML的资源清单。转换出来就是RESTful地址，那么应该怎么理解这个呢？即，对资源的动作（操作）如图所示。但如果需要了解Kubernetes API需要掌握一些概念才可继续。
Group 出于对kubernetes扩展性的原因，将资源类型分为了API组进行独立管理，可以通过 kubectl api-resources查看。在代码部分为 vendor/k8s.io/api
也可以通过 kubectl xxx -v 6 来查看 kubectl 命令进行了那些API调用
text 1 2 3 4 5 6 7 8 9 10 11 $ kubectl get pods -v 6 I0513 21:54:33.</description>
    </item>
    <item>
      <title>ch12 进程间通讯</title>
      <link>https://www.oomkill.com/ch12-ipc/</link>
      <pubDate>Tue, 03 May 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch12-ipc/</guid>
      <description>Overview 进程间是相互保持独立的，内存管理中，就是保护进程的地址空间不被其他进程访问。而进程间通信 ( Inter-process Communication IPC) 用于在一个或多个进程间交换数据
进程间合作是那些可以影响或受其他过程影响的过程。例如网站包含 JS、H5、Flash，当有一个相应缓慢时，会发生整个网站的布局或其他功能的展示。
通常情况下进程间合作被允许的原因有：
信息共享：多个进程需要访问同一个文件。（如管道）
计算加速：将复杂功能拆分为多个子任务（多处理器时效果更佳），可以更快地解决问题
模块化：将整体系统架构分为不同功能模块，模块间相互协作
便利：单用户可以同时多任务处理，如 编辑、编译、打印等
Communications model (a) 消息队列（间接通信） &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(b) 共享内存（直接通信） Message Passing IPC背后关键的一点是消息的传递，即一个进程发消息，一个进程接收消息
而为了使进程间通信，就必须在进程间建立连接，连接可以是单/双向。连接可以使用直接通信和间接通信来实现
Direct Communication 直接通信，必须明确声明发送者或接收者的名称，通常定义为：
Send(P, message)：发送信息到进程 P Receive(Q, message)：接收来自进程 Q 的信息 在直接通信中，一般连接的属性有以下特征：
一个链路与一对进程相关联 自动建立链接 链接是通用的双向链接 Indirect Communication 间接通信，为异步通信，通常情况下互通信都需要有消息队列；发送者将信息放置消息队列中，接受者从消息队列中取出消息
Send(P, message)：像消息队列发送消息 Receive(Q, message)：接受消息队列中的消息 每个进程都有唯一ID 共享一个消息队列 在间接通信中，一般连接的属性有以下特征：
一对进程共享消息队列时，才会在进程之间建立链接 链接可以被许多进程关联 链接可以是单向也可以是双向 每个进程可以有多个链接 &amp;nbsp;&amp;nbsp;直接通信&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;间接通信 Synchronization 从另一方面来讲，消息传递可以是阻塞 Blocking 或非阻塞 Non-Blocking 的；同步 synchronous 会阻塞一个进程，直到发送完成。异步 asynchronous 则是是非阻塞的，发送操作完成后会立即返回不等待返回结果
Buffer 消息通过队列传递，队列的容量则具有下列三种配置之一：
0容量：消息不能存储在队列中，因此发送者必须阻塞，直到接收者接受消息 有限容量：队列中有一定的预先约定大小的容量。如果队列已满，发送者必须阻塞，直到队列中有可用空间（反之为空，接受者阻塞），否则可能是阻塞的或非阻塞的 无限容量：具有无限容量的队列，发送者永远不会被迫阻塞 至此整节围绕对消息传递功能的三个方面做了介绍：</description>
    </item>
    <item>
      <title>ch13 file system</title>
      <link>https://www.oomkill.com/ch13-file-system/</link>
      <pubDate>Tue, 03 May 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch13-file-system/</guid>
      <description>Overview 文件系统和文件 文件系统: 一种用于持久性存储的系统抽象，决定了辅存中的内容如何组织与存储的抽象概念
文件：文件系统中的一个单元的相关数据在操作系统中的抽象，展现给用户的抽象概念
文件系统的功能：
分配文件磁盘空间 管理文件块(哪一块属于哪一个文件) 管理空闲空间(哪一块是空闲的) 分配算法(策略) 管理文件集合 定位文件及其内容 命名：通过名字找到文件的接口 最常见：分层文件系统 文件系统类型(组织文件的不同方式) 提供的便利及特征 保护：分层来保护数据安全 可靠性，持久性：保持文件的持久即使发生崩溃,媒体错误,攻击等 为什么需要文件系统：
如果将文件放入一个房间中，整个房间都是堆积的文件
有了文件系统的存在将会改变一切
空间管理、元数据、数据加密、文件访问控制和数据完整性等等都是文件系统的职责。
文件属性 文件具有名称和数据，还存储文件创建日期和时间、当前大小、上次修改日期等元信息。所有这些信息都称为文件系统的属性。常见的文件属性有
名称：它是以人类可理解的形式。 标识符：每个文件都由文件系统中的唯一标记号标识，称为标识符。 位置：设备上的文件位置。 类型：支持各种类型文件的系统需要此属性。 大小：当前文件大小的属性。 保护：分配和控制读、写和执行文件的访问权限。 时间、日期和安全：用于对文件的保护、安全，也用于监控 文件描述符 文件头 File Header；类似于Unix的 inode，在存储元数据中保存了每个文件的信息，保存文件的属性，跟踪哪一块存储块属于逻辑上文件结构的哪个偏移
文件描述符 （file-descriptor）；是唯一标识操作系统中打开文件的数字（整形），用于用户和内核空间之间的接口，以识别 文件/Socket 资源。因此，当使用 open() 或 socket()（与内核接口的系统调用）时，会得到一个文件描述符，一个整数。因此，如果直接与内核交互，使用系统调用 read(), write() 等 close()。使用的是一个文件描述符句柄。
在 C 语言中 stdin，stdout、 和 stderr ，在 UNIX 中分别映射到文件描述符 0 1 2
text 1 2 3 4 5 f = open(name, flag); ... .</description>
    </item>
    <item>
      <title>ch11 死锁</title>
      <link>https://www.oomkill.com/ch11-deadlock/</link>
      <pubDate>Mon, 02 May 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch11-deadlock/</guid>
      <description>死锁问题 死锁 deadlock；是一组阻塞的进程，每个进程都持有一个资源并等待获取另一个进程持有的资源。
死锁的示例：交通桥
如图所示，桥是资源，进程是车辆，两个不同方向的车辆同时占用桥，此时发生谁也过不去的情况（死锁的发生）；
当死锁发生时，如果一辆车倒车（抢占资源和回滚）就可以解决死锁问题 死锁发生时，可能需要后退多台车辆 饥饿，而饥饿并不一定是死锁 系统模型 在正常情况下，进程必须在使用之前请求资源，并在完成后释放它，顺序如下：
请求：如果不能立即授予请求，则进程等待，直到它需要的资源变得可用。例如，系统调用 open()、malloc()、new() 、request() 等。
使用：进程使用资源，例如文件中读取数据；使用硬件。
释放：进程完成后放弃资源，以便其可用于其他进程。如，close()、free()、delete() 、 release()。
当在集合中的每个进程都在等待当前分配给集合中另一个进程的资源时，这一组进程就会发生死锁
资源分配 通过实例来理解死锁，
一组资源：
${ R_1,\ R_2,\ R_3,\ &amp;hellip;.,\ R_N }$；为方形，图形内的点代表资源数量 一组进程：
${ P_1,\ P_2,\ P_3,\ &amp;hellip;.,\ P_N }$ 请求边缘 Request Edge：进程需要一些资源，被称为请求边缘；如 $P_i\ →\ R_j$
分配边缘 Assign Edge：当资源已经被分配给进程，被称为分配边缘；如 $R_j\ →\ P_i$
当请求被授予时，可以通过反转方向的线将请求边缘转换为分配边缘
类型 示意图 Process Resource $P_i$ 请求的 $R_j$ 实例 $P_i$ 持有一个 $R_j$ 的实例
也可以说 $R_j$ 被 $P_i$ 所持有 资源分配图 资源分配图 如图所示，资源类型为：</description>
    </item>
    <item>
      <title>ch10 信号量和监视器</title>
      <link>https://www.oomkill.com/ch10-semaphore-and-monitors/</link>
      <pubDate>Sun, 01 May 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch10-semaphore-and-monitors/</guid>
      <description>Backgound 信号量 semaphores，是操作系统中非常重要的技术，通过使用一个简单的整数值来管理并发进程，信号量只是一个在线程之间共享的整数变量。该变量用于解决临界区问题并实现进程同步。 信号量具有两个原子操作：
P()：sem减一，如果sem&amp;lt;0，等待；否则继续 V()：sem加一，如果sem≤0，唤醒一个等待的P； Semaphore 信号量的使用 型号量的特点：
两个类型信号量
二进制信号量 Binary Semaphore：也称为互斥锁。它只能有两个值0和1。它的值被初始化为1。它用于实现多进程临界区问题的解决。
计数信号量 Counting Semaphore：值可以跨越一个不受限制的域（可以取任何非负数）。它用于控制对具有多个实例的资源的访问。
信号量是被保护的变量
初始化完成后，唯一改变一个信号量的值的办法是通过P() 和 V()
操作必须是原子
P() 能够阻塞，V() 不会阻塞
信号量可以用在2个方面
互斥
条件同步(调度约束 —— 一个线程等待另一个线程的事情发生)
信号量实现的互斥 c 1 2 3 4 5 6 7 mutex = new Semaphore(1); mutex-&amp;gt;P(); // 临界区前p ... critical section ... mutex-&amp;gt;V(); // 临界区后v 信号量实现调度约束 c 1 2 3 4 5 6 7 8 9 10 condition = new Semaphore(0); // Thread A .</description>
    </item>
    <item>
      <title>ch8 CPU调度算法</title>
      <link>https://www.oomkill.com/ch8-cpu-scheduling-algorithms/</link>
      <pubDate>Sat, 30 Apr 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch8-cpu-scheduling-algorithms/</guid>
      <description>Overview CPU调度 (cpu scheduling )，是决定在一个时间窗口内，哪个进程可以拥有CPU而另外一个个进程会被暂停的过程。CPU调度的作用是为了确保每当CPU空闲时，操作系统至少选择就绪队列中一个可用的进程执行。这个选择过程将由CPU调度器来执行。
调度程序：挑选就绪进程的内核函数
调度策略：依据什么挑选进程？ 调度时机：什么时间进行调度？ 进程从运行状态切换到等待状态 进程退出 非抢占式：当前进程主从放弃CPU时， 抢占式：当前进程被抢占 时间片用完 进程从等待切换到就绪（当前就绪进程优先级高于当前运行进程） 调度准则 CPU的调度策略 抢占式调度 抢占式调度（Preemptive）在分配进程时有对应的优先级。而在另一个较低优先级进程之前运行具有较高优先级的进程很重要，即使较低优先级的进程仍在运行。较低优先级的进程扔会等待一段时间，让较高优先级的进程完成执行后恢复。
抢占式调度主要发生在运行状态切换到就绪或等待状态
非抢占式调度 非抢占式调度 （Non-Preemptive），在这种类型的调度中，一旦将资源（CPU 周期）分配给一个进程，该进程就会持有CPU使用权，直到它被终止或达到等待状态。
抢占式调度主要发生在运行状态终止的情况下
如何确定调度是抢占式还是非抢占式？ 一般来讲，确定调度的方式是通过以下四点来确定的：
当进程从运行状态切换到等待状态；如I/O请求或调用 wait() 系统调用 当进程从运行状态切换到就绪状态；如响应中断。 当进程从等待状态切换到就绪状态；如在 I/O 完成或从 wait() 返回时。 进程完成执行并终止； 如果调度发生在1 4情况下，则为非抢占式，否则为抢占式
程序执行模型 需要关注的是进程在计算机系统中运行时存在什么状态？
几乎所有进程都在一个连续的循环的两种模型之间交替：即CPU突发和I/O突发中交替
每个调度决定都是关于在下一个CPU突发时将哪个工作交给CPU 在时间分片机制下，线程可能在结束当前CPU突发前被迫放弃CPU CPU突发和 I/O突发的交替序列逻辑CPU 突发型的持续时间调度指标 在了解评价指标前，需要对CPU调度中的一些术语需要了解
CPU突发 （Burst Time BT）：进程开始执行的时间，从到达到开始执行花费的时间 到达时间 （Arrival Time AT）：进程到达就绪队列的时间 完成时间（End Time ET 或 Completion Time CT）：进程执行完成的时间 等待时间 （Waiting Time WT）：进程在就绪队列中等待轮到 CPU 占用的时间；$WT = TT - BT$ 周转时间 （Turnaround Time TT）：完成时间和到达时间的差 $TT=CT-AT$ 相应时间（Response Time RT）：开始响应请求所需的时间。第一次请求到相应的时间。 吞吐量 (Throughput)：单位时间内完成的进程数。$Throughput = (Number\ of\ processes\ completed) \div (Time\ unit)$ 一般情况下，需要的服务”越快“越好，而快的定义：</description>
    </item>
    <item>
      <title>ch9 同步</title>
      <link>https://www.oomkill.com/ch9-synchronization/</link>
      <pubDate>Sat, 30 Apr 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch9-synchronization/</guid>
      <description>Background 多进程作为现代操作系统的重要特性，交互则会引起同时对共享资源的访问，当这些资源访问不正确会出现冲突或产生不适当的输出（冲突、死锁、饥饿）；而在同步的基础上，进程被分为以下两种类型：
独立进程 Independent Process 不和其他进程共享资源或状态 确定性，输入状态确定结果 可重现，能够重现起始条件，I/O 调度的顺序不重要 协作进程 Cooperative Process； 多进程共享资源或状态 不确定性 probabilistic 不可重现 不确定性和不可重现意味着bug可能是间歇性发生的
Cooperation 进程的互相影响，即进程间的合作（相互或破坏）；最简单的例子就是两个进程使用同一个文件，一个进程读，一个进程写。读进程的结果会被写进程所影响。
进程需要合作的原因：
资源共享：多个进程访问相同的数据 一台电脑，多个用户 一个银行存款余额,多台ATM机 嵌入式系统（机器人手臂和收的协调） 计算加速： I/O 和 CPU计算可重叠 多处理器 - 将任务分解为子任务并分布在不同的进程中，它通常可以更快地运行（也需要多个可共享的 CPU） 模块化：复杂的任务组织成单独的子任务，让不同的进程运行 大程序分成小程序 是系统易于扩展 程序可以调用函数fork()来创建一个新的进程
操作系统需要分配一个新的并且唯一的进程ID 因此在内核中,这个系统调用会运行 new_pid = next_pid++; 翻译成机器指令: Load next_pid Reg1 STORE Reg1 new_pid INC Reg1 STORE Reg1 next_pid 假设两个进程并发执行
如果next_pid等于100, 那么其中一个进程得到的ID应该是100, 另一个进程的ID应该是101, next_pid应该增加到102 可能在INC前进行了上下文切换, 最终导致两个进程的pid都是100,而next_pid也是101 无论多个线程的指令序列怎样交替执行,程序都必须正常工作
多线程程序具有不确定性和不可重现的特点 不经过专门设计,调试难度很高 不确定性要求并行程序的正确性
先思考清楚问题，把程序的行为设计清楚 切忌给予着手编写代码，碰到问题再调试 Race Condition 竞态条件是由操作系统软件中的同步错误。出现在进程试图同时执行两个或多个操作时，这是一种不希望出现的情况。
怎么样避免竞态?</description>
    </item>
    <item>
      <title>ch7 进程管理</title>
      <link>https://www.oomkill.com/ch7-process-management/</link>
      <pubDate>Fri, 29 Apr 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch7-process-management/</guid>
      <description>Overview 进程的描述 进程的状态 State 线程 Thread 进程间通信 Inter-Process Communication 进程互斥与同步 死锁 DeadLock 进程的描述 在操作系统中，通常来说进程 Process 是当前正在执行的东西。因此，一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程，可以称之为进程。
程序是静态的文件
进程是程序动态执行的过程
进程的组成 进程包括 :
程序的代码 程序处理的数据 程序计数器 (PC) 中的值, 指示下一条将运行的指令 一组通用的寄存器的当前值, 堆 Heap , 栈 Stack 一组系统资源(如打开的文件、内存、网络) 而进程的主要构成如下，
Stack Section Heap Section Data Section Text Section Stack Stack部分包含：
局部变量 函数和返回地址 main函数 如上图所示，Stack和 heap 以相反的方向增长，如果两者都以相同的方向增长，那么其两者可能会重叠，因此如果它们以相反的方向增长则很好。
示例：如，调用下列函数时，将存储在Stack部分，一旦函数返回，该函数堆栈部分的值将被删除。
Stack上有一个堆栈帧，其中包含main函数以及局部变量a, b sum 。使用 printf()，创建的帧以及局部变量只能在内存中访问，帧的持续时间在从函数 return 0 后释放。
c 1 2 3 4 5 6 7 8 int main(void) { int a, b, sum; a = 2; b = 3; sum = a + b; printf(&amp;#34;%d\n&amp;#34;, sum); return 0 } Stack是一种后进先出 (LIFO) 数据结构，最后一个被推到Stack上的内容就是从顶部弹出的第一个内容。不允许从Stack的中间插入或移除。因此Stack必须至少支持两种操作：push 和 pop ；其他操作也是可以，但不是必需的。</description>
    </item>
    <item>
      <title>ch6 页面置换算法</title>
      <link>https://www.oomkill.com/ch6-page-replacement-algorithms/</link>
      <pubDate>Thu, 28 Apr 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch6-page-replacement-algorithms/</guid>
      <description>Overviews 功能与目标 实验设置与评价方法 局部页面算法 最优页面置换算法 先进先出算法 最近最久未使用算法 时钟页面置换算法 最不常用置换算法 Belady现象 LRU FIFO Clock对比 全局页面置换算法 工作集模型 工作集页面置换算法 缺页率置换算法 功能与目标 功能 : 当缺页中断发生，需要调入新的页面而内存已满时，选择内存当中哪个物理页面被置换。
目标 : 尽可能地减少页面的换进换出次数(即缺页中断的次数)。 具体来说，把未来不再使用的或短期内较少使用的页面换出，通常只能在局部性原理指导下依据过去的统计数据来进行预测。
页面锁定 frame locking：用于描述必须常驻内存的操作系统的关键部分或时间关键（time critical）的应用进程。实现的方式是：在页表中添加锁定标记位(lock bit)。
实验设置与评价方法 实例：记录一个进程对页访问的一个轨迹
举例 : 模拟一个实验环境，记录对应的地址访问序列，虚拟地址跟踪(页号, 偏移)&amp;hellip; (3,0) (1,9) (4,1) (2,1) (5,3) (2,0) &amp;hellip; 而offset可以忽略（页不存在才会产生 page fault），生成的页面轨迹 3, 1, 4, 2, 5, 2, 1, &amp;hellip;（替换为，3,1,4,2,5,2,1） 模拟一个页面置换的行为并且记录产生页缺失数的数量
更少的缺失，更好的性能 局部页面置换算法 最优页面置换算法 基本思路：当一个缺页中断发生时，对于保存在内存当中的每一个逻辑页面，计算在它的下一次访问之前，还需等待多长时间，从中选择等待时间最长的那个，作为被置换的页面。
这是一种理想情况, 在实际系统中是无法实现的, 因为操作系统无法知道每一个页面要等待多长时间以后才会再次被访问.
最优页面置换算法（Optimal Page Replacement）可用作其他算法的性能评价的依据，(在一个模拟器上运行某个程序, 并记录每一次的页面访问情况，在第二遍运行时即可使用最优算法)
在该算法中，会替换在未来最长持续时间内不会使用的页面。如下图所示有 a b c d e五个页，但是只有四个页帧。此时会产生物理页不够，会产生 Page Fault。</description>
    </item>
    <item>
      <title>ch5 虚拟内存</title>
      <link>https://www.oomkill.com/ch5-virtual-memory/</link>
      <pubDate>Wed, 27 Apr 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch5-virtual-memory/</guid>
      <description>Objective 覆盖技术 交换技术 虚拟内存 目标 程序局部性原理 基本概念 基本特征 虚拟页式内存管理 覆盖技术 overlay 在固定分区中的主要遇到的问题是进程的大小受到分区的最大大小的限制，这将意味着一个进程将不能跨越另一个进程。为了解决这个问题，早期使用了称为覆盖(overlay) 的解决方案，覆盖技术是为了在较小的可用内存中运行较大的程序。常用于多道程序系统，与分区存储管理配合使用。这样并非所有模块都需要同时存在于内存中，实现了运行大于物理内存大小的程序的技术。
覆盖技术的原理： 将程序按照执行逻辑拆分为多个功能上相对独立的部分（overlays）, 那些不会同时执行的模块共享同一块内存区域, 按时间先后来运行（分时）。 必要部分，常驻内存的代码和数据，负责管理，在某个时间片将相应的程序和数据导入或导出内存。 可选部分，在其他程序模块中实现, 平时存放在外存中, 在需要用到时才装入内存; 不存在调用关系的模块不必同时装入到内存, 从而可以相互覆盖, 即这些模块共用一个分区. 覆盖技术实例 覆盖技术说明：
有一个程序，分位A B C D E F G 六个模块，每一个模块占用了一定空间，程序的覆盖树如图所示。
问：当满足加载（和运行）该程序所需物理内存中的大小是多少？
使用覆盖技术，实际上不需要将整个程序放在主内存中。只需要在对应时间片时所需要的部分即可，其逻辑调用关系树可以分为：Root-A-D或者 Root-A-E ; Root-B-F 或 Root-C-G 部分。
Root是常驻内存，因为其需要调用A B C D E F G 六个模块，占用2KB
如图：加载与运行改程序所需的物理内存大小是多少？
​	(a) 12 KB
​	(b) 14 KB
​	(c) 10 KB
​	(d) 8 KB
答：由公式可得，最大运行层所需的物理内存为14KB，即拥有 14KB 大小的分区就可以运行上图任意一个分区</description>
    </item>
    <item>
      <title>ch4 操作内存管理 - 非连续内存分配</title>
      <link>https://www.oomkill.com/ch4-non-contiguous-memory-allocation/</link>
      <pubDate>Tue, 26 Apr 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch4-non-contiguous-memory-allocation/</guid>
      <description>overview Q1: 为什么需要非连续内存分配
连续内存管理 （contiguous memory allocation）, 即 : 操作系统加载到内存以及程序加载到内存中时, 分配一块连续的内存块. 但这种方式会出现碎片问题，而非连续内存分配（Non-contiguous memory allocation ）可以有效的减少碎片（Fragmentation）的出现。
Q2: 主要的非连续内存分配的管理方法
分段（Segmentation） 分页（Paging） 页表 （Page Table） 1.非连续内存分配的必要性 连续内存管理的缺陷：
内存利用率较低（memory wastage），在程序运行时分配的内存是增长的，但在进程使用为达到分配大小时，分配的块并未使用，并且也不能给其他进程使用，造成了内存的浪费。 分配给一个程序的物理内存必须是连续的。 碎片化问题 不灵活（inflexibility），当进程或文件使用的内存超出预期时（即：超出分配的内存块大小），将停止并抛出异常，例如：No disk space。 非连续内存分配的优点:
一个程序的物理地址空间是非连续的 更好的内存利用和管理，（减少了内存浪费） 允许共享代码与数据(共享库等&amp;hellip;) 支持动态加载和动态链接 非连续内存分配的缺点：
建立虚拟地址和物理地址的转换难度大 软件方案 硬件方案(采用硬件方案) : 分段 / 分页 分段（segmentation） 首先 segmentation mechanism需要考虑的问题：
程序的分段地址空间 分段寻址方案 什么是segmentation 段（segmentation）是一个逻辑单元 (logical unit)，例如：
主程序 main program 程序（主要是指功能的代码，如一段函数） procedure 函数 function 方法 method 对象 object 局部变量和全局变量 local variables, global variables 公共块 common block 堆 stack 符号表 symbol table 数组 arrays [segmentation的逻辑视图]可以看到左边是逻辑地址，右边是不连续的物理地址，中间有一个映射机制将两边建立了一个关联关系（ST Segment Table）。通过映射机制将不同的块（如stack，function.</description>
    </item>
    <item>
      <title>ch3 操作内存管理 - 连续内存分配</title>
      <link>https://www.oomkill.com/ch3-contiguous-memory-allocation/</link>
      <pubDate>Mon, 25 Apr 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch3-contiguous-memory-allocation/</guid>
      <description>一 计算机体系结构及内存分层体系 1.计算机硬件体系结构大致分为
CPU，完成程序的执行控制 主存 （main memory），放置程序代码和数据 I/O（外）设备，配合程序工作。 2.内存分层体系（金字塔结构) 什么是内存结构：CPU所访问的指令和数据在什么地方。
第一类：位于CPU内部，操作操作系统无法直接进行管理的，寄存器，cache；特点，速度快，容量小
第二类：主存或物理内存，主要用来放置操作系统本身及要运行的代码；其特点是，容量比cache要大很多，单速度交于cache要慢一些。
第三类：磁盘，永久保存的数据及代码，当对于主存要慢，容量比主存大很多。
操作系统的作用可以将数据访问的速度（cache与内存）与存储的大小（硬盘）很好的融合在一起
3.OS管理内存时需要完成的目标
① 抽象：逻辑地址空间（将物理内存，外设等抽象成逻辑地址空间，只需要访问对应地址空间)
② 保护（独立）：操作系统完成隔离机制实现，独立地址空间（每段程序执行时，不受其他程序的影响）
③ 共享：进程间安全，可靠，有效，进行数据传递，访问相同的内存。
④ 虚拟化：更多的地址空间（利用磁盘的空间) 4.需要完成在操作系统中管理内存的不同方法
操作系统层面
程序重定位
分段
分页
虚拟内存
按需分页虚拟内存
硬件层面
必须知道内存架构 MMU(内存管理单元)：处理CPU的内存访问请求 二 地址空间&amp;amp;地址生成 地址空间的定义
地址生成器
地址安全检查
1.内存地址的定义 ① 物理内存地址：硬件支持的地址空间，如主存（内存）和硬盘，由硬件完成管理和控制 ② 逻辑内存地址：一个程序运行时所需要的内存范围。
两者间的关系：逻辑地址空间最终是一个存在的物理地址空间，两者间的映射关系是由操作系统来管理的
2.逻辑地址生成过程（把代码转化为计算机能理解语言） 一段代码运行→编译→汇编语言→机器语言→产生链接文件→将硬盘中程序载入到内存当中运行（完成逻辑地址的分配）
如C中变量的名字，函数的位置，为逻辑地址。
3.物理地址生成（逻辑地址对应的物理地址的过程） CPU方面 MMU表示映射关系
① CPU ALU Arithmetic logic unit 发出请求，为逻辑地址 ② CPU MMU Memory management unit 查找逻辑地址映射表，不存在会去内存中找 ③ 控制器提出内存请求（需要的内容，内容即指令） 内存方面
④ 内存通过bus发送物理内存地址的内容给CPU OS方面 建立逻辑地址和物理地址之间的映射关系（需在前四部前将映射管理建立好）</description>
    </item>
    <item>
      <title>Windows Terminal无法加载WSL  [process exited with code 4294967295 (0xffffffff)]</title>
      <link>https://www.oomkill.com/wsl-problem-with-windows-terminal/</link>
      <pubDate>Wed, 30 Mar 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/wsl-problem-with-windows-terminal/</guid>
      <description>在Windows Terminal中WSL无法打开错误代码是 process exited with code 4294967295 (0xffffffff)，但在命令行中 通过 &amp;quot;C:\Windows\System32\wsl.exe&amp;quot; -d ubuntu18 是正常的
解决方法是：通过修改启动的命令为 wsl.exe ~ -d Ubuntu 中间加一个 ~ 可以很好的解决掉
这种方法存在一个问题，打开的wsl终端将为根目录而不是当前windows目录
Reference Unable to launch WSL Ubuntu</description>
    </item>
    <item>
      <title>Go每日一库 - gocolly</title>
      <link>https://www.oomkill.com/golib-gocolly/</link>
      <pubDate>Tue, 29 Mar 2022 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/golib-gocolly/</guid>
      <description>Introduction 本文对colly如何使用，整个代码架构设计，以及一些使用实例的收集。
Colly是Go语言开发的Crawler Framework，并不是一个完整的产品，Colly提供了类似于Python的同类产品（BeautifulSoup 或 Scrapy）相似的表现力和灵活性。
Colly这个名称源自 Collector 的简写，而Collector 也是 Colly的核心。
Colly Official Docs，内容不是很多，最新的消息也很就远了，仅仅是活跃在Github
Concepts Architecture 从理解上来说，Colly的设计分为两层，核心层和解析层，
Collector ：是Colly实现，该组件负责网络通信，并负责在Collector 作业运行时执行对应事件的回调。 Parser ：这个其实是抽象的，官网并未对此说明，goquery和一些htmlquery，通过这些就可以将访问的结果解析成类Jquery对象，使html拥有了，XPath选择器和CSS选择器 通常情况下Crawler的工作流生命周期大致为
构建客户端 发送请求 获取响应的数据 将相应的数据解析 对所需数据处理 持久化 而Colly则是将这些概念进行封装，通过将事件注册到每个步骤中，通过事件的方式对数据进行清理，抽象来说，Colly面向的是过程而不是对象。大概的工作架构如图
event 通过上述的概念，可以大概了解到 Colly 是一个基于事件的Crawler，通过开发者自行注册事件函数来触发整个流水线的工作
Colly 具有以下事件处理程序：
OnRequest：在请求之前调用 OnError ：在请求期间发生错误时调用 OnResponseHeaders ：在收到响应头后调用 OnResponse： 在收到响应后调用 OnHTML：如果接收到的内容是 HTML，则在 OnResponse 之后立即调用 OnXML ：如果接收到的内容是 HTML 或 XML，则在 OnHTML 之后立即调用 OnScraped：在 OnXML 回调之后调用 OnHTMLDetach：取消注册一个OnHTML事件函数，取消后，如未执行过得事件将不会再被执行 OnXMLDetach：取消注册一个OnXML事件函数，取消后，如未执行过得事件将不会再被执行 Reference
goquery
htmlquery
Utilities 简单使用 go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;github.</description>
    </item>
    <item>
      <title>grafana v8.0&#43; 隐藏表格字段</title>
      <link>https://www.oomkill.com/grafana-8.0/</link>
      <pubDate>Fri, 17 Dec 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/grafana-8.0/</guid>
      <description>Select panel title → Inspect → Panel JSON
Set “type” to &amp;ldquo;table-old&amp;rdquo;
Apply
The visualization should now appear as Table (old) and in the right side will appear Column Styles
Column Styles → Options → Name pattern set the name of the column to hide
Type → Hidden
Reference：Hide column in table in v8.0</description>
    </item>
    <item>
      <title>理解kubernetes listwatch机制原理</title>
      <link>https://www.oomkill.com/ch05-listwatch-mechanism/</link>
      <pubDate>Sun, 12 Dec 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch05-listwatch-mechanism/</guid>
      <description>overview kubernetes的设计里面大致上分为3部分：
API驱动型的特点 (API-driven) 控制循环（control loops）与 条件触发 （Level Trigger） API的可延伸性 而正因为这些设计特性，才使得kubernetes工作非常稳定。
什么是Level Trigger与 Edge trigger 看到网上有资料是这么解释两个属于的：
条件触发(level-trigger，也被称为水平触发)LT指： 只要满足条件，就触发一个事件(只要有数据没有被获取，就不断通知)。
边缘触发(edge-trigger)ET: 每当状态变化时，触发一个事件。
通过查询了一些资料，实际上也不明白这些究竟属于哪门科学中的理论，但是具体解释起来看的很明白。
LEVEL TRIGGERING：当电流有两个级别，VH 和 VL。代表了两个触发事件的级别。如果将VH 设置为LED在正时钟。当电压为VH时，LED可以在该时间线任何时刻点亮。这称为LEVEL TRIGGERING，每当遇到VH 时间线就会触发事件。事件是在时间内的任何时刻开始，直到满足条件。
Edge TRIGGERING:
如图所示，会看到上升线与下降线，当事件在上升/下降边缘触发时（两个状态的交点），称为边缘触发（Edge TRIGGERING:）。
如果需要打开LED灯，则当时钟从VL转换到VH时才会亮起，而不是一家处在对应的时钟线上，仅仅是在过渡时亮起。
为什么kubernetes使用Level Trigger而不使用Edge trigger 如图所述，两种不同的设计模式，随着时间形状进行相应，当系统在由高转低，或由低转高时，系统处在关闭或者不可控的异常状态下，应如何触发对应的事件呢。
换一种方式来来解释，比如说通过 加法运算，如下，i=3，当给I+4作为一个操作触发事件。
text 1 2 3 4 5 # let i=3 # let i+=4 # let i # echo $i 7 当为Edge trigger时操作的情况下，将看到 i+4 ,而在 level trigger 时看到的是 i=7。这里将会从``i+4` 一直到下一个信号的触发。
信号的干扰 通常情况下，两者是没有区别的，但在大规模分布式网络环境中，有很多因素的影响下，任何都是不可靠的，在这种情况下会改变了我们对事件信号的感知。
如图所示，图为Level Trigger与Edge trigger 的信号发生模拟，在理想情况下，两者间并没有什么不同。</description>
    </item>
    <item>
      <title>理解kubernetes schema</title>
      <link>https://www.oomkill.com/ch03-kubernetes-schema/</link>
      <pubDate>Mon, 22 Nov 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch03-kubernetes-schema/</guid>
      <description>什么是schema schema一词起源于希腊语中的form或figure，但具体应该如何定义schema取决于应用环境的上下文。schema有不同的类型，其含义与数据科学、教育、营销和SEO以及心理学等领域密切相关。
在维基百科中将schema解释为，图式，在心里学中主要描述一种思维或行为类型，用来组织资讯的类别，以及资讯之间的关系。它也可以被描述为先入为主思想的心理结构，表示世界某些观点的框架，或是用于组织和感知新资讯的系统。
但在计算机科学中，从很多地方都可以看到 schema 这个名词，例如 database，openldap，programing language等的。这里可以简单的吧schema 理解为 元数据集合 （metadata component）数据模型，主要包含元素及属性的声明，与其他数据结构组成。
数据库中的schema 在数据库中，schema 就像一个骨架结构，代表整个数据库的逻辑视图。它设计了应用于特定数据库中数据的所有约束。当在数据建模时，就会产生一个schema。在谈到关系数据库]和面向对象数据库时经常使用schema。有时也指将结构或文本的描述。
数据库中schema描述数据的形状以及它与其他模型、表和库之间的关系。在这种情况下，数据库条目是schema的一个实例，包含schema中描述的所有属性。
数据库schema通常分为两类：定义数据文件实际存储方式的**物理数据库schema ；和逻辑数据库schema **，它描述了应用于存储数据的所有逻辑约束，包括完整性、表和视图。常见包括
星型模式（star schema） 雪花模式（snowflake schema） 事实星座模型（fact constellation schema 或 galaxy schema） 星型模式是类似于一个简单的数据仓库图，包括一对多的事实表和维度表。它使用非规范化数据。
雪花模式是更为复杂的一种流行的数据库模式，在该模式下，维度表是规范化的，可以节省存储空间并最大限度地减少数据冗余。
事实星座模式远比星型模式和雪花模式复杂得多。它拥有多个共享多个维度表的事实表。
Kubernetes中的schema 通过上面的阐述，大概上可以明白 schema究竟是什么东西了，在Kubernetes中也有schema的概念，通过对kubernetes中资源（GVK）的规范定义、相互关系间的映射等，schema即k8s资源对象元数据。
而kubernetes中资源对象即 Group Version Kind 这些被定义在 staging/src/k8s.io/api/type.go中，即平时所操作的yaml文件，例如
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 apiVersion: apps/v1 kind: Deployment metadata: name: ngx namespace: default spec: selector: matchLabels: app: ngx template: metadata: labels: app: nginx spec: containers: - name: ngx-schema image: nginx ports: - containerPort: 80 而对应的的即为TypeMeta 、ObjectMeta 和 DeploymentSpec,</description>
    </item>
    <item>
      <title>k8s开发环境准备 - 如何配置开发环境</title>
      <link>https://www.oomkill.com/ch01-k8s-perpare/</link>
      <pubDate>Fri, 19 Nov 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch01-k8s-perpare/</guid>
      <description>下载源码 根据kubernetes github 方式可以
text 1 2 3 4 5 mkdir -p $GOPATH/src/k8s.io cd $GOPATH/src/k8s.io git clone https://github.com/kubernetes/kubernetes cd kubernetes make 如果有需要可以切换到对应的版本进行学习或者修改，一般kubernetes版本为对应tag
text 1 2 3 git fetch origin [远程tag名] git checkout [远程tag名] git branch 配置goland kubernetes本身是支持 go mod 的，但源码这里提供了所有的依赖在 staging/src/k8s.io/ 目录下，可以将此目录内的文件复制到 vendor下。
bash 1 cp -a staging/src/k8s.io/* vendor/k8s.io/ 对于 k8s.io/kubernetes/pkg/ 发红的（找不到依赖的），可以将手动创建一个目录在 vendor/k8s.io/ 将克隆下来的根目录 pkg 复制到刚才的目录下。
goland中，此时不推荐使用go mod模式了，这里goland一定要配置GOPATH的模式。对应的GOPATH加入 {project}/vender即可。 这里可以添加到 goland中 project GOPATH里。</description>
    </item>
    <item>
      <title>Linux高级IPC - DBus</title>
      <link>https://www.oomkill.com/what-is-dbus/</link>
      <pubDate>Thu, 18 Nov 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/what-is-dbus/</guid>
      <description>What is IPC IPC [Inter-Process Communication] 进程间通信，指至少两个进程或线程间传送数据或信号的一些技术或方法。在Linux/Unix中，提供了许多IPC。Unix七大IPC：
Pipe：无名管道，最基本的IPC，单向通信，仅在父/子进程之间，也就是将一个程序的输出直接交给另一个程序的输入。常见使用为 ps -ef|grep xxx FIFO [(First in, First out)] 或 有名管道（named pipe）:与Pipe不同，FIFO可以让两个不相关的进程可以使用FIFO。单向。 Socket 和 Unix Domain Socket：socket和Unix套接字，双向。适用于网络通信，但也可以在本地使用。适用于不同的协议。 消息队列 Message Queue: SysV 消息队列、POSIX 消息队列。 Signal: 信号，是发送到正在运行的进程通知以触发其事件的特定行为，是IPC的一种有限形式。 Semaphore：信号量，通常用于IPC或同一进程内的线程间通信。他们之间使用队列进行消息传递、控制或内容的传递。（常见SysV 信号量、POSIX 信号量） Shared memory：（常见SysV 共享内存、POSIX 共享内存）。共享内存，是在进程（程序）之间传递数据的有效方式，目的是在其之间提供通信。 每种IPC都有不通的特点，每种方式对资源的使用及性能都是不通的
管道 I/O是最快的，但为单向通信，需要工作在 父/子 进程关系之间。 UNIX 套接字可以在本地连接不同的进程，并且具有更高的带宽，并且没有固有的消息边界。 TCP/IP套接字可以连接任何进程。并且可以通过网络连接，但是对资源会有更多的开销，同样的没有固定的消息边界。 Reference comparsion Unix/Linux IPC
What is D-Bus 提到，D-Bus就不能不提一下freedesktop，而 D-Bus 仅仅作为freedesktop.org的一部分。
D-Bus 桌面总线 (Desktop Bus)，的简写，也是Linux- IPC机制，不同于Unix 7大基础IPC的是，D-Bus是在这些IPC类型之上实现的中间件IPC，D-Bus使用了基础IPC中一种过多种，其设计的目的是在Linux桌面环境，提供服务的标准化。但目前并没有合入主线内核中。
作为中间件IPC，D-Bus的性能较低与其他IPC模式，因为在通信过程中会进行很多上下文切换，如果通过Dbus来发送消息，会先将其发送到内核，然后将其送回D-Bus。AF_BUS 补丁是新的套接字类型，用来减少D-Bus上下文的切换。
更多可参考：https://en.wikipedia.org/wiki/D-Bus
D-Bus组成 D-Bus是 一个IPC的实现方式，在架构上分位三层。
Layer 1 libdbus：freedesktop机构提供的一个免费开源的一个由C语言编写的 low-level API 。是提供dbus功能的库。是高级API绑定的低级API。 Layer 2 dbus daemon：dbus实现的IPC守护进行，随Linux启动，通过不通进程对其的连接，实现了多进程间消息的路由（包含内核、网络、桌面等） Layer 3 Wapper libraries （high-level API）： 对 low-level API libdbus的封装 ，例如 libdbus-qt libdbus-python github.</description>
    </item>
    <item>
      <title>使用firewalld dbus接口配置iptables</title>
      <link>https://www.oomkill.com/firewalld-dbus-interface/</link>
      <pubDate>Thu, 18 Nov 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/firewalld-dbus-interface/</guid>
      <description>firewalld，一个基于动态区的iptables/nftables守护程序，自2009年左右开始开发，CentOS7基于 firewalld-0.6.3 ， 发布于2018年10月11日。主要的开发人员是托马斯·沃纳，他目前为红帽公司工作。这是因为为Federal 18 的默认防火墙机制， 随后在 Rhel7 和 Centos 7 中使用。
firewalld比旧的 iptable 机制有许多优势。值得注意的是，它解决了 iptable 要求每次更改时重新启动防火墙的问题，从而中断了任何状态连接。它还提供了丰富的 D-Bus 方法、信号和属性。
这里并不是从firewalld操作使用方式来介绍firewalld的改名，想反，是介绍firewalld D-Bus API来检索信息或更改设置。
firewalld被配置为系统 D-Bus 服务，注意看 systemd file中的&amp;quot; Type=dbus &amp;ldquo;参数。
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 $ cat /usr/lib/systemd/system/firewalld.service [Unit] Description=firewalld - dynamic firewall daemon Before=network-pre.target Wants=network-pre.target After=dbus.service After=polkit.service Conflicts=iptables.service ip6tables.service ebtables.service ipset.</description>
    </item>
    <item>
      <title>通俗易懂的dbus数据结构</title>
      <link>https://www.oomkill.com/dbus-data-structure/</link>
      <pubDate>Thu, 18 Nov 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/dbus-data-structure/</guid>
      <description>DBus中也是类似于静态语言，使用了“强类型”数据格式。在DBus上传递的所有数据都需要声明其对应的类型，下面整理了下，DBus中的数据类型，以及在DBus中声明的数据类型是什么意思。
dbus类型 说明 s string 字符串类型，可以声明 s: a array 数组，可以声明为 a: v variant，variant:: () 结构体，声明时为双括号中间的为类型，可以是多个，例如(ss) 即这个结构体内包含两个字符串属性 b 布尔值 SIGNATURE signature类型 y BYTE d DOUBLE t UINT64 x INT64 u UINT32 i INT32 q uint16 n INT16 {} 词典，这里声明为两个括号，中间为其对应的 key value，例如 {sv} 即 key是字符串类型，value是variant类型。 o OBJECT_PATH 对象路径 a{sv} : 是一个数组，为 一个键值对的词典，里面仅有一个
(ssssa{ss}as） 为一个结构体， 里面属性有7个 两个词典（数组），五个字符串类型
(sssbsasa(ss)asba(ssss)asasasasa(ss)b) 这个类型拆开为下：共16个属性
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ( s string s string s string b bool s string as array only one string a(ss) two string type in the array as array only one string b bool a(ssss) four string type in the array as array only one string as array only one string as array only one string as array only one string a(ss) two string type in the array b bool ) 对上述类型，python中就可以很灵活的声明</description>
    </item>
    <item>
      <title>C程序编译错误记录</title>
      <link>https://www.oomkill.com/c-complie-record/</link>
      <pubDate>Tue, 02 Nov 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/c-complie-record/</guid>
      <description>Question1: Similar to pause command in linux
text 1 read -n 1 Question2 read : Illegal option -n
原因为ubuntu 默认的是dash 不是 bash Reference
Question3: How to Compile C programing Language
text 1 gcc hello.c -o hello Question4: Segmentation fault (core dumped)
编译正常执行错误，在linux中使用 strace 查看具体报错。
Reference</description>
    </item>
    <item>
      <title>elasticsearch mapping</title>
      <link>https://www.oomkill.com/elasticsearch-mapping/</link>
      <pubDate>Tue, 02 Nov 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/elasticsearch-mapping/</guid>
      <description>索引管理 创建索引 直接创建索引 PUT newindex1，创建索引可以通过 number_of_shares 和 number_of_replicas 数量来修饰分片和副本的数量。
text 1 2 3 4 5 6 7 8 9 PUT newindex { &amp;#34;settings&amp;#34;: { &amp;#34;index&amp;#34; : { &amp;#34;number_of_shares&amp;#34; : 2, &amp;#34;number_of_replicas&amp;#34;: 1 } } } number_of_shares 分片数在创建索引后不能修改
number_of_replicas 副本数可以随时完成修改
删除索引 DEL index_name
打开/关闭索引 POST {index_name}/_close
POST {index_name}/_open
关闭的索引无法进行【增删改查】操作
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 { &amp;#34;error&amp;#34; : { &amp;#34;root_cause&amp;#34; : [ { &amp;#34;type&amp;#34; : &amp;#34;index_closed_exception&amp;#34;, &amp;#34;reason&amp;#34; : &amp;#34;closed&amp;#34;, &amp;#34;index_uuid&amp;#34; : &amp;#34;3eCslZZ3Q9amlUyDtqTXWA&amp;#34;, &amp;#34;index&amp;#34; : &amp;#34;newindex&amp;#34; } ], &amp;#34;type&amp;#34; : &amp;#34;index_closed_exception&amp;#34;, &amp;#34;reason&amp;#34; : &amp;#34;closed&amp;#34;, &amp;#34;index_uuid&amp;#34; : &amp;#34;3eCslZZ3Q9amlUyDtqTXWA&amp;#34;, &amp;#34;index&amp;#34; : &amp;#34;newindex&amp;#34; }, &amp;#34;status&amp;#34; : 400 } 索引的映射 mapping mapping是定义文档及包含字段的存储与索引方式。可以理解为是elasticsearch的表结构，定义mapping，即在创建index时，自行判断每个字段的类型，而不是有ES自动自动判断每个纬度的类型。这种更贴合业务场景，如分词、存储。</description>
    </item>
    <item>
      <title>Go每日一库 - deepcopier</title>
      <link>https://www.oomkill.com/golib-deepcopier/</link>
      <pubDate>Sat, 30 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/golib-deepcopier/</guid>
      <description>question: How use golang Copy one struct to another where structs have same members and different types
此时需要的库
github.com/ulule/deepcopier github.com/jinzhu/copier E.g.
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;github.</description>
    </item>
    <item>
      <title>bash shell常用示例</title>
      <link>https://www.oomkill.com/awesome-bash-shell/</link>
      <pubDate>Fri, 22 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/awesome-bash-shell/</guid>
      <description>工具命令集合 长期总结 - Linux日志查询命令 长期总结 - Linux网络命令合集 长期总结 - Linux性能分析命令 awk常用案例 bash shell常用示例 探索kubectl - 巧用jsonpath提取有用数据 探索kubectl - kubectl诊断命令集合 该文整理一些常用的shell用法，及语法，并非介绍如何使用
变量 变量可分为两类：环境变量ENV（全局）和局部变量。
bash环境变量
变量名 含义 _= 上一条命令的最后一个参数 BASH_VERSION=&amp;ldquo;4.1.2(1)-release&amp;rdquo; 当前bash实例的版本号 COLORS=&amp;quot;/etc/DIR_COLORS&amp;quot; COLUMNS=80 设置该变量就给shell编辑模式和选择命令定义了编辑窗口的宽度 CVS_RSH=&amp;ldquo;ssh&amp;rdquo; DIRSTACK 代表目录栈当前的内容 EUID=0 为在shell启动时被初始化的当前用户的有效ID G_BROKEN_FILENAMES=1 GROUPS=() 当前用户所属组 HISTFILE=/root/.bash_history 历史记录文件的全路径 HISTFILESIZE=50 历史文件能包含的最大行数 HISTSIZE=50 记录在命令行历史文件中的命令行数 HOME=/root 当前用户家目录 HOSTNAME= 当前主机机器名称 HOSTTYPE=x86_64 IFS=$&amp;rsquo;\t\n&#39; 内容字段分隔符，一般是空格符、制表符、和换行符，用于由命令替换，循环结构中的表和读取的输入产生的词的字段划分。 INPUTRC=/etc/inputrc readline启动文件的文件名。取代默认的~/.inputrc JAVA_HOME=/app/jdk1.6 KDENIR=/usr KDE IS PRELINKED=1 LANG=zh_CN.GB18030 LESSONPEN LINES=36 LONGNAME=root 登陆的用户名 LS_COLORS=xx MACHTYPE=x86_64-redhat-linux-gnu 包含一个描述正在运行bash的系统串 MAILCHECK=60 这个参数定义shell将隔多长时间（以秒为单位检查一次由参数MAILPATH或MAILFILE）指定的文件，看看是否有邮件到达。默认600秒 MAIL=/var/spool/mail/root 邮件全路径 OLDPWD=/root 前一个当前工作目录 OPTERR=1 如果设置为1，秒年十时毫，来自getopts内置命令的错误信息。 OPTIND=1 下一个有getopts内置命令处理的参数序号 OSTYPE=linux-gnu 自动设置称一个串，该串标书正在运行bash的操作系统，默认值有系统决定 PATH 全局PATH路径。命令搜索路径。一个有冒号分隔的目录列表，shell用它来搜索命令。默认路径有系统决定，并且由安装bash的管理员设置。 PIPESTATUS=([0]=0 [1]=1) 一个数组，包含一列最进在管道执行的前台作业的进程退出状态值。 PPID=1112 父进程的进程ID PS1=[\u@\h \W]$ 主提示符串，默认值是$ PS2= &amp;gt; 次提示符串，默认值是&amp;gt; PS4=+ 当开启追踪时使用的调试提示符串，默认值是+，追踪可用set-x开启。 PWD 当前用户家目录。 SHELL=/bin/bash SHLVL=1 每启动一个bash实例就将其加1 TMOUT=3600 退出前等待超时的秒数。 UID=0 当前用户的UID，在shell启动时初始化。 USER=root 当前用户的用户名，在shell启动时初始化。 自定义环境变量 export</description>
    </item>
    <item>
      <title>Account locked due to 10 failed logins</title>
      <link>https://www.oomkill.com/account-locked-due-to-10-failed-logins/</link>
      <pubDate>Tue, 19 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/account-locked-due-to-10-failed-logins/</guid>
      <description>进入后，找到linux16 开头的一行！将ro改为 rw init=/sysroot/bin/sh
查看passwd和 shadow 发现用户并没有锁，于是想到，应该是pam的设置。
text 1 pam_tally2.so deny=6 onerr=fail unlock_time=120 默认log在： /var/log/tallylog
text 1 2 3 4 chroot /sysroot # 使用pam_tally2命令解锁 pam_tally2 --user=root --reset rw init=/sysroot/bin/sh Reference Centos7.x破解密码
pam_tally2锁用户</description>
    </item>
    <item>
      <title>goland设置import规范</title>
      <link>https://www.oomkill.com/go-mod-specification/</link>
      <pubDate>Thu, 14 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-mod-specification/</guid>
      <description>import 规范
引入了三种类型的包，标准库包，第三方包，程序内部包，建议采用如下方式进行组织你的包：
有顺序的引入包，不同的类型采用空格分离，
第一种标准库 第二是第三方包 第三是项目包。 在项目中不要使用相对路径引入包，在goland中可以使用如下设置自动格式化为引入标准
打开设置：Editor &amp;gt; Code Style &amp;gt; Go，选择import标签，将排序改为goimports, 剩下的按照自己喜好进行修改即可
Reference goimports-group</description>
    </item>
    <item>
      <title>Linux dbus命令行套件</title>
      <link>https://www.oomkill.com/dbus-client-tutorial/</link>
      <pubDate>Mon, 11 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/dbus-client-tutorial/</guid>
      <description>D-Bus是Linux使用的进程间通信机制，允许各个进程互相访问，而不需要为每个其他组件实现自定义代码。即使对于系统管理员来说，这也是一个相当深奥的主题，但它确实有助于解释linux的另一部分是如何工作的。
这里主要介绍 dbus-send 与 GDbus cli工具，其他的还有QtDbus , d-feet&amp;hellip;
命令行工具dbus-send ，是freedesktoop提供的dbus包配套的命令客户端工具，可用于发送dbus消息。
GDbus GLib实现的dbus工具。较与 dbus-send，拥有更完整的功能。
d-feet: 可以处理所有D-Bus服务的GUI应用程序。
dbus-send dbus有两种消息总线 （message bus）：system bus 和 session bus，通过使用 --system和 --session 选项来通过dbus-send 向系统总线或会话总线发送消息。如果两者都未指定，默认为**session bus*.
借此，顺道聊下 system bus 和 session bus：
System Bus:
在桌面上，为所有用户提供一条总线. 专用于系统服务。 有关于低级时间，例如 网络连接，USB设备。 在嵌入式Linux系统中，system bus是唯一D-Bus类型。 Session Bus:
每个用户会话一个实例 为用户应用提供那个桌面服务。 连接到 X-session 参数选项 参数 说明 --dest=NAME 这个是必选的参数，指定要接收消息的接口名称。例如 org.freedesktop.ExampleName --print-reply 打印回复消息 --print-reply=literal 如选项一样，打印回复正文。如有特殊字符，如对象或 object 则按字面打印，没有标点符号、转义字符等。 --reply-timeout= 可选参数，等待回复的超时时长，单位为 毫秒。 --system --session --type=method_call signal 必须始终指定要发送的消息的对象路径和名称。以下参数（如果有）是消息内容（消息参数）。这些值作为类型指定的值给出，可能包括如下所述的容器（数组、dict和变体）。
支持参数 dbus-send 发送的消息，在调用方法需要传参数时，必须将这些值给出。dbus-send 支持传入的参数的类型，并不为D-Bus支持的所有的数据类型，仅为一些简单的类型：如</description>
    </item>
    <item>
      <title>python drf之viewset</title>
      <link>https://www.oomkill.com/python-django-restframework-view-set/</link>
      <pubDate>Wed, 06 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/python-django-restframework-view-set/</guid>
      <description>What is Views drf提供了两个基类，五个视图扩展类，9个视图集
drf提供了一个Django中view的子类APIView ,主要变动大概为以下：
重新封装了Request 与 Response实例。 使用了独有的Request与Response对象，并且提供了专有的解析器 Parser 可以根据HTTP Content-Type 指明的请求数据进行解析。 增加了自有的鉴权/节流 在django中dispatch() 分发前，会对请求进行身份认证、权限检查、流量控制。 异常捕获 APIException。 APIView implement
python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @classmethod def as_view(cls, **initkwargs): .... # 调用父类的方法，Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx view = super(APIView, cls).as_view(**initkwargs) view.cls = cls # 并且生成一个新的request view.initkwargs = initkwargs # Note: session based authentication is explicitly CSRF validated, # all other authentication is CSRF exempt.</description>
    </item>
    <item>
      <title>python drf之Serializer</title>
      <link>https://www.oomkill.com/python-django-restframework-serializers/</link>
      <pubDate>Mon, 04 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/python-django-restframework-serializers/</guid>
      <description>What is serializers？ serializers主要作用是将原生的Python数据类型（如 model querysets ）转换为web中通用的JSON，XML或其他内容类型。
DRF 提供了一个Serializer类，它为您提供了种强大的通用方法来控制响应的输出，以及一个ModelSerializer 类，它为创建处理 model instance 和 serializers 提供了一个序列化的快捷方式。
Reference drf serializers manual
How to Declaring Serializers? 序列化一个django model
python 1 2 3 4 5 6 7 class Comment: def __init__(self, email, content, created=None): self.email = email self.content = content self.created = created or datetime.now() comment = Comment(email=&amp;#39;leila@example.com&amp;#39;, content=&amp;#39;foo bar&amp;#39;) 声明Serializers，可以用来序列化与反序列化对象 Comment的属性及值。
python 1 2 3 4 5 6 from rest_framework import serializers class CommentSerializer(serializers.</description>
    </item>
    <item>
      <title>python django使用</title>
      <link>https://www.oomkill.com/python-django/</link>
      <pubDate>Sun, 03 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/python-django/</guid>
      <description>路由匹配 django中默认匹配页 text 1 url(r&amp;#39;^$&amp;#39;, views.login), django中404匹配 text 1 url(r&amp;#39;^$&amp;#39;, views.login), # 需要放置最后，不过一般不推荐，都是通过异常捕获处理 named group 名称组 https://docs.djangoproject.com/en/1.11/topics/http/urls/#named-groups
text 1 url(r&amp;#39;^test[0-9]{4}&amp;#39;,views.login) 反向解析 别名不能出现冲突
text 1 2 from django.shortcuts import reverse reverse(xxx) 名称组反向解析 无名分组
python 1 2 3 4 5 6 # 路由部分 url(r&amp;#39;^index/(\d+)/&amp;#39;, views.home, name=&amp;#39;xxx&amp;#39;) # 前端 &amp;lt;a href=&amp;#34;{% url &amp;#39;id&amp;#39; obj.id %}&amp;#34; class=&amp;#34;btn btn-primary btn-xs&amp;#34;&amp;gt;remove&amp;lt;/a&amp;gt;s # 后端 print reverse(&amp;#39;id&amp;#39;, args=(id,)) 有名称分组
python 1 2 3 4 5 6 7 8 # 路由部分 url(r&amp;#34;^userdel/(?</description>
    </item>
    <item>
      <title>django ORM</title>
      <link>https://www.oomkill.com/django-orm/</link>
      <pubDate>Sat, 02 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/django-orm/</guid>
      <description>https://www.cnblogs.com/Dominic-Ji/p/11516152.html
对象关系映射（Object Relational Mapping，简称ORM）模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。
简单的说，ORM是通过使用描述对象和数据库之间映射的元数据，将程序中的对象自动持久化到关系数据库中。
ORM在业务逻辑层和数据库层之间充当了桥梁的作用。
django中仅测试ORM 导入model，然后直接使用对应对象进行ORM操作。
text 1 2 3 4 5 6 7 import os if __name__ == &amp;#34;__main__&amp;#34;: os.environ.setdefault(&amp;#34;DJANGO_SETTINGS_MODULE&amp;#34;, &amp;#34;app.settings&amp;#34;) import django django.setup() from xxx import models models.User.objects.all() 连接数据库 django配置数据库
python 1 2 3 4 5 6 7 8 9 10 DATABASES = { &amp;#39;default&amp;#39;: { &amp;#39;ENGINE&amp;#39;: &amp;#39;django.db.backends.mysql&amp;#39;, &amp;#39;USER&amp;#39;: &amp;#39;root&amp;#39;, &amp;#39;PASSWORD&amp;#39;: &amp;#39;111&amp;#39;, &amp;#39;HOST&amp;#39;:&amp;#39;127.0.0.1&amp;#39;, &amp;#39;NAME&amp;#39;: &amp;#39;book&amp;#39;, &amp;#39;CHARSET&amp;#39;: &amp;#39;utf8&amp;#39; } } 可选：pymysql 使用模块连接MySQL数据库:：在项目中__init__.py 文件中添加配置：
python 1 2 import pymysql pymysql.</description>
    </item>
    <item>
      <title>mysql5.6 innodb_large_prefix引起的一个异常</title>
      <link>https://www.oomkill.com/mysql5.6-innodb_large_prefix-abnormal/</link>
      <pubDate>Sat, 02 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/mysql5.6-innodb_large_prefix-abnormal/</guid>
      <description>phenomenon： Specified key was too long; max key length is 3072 bytes
在修改一个数据库字段时，字段容量被限制为了表前缀的大小而不是本身的容量大小
查了一下innodb_large_prefix究竟是什么？
动态行格式DYNAMIC row format 支持最大的索引前缀(3072)。由变量innodb_large_prefix进行控制。
By default, the index key prefix length limit is 767 bytes. See Section 13.1.13, “CREATE INDEX Statement”. For example, you might hit this limit with a column prefix index of more than 255 characters on a TEXT or VARCHAR column, assuming a utf8mb3 character set and the maximum of 3 bytes for each character.</description>
    </item>
    <item>
      <title>由PIPE size 引起的线上故障</title>
      <link>https://www.oomkill.com/pipe-size-problem/</link>
      <pubDate>Sat, 02 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/pipe-size-problem/</guid>
      <description>sence：python中使用subprocess.Popen(cmd, stdout=sys.STDOUT, stderr=sys.STDERR, shell=True) ，stdout, stderr 为None.
在错误中执行是无法捕获 stderr的内容，后面将上面的改为 subprocess.Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True),发现是可以拿到 stderr, 但是会遇到大量任务hanging，造成线上事故。
为此特意查询subprocess的一些参数的说明。
stdin stdout stderr 如果这些参数为 PIPE, 此时会为一个文件句柄，而传入其他（例如 sys.stdout 、None 等）的则为None
正如这里介绍的一样，subprocess 。
而使用 PIPE，却导致程序 hanging。一般来说不推荐使用 stdout=PIPE stderr=PIPE，这样会导致一个死锁，子进程会将输入的内容输入到 pipe，直到操作系统从buffer中读取出输入的内容。
查询手册可以看到确实是这个问题 Refernce
Warning This will deadlock when using stdout=PIPE and/or stderr=PIPE and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that.</description>
    </item>
    <item>
      <title>go面试题收集</title>
      <link>https://www.oomkill.com/interview-go/</link>
      <pubDate>Fri, 01 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/interview-go/</guid>
      <description>数据结构 数据类型总结 Go语言将数据类型分为四类：基础类型、复合类型、引用类型和接口类型。
基础数据类型包括：
基础类型： 布尔型、整型、浮点型、复数型、字符型、字符串型、错误类型。 复合数据类型包括： 指针、数组、切片、字典、通道、结构体、接口。 什么是反射 在计算机科学领域，反射是指一类应用，它们能够自描述和自控制。
在go中，编译时不知道类型的情况下，可更新变量、运行时查看值、调用方法以及直接对他们的布局进行操作的机制，称为反射。
场景：无法透视一个未知类型的时候，这时候就需要有反射来帮忙你处理，反射使用TypeOf和ValueOf函数从接口中获取目标对象的信息，轻松完成目的。
rune与byte的区别 byte是uint8、rune为uint32，一个仅限于ascii码的值，一个支持更多的值。rune比byte能表达更多的数。 golang默认使用utf8编码，一个中文占用3字节，一个utf8数字占用1字节，utf8字母占用1字节 切片 切片的扩容：切片扩容，一般方式：上一次容量的2倍，超过1024字节，每次扩容上一次的1/4
切片的截取：在截取时，capacity 不能超过原slice的 capacity
new() 与 make() 的区别 new(T) 和 make(T, args) 是Go语言内建函数，用来分配内存，但适用的类型不用。
new函数用于分配指定类型的零值对象，并返回指向其内存地址的指针。例如，new(int)将分配一个类型为int且值为0的对象，并返回一个指向该地址的指针。可以使用*运算符访问指针指向的值。 make函数用于创建和初始化内置类型（如map、slice、channel）的数据结构，并返回其指针。它比new函数更加复杂很多，因为它需要知道类型的大小和结构，以便为其分配内存并初始化其字段或元素。例如，make(map[string]int)将创建一个空的map。它有一个string类型的键和一个int类型的值。 nil切片和空切片指向的地址一样吗？ nil切片和空切片指向的地址==不一样==。nil空切片引用数组指针地址为0（无指向任何实际地址） 空切片的引用数组指针地址是有的，且固定为一个值 什么是Receiver Golang的Receiver是绑定function到特定type成为其method的一个参数，即一个function加了receiver就成为一个type的method。
构体方法跟结构体指针方法的区别（Receiver和指针Receiver的区别） T 的方法集仅拥有 T Receiver。 *T 方法集则包含全部方法 (Receiver + *Receiver)。 sync.once 是 Golang package 中使方法只执行一次的对象实现，作用与 init 函数类似。但也有所不同
init 函数是在文件包首次被加载的时候执行，且只执行一次
sync.Onc 是在代码运行中需要的时候执行，且只执行一次
当一个函数不希望程序在一开始的时候就被执行的时候，我们可以使用 sync.Once
实现：sync.Once 的源码实现非常简单，采用的是双重检测锁机制 (Double-checked Locking)，是并发场景下懒汉式单例模式的一种实现方式
首先判断 done 是否等于 0，等于 0 则表示回调函数还未被执行 加锁，确保并发安全 在执行函数前，二次确认 done 是否等于 0，等于 0 则执行 将 done 置 1，同时释放锁 疑问一: 为什么不使用乐观锁 CAS 简单的来说就是 f() 的执行结果最终可能是不成功的，所以你会看到现在采用的是双重检测锁机制来实现，同时需要等 f() 执行完成才修改 done 值 疑问二: 为什么读取 done 值的方式没有统一 比较 done 是否等于 0，为什么有的地方用的是 atomic.</description>
    </item>
    <item>
      <title>kubernetes面试题收集</title>
      <link>https://www.oomkill.com/interview-kubernetes/</link>
      <pubDate>Fri, 01 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/interview-kubernetes/</guid>
      <description>Kubernetes概念 Ingress和LoadBalancer的区别 Ingress通常用于将HTTP(S)流量路由到Kubernetes群集内部的服务，支持复杂路径路由和负载均衡算法 LB则是通过提供商提供一种外部流量引入到集群内的组件，通常为2 3层 Ingress本身是基于service的，引入流量时依赖 kube-proxy LB则是独立的组件，最小接入单元也是service，而通过2 3层的广播等功能可以提供多节点的引入 功能：Ingress是一个规范，LB则是一种实现 实现方式：ingress通过扩展Kubernetes API+controller, 而LB除此外还需要外部设备提供（软硬件，云组件） kubernetes之最小单元 Pod最小可调度单元，最小部署单元 容器：容器是最小的执行单元 Namespace：最小隔离单元 Service：最小接入单元 etcd用的什么算法，简单解释一下 raft算法 强一致性 同一时间只能有一个leader,所有的操作都在leader上。
Pod 的生命周期 Pod 状态始终处于一下几个状态之一:
Pending: 部署 Pod 事务已被集群受理，但当前容器镜像还未下载完或现有资源无法满足 Pod 的资源需求 Running: 所有容器已被创建，并被部署到节点上 Successed: Pod 成功退出，并不会被重启 Failed: Pod 中有容器被终止 Unknown: 未知原因，如 kube-apiserver 无法与 Pod 进行通讯 Kubernetes有哪些不同类型的服务？ cluster ip Node Port Load Balancer Extrenal Name 什么是ETCD？ Etcd是用Go编程语言编写的，是一个分布式键值存储，用于协调分布式工作。因此，Etcd存储Kubernetes集群的配置数据，表示在任何给定时间点的集群状态。
什么是Ingress网络，它是如何工作的？ Ingress网络是一组规则，充当Kubernetes集群的入口点。这允许入站连接，可以将其配置为通过可访问的URL，负载平衡流量或通过提供基于名称的虚拟主机从外部提供服务。因此，Ingress是一个API对象，通常通过HTTP管理集群中服务的外部访问，是暴露服务的最有效方式。
什么是Headless Service？ Headless Service类似于“普通”服务，但没有群集IP。此服务使您可以直接访问pod，而无需通过代理访问它。
什么是集群联邦？ 在联邦集群的帮助下，可以将多个Kubernetes集群作为单个集群进行管理。因此，您可以在数据中心/云中创建多个Kubernetes集群，并使用联邦来在一个位置控制/管理它们。
联合集群可以通过执行以下两项操作来实现此目的。请参考下图。
kube-proxy的作用 kube-proxy运行在所有节点上，它监听apiserver中service和endpoint的变化情况，创建路由规则以提供服务IP和负载均衡功能。简单理解此进程是Service的透明代理兼负载均衡器，其核心功能是将到某个Service的访问请求转发到后端的多个Pod实例上。
kube-proxy iptables的原理 Kubernetes从1.</description>
    </item>
    <item>
      <title>操作系统类面试题收集</title>
      <link>https://www.oomkill.com/interview-linux/</link>
      <pubDate>Fri, 01 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/interview-linux/</guid>
      <description>Linux 基础 进程 如何查找特定进程消耗多少内存 bash 1 ps aux --sort=-%mem 按住 ctrl + c 会发生什么 按下 Ctrl + C 时，会向当前正在运行的前台进程发送一个信号，具体来说是 SIGINT 信号（Interrupt Signal，中断信号）。这个信号的作用是请求进程中断执行，通常会导致进程终止。信号编号是 2。
如果程序有处理信号，那么将不会发生任何事情。
守护、僵⼫、孤⼉进程的概念终端 【答】
守护进程：运⾏在后台的⼀种特殊进程，独⽴于控制终端并周期性地执⾏某些任务。 僵⼫进程：⼀个进程 fork ⼦进程，⼦进程退出，⽽⽗进程没有 wait/waitpid⼦进程，那么⼦进程的进程描述符仍保存在系统中，这样的进程称为僵⼫进程。 孤⼉进程：⼀个⽗进程退出，⽽它的⼀个或多个⼦进程还在运⾏，这些⼦进程称为孤⼉进程。（孤⼉进程将由 init 进程收养并对它们完成状态收集⼯作） 进程间通讯方式有哪些？ Pipe：无名管道，最基本的IPC，单向通信，仅在父/子进程之间，也就是将一个程序的输出直接交给另一个程序的输入。常见使用为 ps -ef|grep xxx FIFO [(First in, First out)] 或 有名管道（named pipe）:与Pipe不同，FIFO可以让两个不相关的进程可以使用FIFO。单向。 Socket 和 Unix Domain Socket：socket和Unix套接字，双向。适用于网络通信，但也可以在本地使用。适用于不同的协议。 消息队列 Message Queue: SysV 消息队列、POSIX 消息队列。 Signal: 信号，是发送到正在运行的进程通知以触发其事件的特定行为，是IPC的一种有限形式。 Semaphore：信号量，通常用于IPC或同一进程内的线程间通信。他们之间使用队列进行消息传递、控制或内容的传递。（常见SysV 信号量、POSIX 信号量） Shared memory：（常见SysV 共享内存、POSIX 共享内存）。共享内存，是在进程（程序）之间传递数据的有效方式，目的是在其之间提供通信。 BASH和DOS控制台之间的主要区别在于3个方面： 答案：
BASH命令区分大小写，而DOS命令则不区分; 在BASH下，/ character是目录分隔符，\ 作为转义字符。在DOS下，/ 用作命令参数分隔符，\ 是目录分隔符 DOS遵循命名文件中的约定，即8个字符的文件名后跟一个点，扩展名为3个字符。BASH没有遵循这样的惯例。 Linux 中进程有哪几种状态？在 ps 显示出来的信息中，分别用什么符号表示的？ 答案：</description>
    </item>
    <item>
      <title>监控类面试题</title>
      <link>https://www.oomkill.com/interview-monitor/</link>
      <pubDate>Fri, 01 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/interview-monitor/</guid>
      <description>Prometheus的四种数据类型 Counter(计数器类型) Counter类型的指标的工作方式和计数器一样，只增不减 Gauge(仪表盘类型) Gauge是可增可减的指标类，通常用于反应当前应用的状态。 Histogram 主要用于表示一段时间范围内对数据进行采样 Summary(摘要类型) Summary类型和Histogram类型相似，主要用于表示一段时间内数据采样结果 Prometheus 的局限 Prometheus 是基于 Metric 的监控，不适用于日志（Logs）、事件(Event)、调用链(Tracing)。 Prometheus 默认是 Pull 模型，合理规划你的网络，尽量不要转发。对于集群化和水平扩展，官方和社区都没有银弹，需要合理选择 Federate、Cortex、Thanos等方案。 监控系统一般情况下可用性大于一致性，容忍部分副本数据丢失，保证查询请求成功。这个后面说Thanos 去重的时候会提到。 Prometheus 不一定保证数据准确，这里的不准确一是指 rate、histogram_quantile 等函数会做统计和推断，产生一些反直觉的结果，这个后面会详细展开。二来查询范围过长要做降采样，势必会造成数据精度丢失，不过这是时序数据的特点，也是不同于日志系统的地方 采集组件 All IN One Prometheus 体系中 Exporter 都是独立的，每个组件各司其职，如机器资源用 Node-Exporter，Gpu 有Nvidia Exporter等等。但是 Exporter 越多，运维压力越大，尤其是对 Agent做资源控制、版本升级。我们尝试对一些Exporter进行组合，方案有二：
通过主进程拉起N个 Exporter 进程，仍然可以跟着社区版本做更新、bug fix。 用Telegraf来支持各种类型的 Input，N 合 1。另外，Node-Exporter 不支持进程监控，可以加一个Process-Exporter，也可以用上边提到的Telegraf，使用 procstat 的 input来采集进程指标。 合理选择黄金指标 采集的指标有很多，我们应该关注哪些？Google 在 “Sre Handbook” 中提出了“四个黄金信号”：延迟、流量、错误数、饱和度。实际操作中可以使用 Use 或 Red 方法作为指导，Use 用于资源，Red 用于服务。
Use 方法：Utilization、Saturation、Errors。如 Cadvisor 数据 Red 方法：Rate、Errors、Duration。如 Apiserver 性能指标 Prometheus 采集中常见的服务分三种：</description>
    </item>
    <item>
      <title>网络基础面试题收集</title>
      <link>https://www.oomkill.com/interview-network/</link>
      <pubDate>Fri, 01 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/interview-network/</guid>
      <description>域名相关 什么是DNS劫持 DNS劫持就是通过劫持了DNS服务器，通过某些手段取得某域名的解析记录控制权，进而修改此域名的解析结果，导致对该域名的访问由原IP地址转入到修改后的指定IP，其结果就是对特定的网址不能访问或访问的是假网址，从而实现窃取资料或者破坏原有正常服务的目的。DNS劫持通过篡改DNS服务器上的数据返回给用户一个错误的查询结果来实现的。
通俗来讲：DNS劫持就是指用户访问一个被标记的地址时，DNS服务器故意将此地址指向一个错误的IP地址的行为。范例，网通、电信、铁通的某些用户有时候会发现自己打算访问一个地址，却被转向了各种推送广告等网站，这就是DNS劫持。
DNS劫持症状：在某些地区的用户在成功连接宽带后，首次打开任何页面都指向ISP提供的“电信互联星空”、“网通黄页广告”等内容页面。还有就是曾经出现过用户访问Google域名的时候出现了百度的网站。这些都属于DNS劫持。
解决：对于DNS劫持，可以采用使用国外免费公用的DNS服务器解决。例如OpenDNS（208.67.222.222）或GoogleDNS（8.8.8.8）。
什么是DNS污染 DNS污染是指在DNS服务器中修改DNS解析结果的过程，以便将用户重定向到恶意网站或欺骗性网站，而不是所期望的目标网站。
攻击者可以通过多种方式进行DNS污染攻击。最常见的手段是在用户的网络中添加一个恶意DNS服务器，或者在受感染的计算机上运行一个恶意DNS服务器。当用户试图连接到互联网上的某个网站时，计算机将查询DNS服务器以查找目标网站的IP地址。如果攻击者控制的恶意DNS服务器已将相应的IP地址修改为攻击者的网站，则用户将被重定向到恶意网站或欺骗性网站。
DNS污染发生在用户请求的第一步上，直接从协议上对用户的DNS请求进行干扰。 DNS污染症状：目前一些被禁止访问的网站很多就是通过DNS污染来实现的，例如YouTube、Facebook等网站。
解决：
可靠的DNS服务器，但这种方式效果不佳 手动修改Hosts文件 使用VPN或域名远程解析 加密通信：VPN可以加密整个通信过程，这意味着攻击者无法窃取UDP数据包中的任何信息，包括DNS查询请求和响应。这样可以避免DNS查询被篡改的风险。 虚拟IP地址：VPN会给每个用户分配其所连接的虚拟IP地址，使用户的真实IP地址不会暴露在公共互联网中。这样，DNS服务器只能看到VPN服务器的IP地址，而无法识别用户的IP地址。这意味着攻击者无法跟踪用户的访问历史，从而减少遭受DNS污染攻击的风险。 总结：
DNS污染，指的是用户访问一个地址，国内的服务器(非DNS)监控到用户访问的已经被标记地址时，服务器伪装成DNS服务器向用户发回错误的地址的行为。范例，访问Youtube、Facebook之类网站等出现的状况。
什么是域名被墙 这种情况一般出现在解析为国外地址的域名上，假如域名下的网站非法信息多，敏感，又不整改，会直接被G.F.W墙掉，就是通常所说的被封锁、被屏蔽、被和谐，结果就是访问域名是打不开的，但是解析是正常的。此时域名在国内是无法使用的，国外可以访问和使用。
主要有以下几种情况：
ip 被墙 解决：换 ip 。 域名被 url 重置（访问时出现ERR_CONNECTION_RESET 或 “连接重置” 换域名 做301跳转，(有专门服务商)，域名通过解析到国内301服务商，重定向到真是国外IP，以减少流量和权重的丢失。 上 https或域名备案，智能解析分国内，国外 。 可以使用HTTPS；一般来讲解析到国外的IP的域名，有敏感词会被重置，GFW可以进行敏感词检测（http为明文），使用https加密GFW无法检测数据包内容 ，（客户端与服务端默认会有公钥私钥，而GFW没有）。 域名被国家出口 dns 污染，解决：用国内 dns ，备案回国。 域名被省级 dns 污染，解决：能做到这个这里可能为内部或对应运营商被黑（只能进行dns清洗，一般大流量域名了） 什么是DNS清洗？ DNS清洗是一项旨在阻止访问特定网站和域名的措施，在该措施中，Internet服务提供商（ISP）通过其服务器筛选特定网站的DNS查询，并将查询重定向到一个错误的IP地址（通常是一个不存在的地址），从而防止用户访问该网站。这种措施通常是由政府、公司或组织实施，旨在防止用户接触到不适当、危险或非法的内容。
网络攻击相关 什么是TCP的SYN攻击？如何预防？ TCP SYN攻击是一种利用TCP协议三次握手机制的攻击。攻击者发送大量伪造的TCP SYN请求（数据包），然后在TCP三次握手建立连接的第二步时停止（使服务器不断地向攻击者发送SYN-ACK确认，但攻击者不回复ACK确认），从而导致服务器等待客户端的确认信号很长时间，最终占用服务器的资源而无法处理新的请求。
为了预防TCP SYN攻击，可以采取以下措施：
服务器操作系统的设置：可以设置TCP的连接数和时间等参数，限制每个IP地址的连接数，设置连接超时时间。 防火墙设置：可以设置防火墙规则，根据IP地址、端口等信息对连接进行过滤，控制IP地址的访问等。 加强网络监测：使用入侵检测系统（IDS）对流量进行实时监控，并对异常流量进行报警处理。 使用SYN Cookies：SYN cookies是一种可以防止SYN攻击的技术，它通过特殊的算法对TCP连接进行加密，并保存在服务器端，当客户端发送响应时，服务器端可以对连接进行识别和验证，从而防止SYN攻击。 增加硬件设备：可以增加具有流量分析和过滤功能的硬件设备来协助防御SYN攻击，这种设备可以通过分析流量实现精细化的流量分析和识别。 ddos攻击的类型 DDoS攻击（Distributed Denial of Service）是一种利用许多计算机和网络设备构成的“僵尸网络”对一个或多个目标服务器发起攻击，从而占用大量的网络资源，耗尽系统资源，导致服务拒绝的攻击方式。DDoS攻击的类型可以分为以下几种：
带宽攻击（Bandwidth-based Attack）：利用大量的数据流或报文，通过消耗目标系统的网络带宽使其服务不能正常传输。 应用层攻击（Application-Layer Attack）：利用正常流量模拟合法用户的请求，通过消耗服务器CPU和内存资源使其无法处理合法请求。 反射式攻击（Reflection Attack）：使用伪造的IP地址向网络中的一个或多个服务器发起请求，这些服务器会响应请求，但响应信息将被发回目标服务器，从而形成了一次反射式攻击。 慢速攻击（Slowloris Attack）：利用HTTP协议的设计漏洞，向目标服务器发送大量不完整请求，从而占用目标服务器处理请求的线程资源。 IoT攻击（IoT Attack）：通过侵入大量的物联网设备，如路由器、摄像头、智能家居等，利用这些设备来发起攻击，构建大规模的“僵尸网络”。 DNS Amplification攻击：攻击者向域名服务器发送请求，利用伪造的IP地址和请求报文，让服务器向目标主机发送大量的DNS解析响应数据包，从而使目标系统在短时间内遭受网络拥塞。 NTP Amplification攻击：攻击者伪造IP地址，向其余互联网上安装有网络时间服务器（Network Time Protocol，NTP）软件的服务器发送请求，从而获取大量NTP响应包，最终将其转发到目标IP地址，从而占用目标系统的网络带宽。 SYN Flood攻击：攻击者向目标服务器发送大量的TCP SYN请求，但却不发送客户端的应答确认，造成服务器长时间处于等待状态，无法接受正常的TCP连接请求。 HTTP Flood攻击：攻击者利用HTTP叠加攻击、HTTP POST攻击等手段，向目标系统发送大量HTTP请求和数据包，造成目标系统资源的耗尽，从而导致服务不可用。 ICMP Flood攻击：攻击者向目标系统发送大量的ICMP数据包，造成目标系统CPU和内存资源的消耗，从而导致系统缓慢或崩溃。 什么是反射式攻击 反射式攻击（Reflection Attack）是一种利用网络协议的设计缺陷进行攻击的方式。攻击者通常会利用一些可以进行源地址欺骗或反射的协议，例如Domain Name System（DNS），Simple Network Management Protocol（SNMP），和Network Time Protocol（NTP）等。攻击者利用这些协议在网络中进行广播，构造一些请求消息，伪造源IP地址为目标IP地址，将请求消息发送给网络上的服务器，要求其向目标IP地址回送响应。这样攻击者就可以通过伪造的IP地址对目标系统进行攻击，占用它的网络带宽和资源，极大地降低了目标系统的可用性。</description>
    </item>
    <item>
      <title>运维类面试题收集</title>
      <link>https://www.oomkill.com/interview-om/</link>
      <pubDate>Fri, 01 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/interview-om/</guid>
      <description>如何优化 Linux系统（笼统） 不用root，添加普通用户，通过sudo授权管理 更改默认的远程连接SSH服务端口及禁止root用户远程连接 定时自动更新服务器时间 配置国内yum源 关闭selinux及iptables（iptables工作场景如果有外网IP一定要打开，高并发除外） 调整文件描述符的数量 精简开机启动服务（crond rsyslog network sshd） 内核参数优化（/etc/sysctl.conf） 更改字符集，支持中文，但建议还是用英文字符集，防止乱码 锁定关键系统文件 清空/etc/issue，去除系统及内核版本登录前的屏幕显示 基础命令 ps aux 中的VSZ代表什么意思，RSS代表什么意思 VSZ:虚拟内存集,进程占用的虚拟内存空间 RSS:物理内存集,进程战用实际物理内存空间 shell下32位随机密码生成 text 1 cat /dev/urandom | head -1 | md5sum | head -c 32 &amp;gt;&amp;gt; /pass 将生成的32位随机数 保存到/pass文件里了
统计出nginx的access.log中访问量最多的5个IP text 1 cat access_log | awk &amp;#39;{print $1}&amp;#39; | sort | uniq -c | sort -n -r | head -5 web与lb 讲述一下LVS三种模式的工作过程 LVS负载的原理，和Nginx负载有啥区别 VS/NAT：（Virtual Server via Network Address Translation）</description>
    </item>
    <item>
      <title>WSL与Windows环境共享</title>
      <link>https://www.oomkill.com/wsl-share-to-win/</link>
      <pubDate>Wed, 28 Jul 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/wsl-share-to-win/</guid>
      <description>在使用 wsl 时，总是需要执行 windows 的 cmd，但是windows命令行对于大多数人使用起来还是不习惯，微软提供了在 windows 中Linux与Windows的命令互通，即可以使用cmd shell执行Linux命令，也可以使用bash shell来执行windows命令。
WSL可对 Windows 与 Linux 之间的集成操作：
从 Linux shell（如 Ubuntu）运行 Windows 工具（任意 .exe）。 从 Windows shell（即 PowerShell or cmd ）运行 Linux 命令（如 cd ls grep）。 在 WSL与windows之间共享环境变量。 （版本 17063+） 满足上述要求，可以很好地使用windows的软件在WSL中畅快的操作，即空WSL环境拥有了python解析器 docker等操作。
如何在 WSL和 Windows 之间共享环境变量 从Build 17063 开始，可以利用 WSLENV 来增强 Win/WSL 之间的环境变量互操作。
什么是WSLENV WSLENV 是一个以冒号分隔的环境变量列表，当从 WSL 启动 WSL进程或 Win进程时包含的变量 每个变量都可以以斜杠作为后缀，后跟标识位以指定它的转换方式 WSLENV 可以在 WSL 和 Win32 之间转换的路径 WSLENV。在WSL中，是以冒号分隔的列表。在Win中，是以分号分隔的列表 可以在.bashrc或者windows自定义环境变量中设置WSLENV 例如：一个WSLENV应该设置为
text 1 WSLENV=GOPATH/l:USERPROFILE/w:SOMEVAR/wp 在17063之前，WSL访问Windows环境变量唯一方法是使用全路径（可以使用全路径从WSL下启动Win32可执行文件）。但是没有办法在WSL中设置环境变量，调用Win进程，并期望将该变量传送到进程。</description>
    </item>
    <item>
      <title>windows递归复制指定时间后修改过的文件</title>
      <link>https://www.oomkill.com/recursive-replication-with-dos/</link>
      <pubDate>Fri, 23 Jul 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/recursive-replication-with-dos/</guid>
      <description>因为在拷贝web站点时，也会存在更新，需要定期覆盖新的内容，就是上次覆盖的时间和到这次时间内修改过的文件都复制。
实现命令xcopy
text 1 2 3 4 5 6 xcopy src dest $ xcopy D:\WWW\back1\* D:\WWW\back4 /D:05-22-2018 /F /E /y D:\WWW\back1\db_qbe.php -&amp;gt; D:\WWW\back4\db_qbe.php D:\WWW\back1\docs.css -&amp;gt; D:\WWW\back4\docs.css D:\WWW\back1\test\changelog.php -&amp;gt; D:\WWW\back4\test\changelog.php 复制了 3 个文件 /D:mm-dd-yyyy
/F 打印复制过程
/E 递归复制目录和子目录包括空目录
/Y 禁止提示</description>
    </item>
    <item>
      <title>python使用虚拟环境venv</title>
      <link>https://www.oomkill.com/python-venv/</link>
      <pubDate>Mon, 14 Jun 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/python-venv/</guid>
      <description>venv模块支持使用自己的站点目录创建轻量级“虚拟环境”，可选择与系统站点目录隔离。每个虚拟环境都有自己的Python二进制文件（与用于创建此环境的二进制文件的版本相匹配），并且可以在其站点目录中拥有自己独立的已安装 Python 软件包集。
3.6 版后已移除: pyvenv 是 Python 3.3 和 3.4 中创建虚拟环境的推荐工具，不过 在 Python 3.6 中已弃用。
在 3.5 版更改: 现在推荐使用 venv 来创建虚拟环境。
创建venv虚拟环境 如果使用python2，则需要安装virtualenv模块
text 1 2 pip install virtualenv python -m virtualenv {name} python3内置了 venv 模块，可以直接使用
text 1 python3 -m venv {name} 进入虚拟环境
linux
text 1 venv\Scripts\activate windows
text 1 venv\Scripts\activate.bat 退出环境
text 1 2 venv\Scripts\deactivate.bat venv\Scripts\deactivate 使用venv环境安装软件报错 Could not fetch URL https://pypi.org/simple/pip/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host=&amp;lsquo;pypi.</description>
    </item>
    <item>
      <title>awk常用案例</title>
      <link>https://www.oomkill.com/awesome-awk-command/</link>
      <pubDate>Wed, 02 Jun 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/awesome-awk-command/</guid>
      <description>工具命令集合 长期总结 - Linux日志查询命令 长期总结 - Linux网络命令合集 长期总结 - Linux性能分析命令 awk常用案例 bash shell常用示例 探索kubectl - 巧用jsonpath提取有用数据 探索kubectl - kubectl诊断命令集合 ##AWK运算符
运算符 说明 赋值运算符 = += -= *= /= %= ^= **= 逻辑运算符 || 逻辑或 &amp;amp;&amp;amp; 逻辑与 正则运算符 ~ !~ 匹配正则表达式和不匹配正则表达式 关系运算符 &amp;lt; &amp;lt;= &amp;gt; &amp;gt;= != == 关系运算符 算术运算符 + - 加，减 *** / &amp;amp;** 乘，除与求余 + - ! 一元加，减和逻辑非 ^ *** 求幂 ++ &amp;ndash; 增加或减少，作为前缀或后缀 其他运算符 $ 字段引用 空格 字符串链接符 ?</description>
    </item>
    <item>
      <title>P2P打洞技术</title>
      <link>https://www.oomkill.com/understand-hole-punchine-mechnism/</link>
      <pubDate>Wed, 02 Jun 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/understand-hole-punchine-mechnism/</guid>
      <description>P2P 概述 相比于 C/S B/S 架构来说， P2P 是由 Peer 组成。每个Peer同时是客户端也是服务器。这意味着，P2P网络中的peer点为每个其他的peer提供服务，所有节点直接相互通信，没有中心节点，并共享资源源相互联系。
P2P有结构化的P2P网络和非结构化P2P网络。如TomP2P (Java的一个框架，一个分布式哈希表，提供去中心化的键/值基础设施）。而Gnutella (第一个分散式P2P文件共享网络)，是非结构化 （unstructured）P2P网络的。另外还有两种类型的P2P网络，即集中式（centralized）P2P网络（Napster）和混合（hybrid p2p）peer网络（如Skype）。
NAT网络 由于NAT的网络模型，破坏了主机 Peer之间的端到端连接，因此P2P网络需要穿过NAT网络，而穿过NAT网络是目前为P2P技术面临的一个很大的挑战。
网络地址转换，NAT （Network Address Translation）是一种模糊指明的机制，可以将两个IP连接在一起，一个NAT设备总是拥有至少两个IP地址，（公网IP，私网IP），NAT就是将数据包上的IP地址在传输时，将私网IP转换为公网IP。每个NAT设备会维护一个NAT表，该表存储了所有活动的连接。
在创建网络映射后，NAT将源IP地址和端口更改为外部源IP地址和端口。NAT保留端口，不将新端口分配给外部源。一旦创建了映射，只要映射存在，与之联系的设备就能够发回消息。不存在NAT映射的所有来自外部的通信请求都是无法穿越NAT。因此，在P2P环境中，如果两个peer位于在NAT之后，两者都无法直接联系，因为它们之间不知道外部IP地址和源端口，NAT表中并没有其所维护的映射信息。所以NAT穿越中的主要问题之一是网络地址转换问题。
NAT网络类型 一般来讲， NAT网络可以分为四种类型: nat type
全锥型(Full Cone) 受限锥型(Restricted Cone)， 或者说是IP受限锥型 端口受限锥型(Port Restricted Cone), 或者说是IP + PORT受限锥型 对称型(Symmetric) Full Cone NAT 全锥形 全锥形网络（Full Cone NAT） 的工作原理类似于 IP 地址一对一映射。 内部 IP 和端口映射到相同的外部地址和端口。 之后，任何外部源都可以通过向外部地址发送数据包来访问内部主机。 这意味着，一旦创建了映射，任何外部主机都可以联系内部主机。如下图
地址受限形的锥形NAT Address Restricted Cone NAT 地址受限形锥形 NAT是，仅当内部主机先联系外部主机时，受限锥形 NAT 才会为相应的内部主机分配外部IP。 外部主机然后能够通过分配的外部地址联系内部主机。
对称型 Symmetric nat 对称 NAT 是最难穿过的NAT，因为对称将随机端口分配给映射。 如果外部主机首先与内部主机连接，则外部主机只能知道外部映射。 在 P2P 场景中， 如果两个Peer（主机）位于 NAT 后面，则它们无法互相通信以让另一个对等体知道所使用的映射。 此外，对称 NAT 几乎不可能知道分配的端口以通过打孔（hole Punching）建立连接。</description>
    </item>
    <item>
      <title>python中的signal</title>
      <link>https://www.oomkill.com/python-signal-handle/</link>
      <pubDate>Wed, 02 Jun 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/python-signal-handle/</guid>
      <description>什么是信号 信号（signal）&amp;ndash; 进程间通讯的一种方式，也可作为一种软件中断的方法。一个进程一旦接收到信号就会打断原来的程序执行来按照信号进行处理。
简化术语，信号是一个事件，用于中断运行功能的执行。信号始终在主Python线程中执行。对于信号，这里不做详细介绍。
Python封装了操作系统的信号功能的库 singal 的库。singal 库可以使我们在python程序中中实现信号机制。
https://zh.wikipedia.org/wiki/Unix%E4%BF%A1%E5%8F%B7)
Python的信号处理 首先需要了解Python为什么要提供 signal Library。信号库使我们能够使用信号处理程序，以便当接收信号时都可以执行自定义任务。
Mission：当接收到信号时执行信号处理方法
可以通过使用 signal.singal() 函数来实现此功能
Python对信号的处理 通常情况下Python 信号处理程序总是会在主 Python 主解析器的主线程中执行，即使信号是在另一个线程中接收的。 这意味着信号不能被用作线程间通信的手段。 你可以改用 threading 模块中的同步原语。
Python信号处理流程，需要对信号处理程序（signal handling ）简要说明。signal handling 是一个任务或程序，当检测到特定信号时，处理函数需要两个参数，即信号id signal number （Linux 中 1-64），与堆栈帧 frame。通过相应信号启动对应 signal handling ，signal.signal() 将为信号分配 处理函数。
如：当运行一个脚本时，取消，此时是捕获到一个信号，可以通过捕获信号方式对程序进行异步的优雅处理。通过将信号处理程序注册到应用程序中：
py 1 2 3 4 5 6 7 8 9 10 11 import signal import time def handler(a, b): # 定义一个signal handling print(&amp;#34;Signal Number:&amp;#34;, a, &amp;#34; Frame: &amp;#34;, b) signal.</description>
    </item>
    <item>
      <title>macos python安装mysqlapi集合</title>
      <link>https://www.oomkill.com/mac-mysqlapi/</link>
      <pubDate>Thu, 29 Apr 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/mac-mysqlapi/</guid>
      <description>记录一下，接了一个python2 django1.x的项目，很老了导致很多扩展无法安装
os version：macos catalina python version: 2.7.18
而django后端使用sqllite以外需要对应客户端引擎，而安装时编译依赖C客户端即实际mysql组件。
使用的数据库后端。 内建的数据库后端有：
&amp;lsquo;django.db.backends.postgresql&amp;rsquo; &amp;lsquo;django.db.backends.mysql&amp;rsquo; &amp;lsquo;django.db.backends.sqlite3&amp;rsquo; &amp;lsquo;django.db.backends.oracle&amp;rsquo;
并且修改配置实例
text 1 2 3 4 5 6 7 8 9 10 DATABASES = { &amp;#39;default&amp;#39;: { &amp;#39;ENGINE&amp;#39;: &amp;#39;django.db.backends.mysql&amp;#39;, &amp;#39;USER&amp;#39;: &amp;#39;mydatabaseuser&amp;#39;, &amp;#39;NAME&amp;#39;: &amp;#39;mydatabase&amp;#39;, &amp;#39;TEST&amp;#39;: { &amp;#39;NAME&amp;#39;: &amp;#39;mytestdatabase&amp;#39;, }, }, } brew unlink mysql
error: command &amp;lsquo;gcc&amp;rsquo; failed with exit status 1 text 1 2 3 4 5 6 creating build/temp.macosx-10.9-x86_64-2.7 gcc -fno-strict-aliasing -fno-common -dynamic -arch x86_64 -g -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -Dversion_info=(1,2,5,&amp;#39;final&amp;#39;,1) -D__version__=1.</description>
    </item>
    <item>
      <title>Linux VMware Tools详解</title>
      <link>https://www.oomkill.com/vmvare-tool-explain/</link>
      <pubDate>Wed, 17 Feb 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/vmvare-tool-explain/</guid>
      <description>VMware Tools描述 VMware Tools 中包含一系列服务和模块，可在 VMware 产品中实现多种功能，从而使用户能够更好地管理客户机操作系统，以及与客户机系统进行无缝交互。
在Linux虚拟机中安装VMware Tools 安装前准备
虚拟机必须打开cd/dvd驱动器，否则安装VMware Tools的选项无法选择 VMware Tools安装程序是使用Perl编写的，必须确认操作系统中安装Perl。 安装步骤
在虚拟机菜单中右键单击虚拟机，然后单击客户机 &amp;gt; 安装/升级 VMware Tools。
要创建一个挂载点 mkdir /mnt/cdrom
要装载 CDROM，mount /dev/cdrom /mnt/cdrom
要将安装文件文件复制到临时目录：cp /mnt/cdrom/VMwareTools*.tar.gz /tmp/；其中，* 部分是 VMware Tools 软件包的版本号，故以替代*。
解压文件：cd /tmp &amp;amp;&amp;amp; tar -zxvf VMwareTools*.tar.gz
运行PERL脚本以安装VMware Tools：cd vmware-tools-distrib &amp;amp;&amp;amp; ./vmware-install.pl，若要求选择，一路回车即可。
安装完成后清理 rm -fr {/tmp/VMwareTools*,/tmp/vmware-tools-distrib} ; yum remove perl -y，如不需要perl可以卸载
命令集合
bash 1 2 3 4 5 mkdir /mnt/cdrom mount /dev/cdrom /mnt/cdrom cp /mnt/cdrom/VMwareTools*.tar.gz /tmp/ cd /tmp &amp;amp;&amp;amp; tar -xf VMwareTools*.</description>
    </item>
    <item>
      <title>calico网络策略</title>
      <link>https://www.oomkill.com/calico-network-policy/</link>
      <pubDate>Mon, 15 Feb 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/calico-network-policy/</guid>
      <description>什么是网络策略 在Kubernetes平台中，要实现零信任网络的安全架构，Calico与istio是在Kubernetes集群中构建零信任网络必不可少的组件。
而建立和维护整个集群中的“零信任网络”中，网络策略的功能在操作上大致可以总结为使用资源配置模板来管理控制平面数据流。说白了讲网络策略就是用来控制Pod间流量的规则。
在Calico中如何编写网络策略 要使用网络策略就需要先了解Calico功能**：NetworkPolicy和GlobalNetworkPolicy**。
NetworkPolicy资源，简称np；是命名空间级别资源。规则应用于与标签选择器匹配的endpoint的集合。
GlobalNetworkPolicy资源，简称 gnp/gnps与NetworkPolicy功能一样，是整个集群级别的资源。
GlobalNetworkPolicy 与 NetworkPolicy资源的管理也与calico的部署方式有关，使用etcd作为存储时，资源的管理只能使用 calicoctl进行管理
NetworkPolicy与GlobalNetworkPolicy的构成 yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 apiVersion: projectcalico.org/v3 kind: NetworkPolicy metadata: name: allow-tcp-90 spec: selector: app == &amp;#39;envoy&amp;#39; # 应用此策略的endpoint types: # 应用策略的流量方向 - Ingress - Egress ingress: # 入口的流量规则 - action: Allow # 流量的行为 protocol: ICMP # 流量的协议 notProtocol: TCP # 匹配流量协议不为 值 的流量 source: # 流量的来源 src与dst的匹配关系为 与，所有的都生效即生效 nets: # 有效的来源IP selector: # 标签选择器 namespaceSelector: # 名称空间选择器 ports: # 端口 - 80 # 单独端口 - 6040:6050	# 端口范围 destination: # 流量的目标 egress: # 出口的流量规则 - action: Allow serviceAccountSelector: # 使用与此规则的serviceAccount NetworkPolicy使用 实例：允许6379流量可以被 role=frontend的pod访问</description>
    </item>
    <item>
      <title>基于混合云模式的calico部署</title>
      <link>https://www.oomkill.com/calico-deploy-on-hybrid-cloud/</link>
      <pubDate>Mon, 15 Feb 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/calico-deploy-on-hybrid-cloud/</guid>
      <description>开始前准备 确定calico数据存储
Calico同时支持kubernetes api和etcd数据存储。官方给出的建议是在本地部署中使用K8S API，仅支持Kubernetes模式。而官方给出的etcd则是混合部署（Calico作为Kubernetes和OpenStack的网络插件运行）的最佳数据存储。
使用etcd作为calico数据存储的好处：
允许多平台混用calico，如Kubernetes OpenStack上运行Calico Kubernetes资源与Calico资源分离 一个Calico群集，该群集不仅仅包含一个Kubernetes群集，如可与多个kubernetes集群互通。 坏处：
安装步骤繁琐 无法使用Kubernetes RBAC对calico资源的控制 无法使用Kubernetes资源对calico进行管理 下载calico部署清单 text 1 curl https://docs.projectcalico.org/manifests/calico-etcd.yaml -o calico.yaml 修改Pod CIDR Calico默认的Pod CIDR使用的是192.168.0.0/16，这里一般使用与controller-manager中的--cluster-cidr 保持一,取消资源清单内的 CALICO_IPV4POOL_CIDR变量的注释，并将其设置为与所选Pod CIDR相同的值。
calico的IP分配范围 Calico IPAM从ipPool分配IP地址。修改Pod的默认IP范围则修改清单calico.yaml中的CALICO_IPV4POOL_CIDR
配置Calico的 IP in IP 默认情况下，Calico中的IPIP已经禁用，这里使用的v3.17.2 低版本默认会使用IPIP
要开启IPIP mode则需要修改配置清单内的 CALICO_IPV4POOL_IPIP 环境变量改为 always
修改secret yaml 1 2 3 4 5 6 7 8 9 10 11 # Populate the following with etcd TLS configuration if desired, but leave blank if # not using TLS for etcd.</description>
    </item>
    <item>
      <title>Linux中169.254.0.0/24的路由来自哪里</title>
      <link>https://www.oomkill.com/linux-1692540024/</link>
      <pubDate>Mon, 08 Feb 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/linux-1692540024/</guid>
      <description>在Linux中，发现每次系统启动时，都会将（169.254.0.0/16）路由启动并将其添加到路由表中。但是并不知道这条路由具有什么功能和它到底来自于哪里？
text 1 2 3 4 5 6 $ route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 10.0.0.2 0.0.0.0 UG 0 0 0 eth0 10.0.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 169.254.0.0 0.0.0.0 255.255.0.0 U 1002 0 0 eth0 要想搞清楚路由（169.254.0.0/16）究竟来自哪里并且它的作用是什么？首先需要搞明白两个概念
zeroconf “zeroconf”或“Zero Configuration Networking” 是一种无需额外配置即可自动创建IP地址网络的技术。也被称为 “Automatic Private IP Addressing”（APIPA）。
zeroconf规范的提出者是Apple公司，其目的是让非专业用户也可以便捷的连接各种网络设备，例如计算机，打印机等。整个搭建网络的过程都是自动实现。如果没有“zeroconf”，用户必须手动，或者利用对应的服务（例如DHCP、DNS）对网络进行配置。这些过程对非技术用户和新用户们来说是很一件难的事情。
zeroconf的出现是问了解决三个问题：
为网络设备自动分配可用IP地址 解析计算机主机名 自动发现网络服务（如打印机等） zeroconf的地址选用 对于Link-local address，IPv4使用的特殊保留地址169.254.0.0/16，在RFC3927中所描述。作用是当DHCP客户端在超时和重试后扔找不到对应的DHCP服务器，它将随机从该网络(｀169.254.0.0/16｀)中获取地址。这样可以与无法获取DHCP地址的主机进行通信。
如何禁用zeroconf 要在系统引导期间禁用zeroconf路由，需要编辑/etc/sysconfig/network文件，配置以下内容
text 1 2 3 NETWORKING=YES HOSTNAME=localhost.</description>
    </item>
    <item>
      <title>基于Kubernetes的PaaS平台提供dashboard支持的一种方案</title>
      <link>https://www.oomkill.com/pass-base-dashboard-k8s/</link>
      <pubDate>Thu, 28 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/pass-base-dashboard-k8s/</guid>
      <description>本文转自博客： 我的小米粥分你一半
我一直在负责维护的PaaS平台引入了Kubernetes作为底层支持, 可以借助Kubernetes的生态做更多的事情, 这篇博客主要介绍如何为用户提供dashboard功能, 以及一些可以扩展的想法. 希望读者有一定的kubernetes使用经验, 并且了解rbac的功能。
Dashboard功能 Kubernetes原生提供了Web界面, 也就是Dashboard, 具体的参考可以见官方文档:
​	安装完成后, 我们一般是通过token来使用的, 不同的token有着不同的权限.
​	上面所说的token是Bearer Token, 除了在界面上输入之外, 你可以这么来用, 通过添加header即可.
text 1 curl -H &amp;#34;Authorization: Bearer ${TOKEN}&amp;#34; https://{dashboard}/api/myresource PaaS平台使用Dashboard简要讨论 需求分析 Dashboard本身的功能是十分强大的, 但是给所有人admin权限显然是不现实的. 对于一个普通用户来讲, PaaS平台的将他的应用(代码)部署好并运行, 他所需要关注的就只有属于他自己的项目, 平台也需要做好权限控制, 避免一个用户操作了另一个用户的应用.
权限系统设计 基于以上的需求讨论, 平台需要做的操作就是为每个用户创建属于自己的权限提供, 并限制可以访问到的资源. 考虑这样的情况:
我们有一个用户A, 他拥有自己的一个应用群组(G), 群组中部署了一系列应用程序(a1, a2…). 在Kubernetes中, 这样的群组概念我们将其映射为namespace, 群组(G) &amp;lt;=&amp;gt; 用户空间(NS), 我们需要控制的权限控制策略就变成了用户A在用户空间NS的权限控制.
token分发策略 拥有了权限控制后, 所需要打就是将token分发给用户, 当然这是一种极度不安全的做法, Kubernetes中的token创建之后一般是不会改变的, 分发这样的token会有很大的安全风险, 有两个方面:
1. 用户A将token保存了下来, 那么他就能不经过平台登录Dashboard, 这样不利于审计工作,2. token一旦泄露, PaaS平台很难做到反应(因为token脱离了平台的控制, 无法判断究竟是什么时候发生了泄露, 也无法马上吊销这个token), 安全风险比较高.</description>
    </item>
    <item>
      <title>ARP与ARP Proxy</title>
      <link>https://www.oomkill.com/arp-proxy-and-arp/</link>
      <pubDate>Wed, 20 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/arp-proxy-and-arp/</guid>
      <description>什么是arp 地址解析协议，Address Resolution Protoco，使用ARP协议可实现通过IP地址获得对应主机的的物理地址（MAC）
在TCP/IP的网络环境下，每个互联网的主机都会被分配一个32位的IP地址，这种互联网地址是在网际范围标识主机的一种逻辑地址。为了让报文在物理网路上传输，还补习要知道对方目的主机的物理地址才行。这样就存在把IP地址变换成物理地址的地址转换问题。
在以太网环境，为了正确地向目的主机传送报文，必须把目的主机的32为IP地址转换成为目的主机48位以太网地址(MAC),这个就需要在互联层有一个服务或功能将IP地址转换为相应的物理地址(MAC)，这个服务就是ARP协议.
所谓的&amp;quot;地址解析&amp;quot;，就是主机在发送帧之前将目标IP地址转换成目标MAC地址的过程。ARP协议的基本功能就是通过目标设备的IP地址，查询目标设备的MAC地址，以保证主机间互相通信的顺利进行.
ARP协议和DNS有相像之处。不同点是：DNS实在域名和IP之间解析，另外ARP协议不需要配置服务，而DNS要配置服务才行。
ARP缓存表 在每台安装有TCP/IP协议的设备都会有一个ARP缓存表（windows命令提示符里输入arp -a即可）， 表里的IP地址与MAC地址是一一对应的。
bash 1 2 3 4 5 6 7 8 9 10 C:\Users\CM&amp;gt;arp -a 接口: 192.168.1.103 --- 0x3 Internet 地址 物理地址 类型 192.168.1.1 3c-46-d8-5d-53-87 动态 192.168.1.255 ff-ff-ff-ff-ff-ff 静态 224.0.0.22 01-00-5e-00-00-16 静态 224.0.0.251 01-00-5e-00-00-fb 静态 224.0.0.252 01-00-5e-00-00-fc 静态 239.11.20.1 01-00-5e-0b-14-01 静态 239.255.255.250 01-00-5e-7f-ff-fa 静态 arp常用命令 arp -a 查看所有记录
arp -d 清除arp表
arp -s $ip $mac 将绑定IP和MAC
arp -n 不解析名称打印arp表
ARP缓存是把双刃剑 主机有了arp缓存表，可以加快arp的解析速度，减少局域网内广播风暴。</description>
    </item>
    <item>
      <title>动态路由- BGP</title>
      <link>https://www.oomkill.com/dynamic-routing-bgp/</link>
      <pubDate>Wed, 20 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/dynamic-routing-bgp/</guid>
      <description>概述 BGP Border Gateway Protocol 边界网关协议,，是一种运行于TCP上的自治系统AS（Autonomous System）之间的路由可达，并选择最佳路由的距离矢量路由协议。
早期发布的三个版本分别是BGP-1、BGP-2和BGP-3，1994年开始使用BGP-4，2006年之后单播IPv4网络使用的版本是BGP-4，其他网络（如IPv6等）使用的版本是MP-BGP。
MP-BGP是对BGP-4进行了扩展，来达到在不同网络中应用的目的，BGP-4原有的消息机制和路由机制并没有改变。MP-BGP在IPv6单播网络上的应用称为BGP4+，在IPv4组播网络上的应用称为MBGP（Multicast BGP）。
历史 为方便管理规模不断扩大的网络，网络被分成了不同的自治系统。1982年，外部网关协议EGP（Exterior Gateway Protocol）被用于实现在AS之间动态交换路由信息。但是EGP设计得比较简单，只发布网络可达的路由信息，而不对路由信息进行优选，同时也没有考虑环路避免等问题，很快就无法满足网络管理的要求。
BGP是为取代最初的EGP而设计的另一种外部网关协议。不同于最初的EGP，BGP能够进行路由优选、避免路由环路、更高效率的传递路由和维护大量的路由信息。
虽然BGP用在AS之间传递路由信息，但并非所有AS之间传递路由信息都要运行BGP。如数据中心上行到Internet的出口上，为了避免Internet海量路由对数据中心内部网络影响，设备采用静态路由代替BGP与外部网络通信。
受益
BGP从多方面保证了网络的安全性、灵活性、稳定性、可靠性和高效性：
BGP采用认证和GTSM的方式，保证了网络的安全性。
BGP提供了丰富的路由策略，能够灵活的进行路由选路，并且能指导邻居按策略发布路由。
BGP提供了路由聚合和路由衰减功能用于防止路由振荡，有效提高了网络的稳定性。
BGP使用TCP作为其传输层协议（端口号为179），并支持BGP与BFD联动、BGP Tracking和BGP GR和NSR，提高了网络的可靠性。
在邻居数目多、路由量大且大多邻居有相同出口策略场景下，BGP用按组打包技术极大提高了BGP打包发包性能。
BGP相关名词说明 名词 说明 BGP 边界网关协议（Border Gateway Protocol）是互联网上一个核心的去中心化自治路由协议，它通过维护IP路由表或前缀表来实现自治系统（AS）之间的可达性大多数ISP使用BGP来与其他ISP创建路由连接，特大型的私有IP网络也可以使用BGPBGP的通信对端（对等实体，Peer）通过TCP（端口179）会话交换数据，BGP路由器会周期地发送19字节的保活消息来维护连接。在路由协议中，只有BGP使用TCP作为传输层协议 IBGP 内部边界网关协议。同一个AS内部的两个或多个对等实体之间运行的BGP被称为IBGP IGP 内部网关协议。同一AS内部的对等实体（路由器）之间使用的协议，它存在可扩容性问题：1. 一个IGP内部应该仅有数十（最多小几百）个对等实体2. 对于端点数，也存在限制，一般在数百（最多上千）个Endpoint级别IBGP和IGP都是处理AS内部路由的，仍然需要IGP的原因是：1. IBGP之间是TCP连接，也就意味着IBGP邻居采用的是逻辑连接的方式，两个IBGP连接不一定存在实际的物理链路。所以需要有IGP来提供路由，以完成BGP路由的递归查找2. BGP协议本身实际上并不发现路由，BGP将路由发现的工作全部移交给了IGP协议，它本身着重于路由的控制 EBGP 外部边界网关协议。归属不同的AS的对等实体之间运行的BGP称为EBGP AS 自治系统（Autonomous system），一个组织（例如ISP）管辖下的所有IP网络和路由器的整体参与BGP路由的每个AS都被分配一个唯一的自治系统编号（ASN）。对BGP来说ASN是区别整个相互连接的网络中的各个网络的唯一标识。64512到65535之间的ASN编号保留给专用网络使用 RouteReflector 同一AS内如果有多个路由器参与BGP路由，则它们之间必须配置成全连通的网状结构——任意两个路由器之间都必须配置成对等实体。由于所需要TCP连接数是路由器数量的平方，这就导致了巨大的TCP连接数为了缓解这种问题，BGP支持两种方案：Route Reflector、Confederations路由反射器（Route Reflector）是AS内的一台路由器，其它所有路由器都和RR直接连接，作为RR的客户机。RR和客户机之间建立BGP连接，而客户机之间则不需要相互通信RR的工作步骤如下：1. 从非客户机IBGP对等实体学到的路由，发布给此RR的所有客户机2. 从客户机学到的路由，发布给此RR的所有非客户机和客户机3. 从EBGP对等实体学到的路由，发布给所有的非客户机和客户机RR的一个优势是配置方便，因为只需要在反射器上配置 工作负载 Workload，即运行在Calico节点上的虚机或容器 全互联 全互联网络（Full node-to-node Mesh）是指任何两个Calico节点都进行配对的L3连接模式 BGP 应用 国内IDC机房需要在 CNNIC (中国互联网信息中心)或 APNIC (亚太网络信息中心)申请自己的IP地址段和AS号，然后将自己的IP地址广播到其它网络运营商的AS中，并通过BGP协议将多个AS进行连接，从而实现可自动跨网访问。此时，当用户发出访问请求后，将根据BGP协议的机制自动在已建立连接的多个AS之间为用户提供最佳路由，从而实现不同网络运营商用户的高速访问同一机房资源。
BGP的运行 BGP使用TCP为传输层协议，TCP端口号179。路由器之间的BGP会话基于TCP连接而建立。运行BGP的路由器被称为BGP发言者（BGP Speaker），或BGP路由器。两个建立BGP会话的路由器互为对等体（或称通信对端/对等实体，peer）。BGP对等体之间交换BGP路由表。
BGP路由器只发送增量的BGP路由更新，或进行触发更新（不会周期性更新）。
BGP具有丰富的路径属性和强大的路由策略工具。</description>
    </item>
    <item>
      <title>calico network cni网络方案</title>
      <link>https://www.oomkill.com/calico-network-cni/</link>
      <pubDate>Mon, 18 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/calico-network-cni/</guid>
      <description>Calico针对容器、虚拟机的开源网络和网络安全解决方案。是纯三层的数据中心网络方案。
Calico在每一个计算节点利用Linux Kernel实现了一个高效的虚拟路由器vRouter来负责数据转发，而每个vRouter通过BGP协议负责把自己上运行的workload的路由信息向整个Calico网络内传播。（小规模部署可以直接互联 BGP full mesh，大规模下可通过指定的BGP route reflector来完成）。 这样保证最终所有的workload之间的数据流量都是通过IP路由的方式完成互联的。Calico节点组网可以直接利用数据中心的网络结构（无论是L2或者L3），不需要额外的NAT，隧道或者Overlay Network。
Calico还基于iptables还提供了丰富而灵活的网络Policy，保证通过各个节点上的ACLs来提供Workload的多租户隔离、安全组以及其他可达性限制等功能。
calico组件 在Kubernetes平台之上calico/node容器会通过DaemonSet部署到每个节点，并运行三个守护程序：
Felix：用于管理路由规则，负责状态上报。 BIRD：BGP的客户端，用于将Felix的路由信息加载到内核中，同时负责路由信息在集群中的分发。 confd：用于监视Calico存储（etcd）中的配置变更并更新BIRD的配置文件。 calicoctl使用问题
text 1 Failed to create Calico API client: invalid configuration: no configuration has been provided 默认情况下，calicoctl 将使用位于的默认KUBECONFIG从 Kubernetes APIServer 读取$(HOME)/.kube/config 。
如果默认的 KUBECONFIG 不存在，或者想从指定的存储访问信息，则需要单独配置。
bash 1 2 3 export DATASTORE_TYPE=kubernetes export DATASTORE_TYPE=etcdv3 export KUBECONFIG=~/.kube/config reference for
calico 安装配置 开始前准备
确定calico数据存储
Calico同时支持kubernetes api和etcd数据存储。官方给出的建议是在本地部署中使用K8S API，仅支持Kubernetes模式。而官方给出的etcd则是混合部署（Calico作为Kubernetes和OpenStack的网络插件运行）的最佳数据存储。
使用kubernetes api作为数据存储的安装
text 1 2 curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.</description>
    </item>
    <item>
      <title>静态路由</title>
      <link>https://www.oomkill.com/static-routing/</link>
      <pubDate>Mon, 18 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/static-routing/</guid>
      <description>在因特网中，网络连接设备用来控制网络流量和保证网络数据传输质量。常见的网络连接设备有集线器（Hub）、网桥（Bridge）、交换机（Switch）和路由器（Router）。
路由器是一种典型的网络连接设备，用来进行路由选择和报文转发。路由器根据收到报文的目的地址选择一条合适的路径（包含一个或多个路由器的网络），然后将报文传送到下一个路由器，路径终端的路由器负责将报文送交目的主机。
路由（routing）就是报文从源地址传输到目的地址的活动。路由发生在OSI网络参考模型中的第三层即网络层。当报文从路由器到目的网段有多条路由可达时，路由器可以根据路由表中最佳路由进行转发。最佳路由的选取与发现此路由的路由协议的优先级、路由的度量有关。当多条路由的协议优先级。
路由是数据通信网络中最基本的要素。路由信息就是指导报文发送的路径信息，路由的过程就是报文转发的过程。
根据路由目的地的不同，路由可划分为：
网段路由：目的地为网段，IPv4地址子网掩码长度小于32位或IPv6地址前缀长度小于128位。
主机路由：目的地为主机，IPv4地址子网掩码长度为32位或IPv6地址前缀长度为128位。
根据目的地与该路由器是否直接相连，路由又可划分为：
直连路由：目的地所在网络与路由器直接相连。
间接路由：目的地所在网络与路由器非直接相连。
根据目的地址类型的不同，路由还可以分为：
单播路由：表示将报文转发的目的地址是一个单播地址。
组播路由：表示将报文转发的目的地址是一个组播地址。
路由的优先级 对于相同的目的地，不同的路由协议（包括静态路由）可能会发现不同的路由，但这些路由并不都是最优的。事实上，在某一时刻，到某一目的地的当前路由仅能由唯一的路由协议来决定。为了判断最优路由，各路由协议（包括静态路由）都被赋予了一个优先级，当存在多个路由信息源时，具有较高优先级（取值较小）的路由协议发现的路由将成为最优路由，并将最优路由放入本地路由表中。
路由协议 优先级 DIRECT 0 OSPF 10 IS-IS IS-IS Level1 15
IS-IS Level 2 由网关加入的路由 50 路由器发现的路由 55 静态路由 60 UNR（User Network Route） DHCP（Dynamic Host Configuration Protocol）：60AAA-Download：60IP Pool：61Frame：62Host：63NAT（Network Address Translation）：64IPSec（IP Security）：65NHRP（Next Hop Resolution Protocol）：65PPPoE（Point-to-Point Protocol over Ethernet）：65 Berkeley RIP 100 点对点接口聚集的路由 110 OSPF的扩展路由 140 OSPF ASE 150 OSPF NSSA 150 BGP 170 EGP 200 IBGP 255 EBGP 255 其中，0表示直接连接的路由，255表示任何来自不可信源端的路由；数值越小表明优先级越高。 除直连路由（DIRECT）外，各种路由协议的优先级都可由用户手工进行配置。另外，每条静态路由的优先级都可以不相同。 路由器根据路由转发数据包，路由可通过手动配置和使用动态路由算法计算产生，其中手动配置的路由就是静态路由。</description>
    </item>
    <item>
      <title>深入理解Kubernetes Pod网络原理 - Linux虚拟网络技术</title>
      <link>https://www.oomkill.com/virtual-networking/</link>
      <pubDate>Mon, 18 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/virtual-networking/</guid>
      <description>本文是关于深入理解Kubernetes网络原理系列第2章 深入理解Kubernetes Pod网络原理 - 网络名称空间 深入理解Kubernetes Pod网络原理 - Linux虚拟网络技术 深入理解Kubernetes Pod网络原理 - CNI 深入理解Kubernetes Pod网络原理 - 跟随 flannel 学习CNI原理 深入理解Kubernetes Pod网络原理 - 跟随 flannel + multus 剖析 Chained Plugins 深入理解Kubernetes Pod网络原理 - 从零实现一个 CNI Plugin part 1 (Shell) 深入理解Kubernetes Pod网络原理 - 从零实现一个 CNI Plugin part 2 (libcni) 深入理解Kubernetes Pod网络原理 - Kubernetes网络模型 1 深入理解Kubernetes Pod网络原理 - Kubernetes网络模型 2 深入理解Kubernetes Pod网络原理 - Pod网络排错思路 Overview 本文将介绍Kubernetes中使用的相关虚拟网络功能，目的是为了任何无相关网络背景经历的人都可以了解这些技术在kubernetes中式如何应用的。
VLAN VLAN (Virtual local area networks)是逻辑上的LAN而不受限于同一物理网络交换机上。同样的VLAN也可以将同一台交换机/网桥下的设备/划分为不同的子网。</description>
    </item>
    <item>
      <title>使用eNSP构建calico BGP网络</title>
      <link>https://www.oomkill.com/ensp-calico-bgp/</link>
      <pubDate>Mon, 18 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ensp-calico-bgp/</guid>
      <description>实验文件： [calico BGP.zip](https://cdn.jsdelivr.net/gh/cylonchau/blogs@img/img/calico BGP.zip)
R1
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 system-view sysname R1 interface l0 ip address 1.1.1.1 32 interface g0/0/0 ip address 10.1.0.1 24 interface g0/0/1 ip address 10.3.0.1 24 bgp 100 router-id 1.1.1.1 peer 10.1.0.2 as-number 123 peer 10.3.0.2 as-number 456 dis this dis ip interface b R2
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 system-view sysname R2 interface l0 ip address 2.</description>
    </item>
    <item>
      <title>网络隧道技术</title>
      <link>https://www.oomkill.com/network-tunnel-technology/</link>
      <pubDate>Mon, 18 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/network-tunnel-technology/</guid>
      <description>隧道技术概要 隧道技术（Tunneling）是网络基础设置在网络之间传递数据的方式，使用隧道技术传递可以是不同协议的数据包，隧道协议将这些其他协议的数据包重新封装在新的包头中发送。被封装的数据包在隧道的两个端点之间通过网络进行路由，被封装数据包在网络上传递时所经历的逻辑路径称为隧道。
简单来说，隧道技术是一类网络协议，是将一个数据包封装在另一个数据包中进行传输的技术；**使用隧道的原因是在不兼容的网络上传输数据，或在不安全网络上提供一个安全路径。**通过网络隧道技术，可以使隧道两端的网络组成一个更大的内部网络。（把不支持的协议数据包打包成支持的协议数据包之后进行传输）。
隧道协议 要创建隧道，隧道的客户机和服务器双方必须使用相同的隧道技术，隧道协议有二层隧道协议与三层隧道协议两类。
二层隧道协议对应OSI模型中数据链路层，使用 帧 作为数据交换单位，PPTP、L2TP、L2F都属于二层隧道协议。是将数据封装在点对点协议的帧中通过互联网络发送。
三层隧道协议对应OSI模型中网络层，使用 包 作为数据交换单位，GRE、IPSec 都属于三层隧道协议。都是数据包封装在附加的IP包头中通过IP网络传送。
在例如VxLAN，工作在传输层和网络层之间。具体来说，将运行在用户数据报协议 (UDP) 和网络数据报协议 (IP) 之间，以便在网络中建立安全的通信通道。
网络隧道技术应用 隧道在Linux 中应用 IP隧道是指一种可在两网络间进行通信的通道。在该通道里，会先封装其他网络协议的数据包，之后再传输信息。
Linux原生共支持5种IPIP隧道：
ipip: 普通的IPIP隧道，就是在报文的基础上再封装成一个IPv4报文 gre: 通用路由封装（Generic Routing Encapsulation），定义了在任意一种网络层协议上封装其他任意一种网络层协议的机制，所以对于IPv4和IPv6都适用 sit: sit模式主要用于IPv4报文封装IPv6报文，即IPv6 over IPv4 isatap: 站内自动隧道寻址协议（Intra-Site Automatic Tunnel Addressing Protocol），类似于sit也是用于IPv6的隧道封装 vti: 即虚拟隧道接口（Virtual Tunnel Interface），是一种IPsec隧道技术 像IPVS/LVS中的 Virtual Server via IP Tunneling，就是使用了IPIP隧道
SSH隧道技术 SSH提供了一个重要功能，称为转发 forwarding 或者称为隧道传输tunneling，它可以通过加密频道将明文流量导入隧道中，在创建SSH隧道时， SSH客户端要设置并转交一个特定本地端口号到远程机器上；一旦SSH隧道创建，用户可以连到指定的本地端口号以访问网络服务。本地端口号不用与远地端口号一样。
SSH隧道主要使用场景一般为 规避防火墙、加密网络流量
规避防火墙，SSH隧道可以使一个被防火墙阻挡的协议可被包在另一个没被防火墙阻挡的协议里，这技巧可用来逃避防火墙政策。而这种操作符合“数据包封装在另一个数据包中进行传输的技术”，故称为SSH隧道技术。
SSH隧道类型 在ssh连接的基础上，指定 ssh client 或 ssh server 的某个端口作为源地址，所有发至该端口的数据包都会透过ssh连接被转发出去；至于转发的目标地址，目标地址既可以指定，也可以不指定，如果指定了目标地址，称为定向转发，如果不指定目标地址则称为动态转发：
定向转发
定向转发把数据包转发到指定的目标地址。目标地址不限定是ssh client 或 ssh server，既可以是二者之一，也可以是二者以外的其他机器。</description>
    </item>
    <item>
      <title>长期总结 - Linux网络命令合集</title>
      <link>https://www.oomkill.com/linux-network-command/</link>
      <pubDate>Mon, 18 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/linux-network-command/</guid>
      <description>工具命令集合 长期总结 - Linux日志查询命令 长期总结 - Linux网络命令合集 长期总结 - Linux性能分析命令 awk常用案例 bash shell常用示例 探索kubectl - 巧用jsonpath提取有用数据 探索kubectl - kubectl诊断命令集合 理解ldap - OpenLDAP客户端命令行使用 Overview 作为系统管理员或程序员，经常需要诊断分析和解决网络问题，而配置、监控与保护网络有助于发现问题并在事情范围扩大前得意解决，并且网络的性能与安全也是管理与诊断网络的重要部分。本文将总结常用与Linux网络管理的命令与使用示例，保持长期更新与更正。
IP iproute2 包含网络、路由、ARP缓存等的管理与配置的ip命令，用来取代传统的 ifconfig 与 route；ip 使用第二个参数，指定在对象执行的操作（例如，add delete show）。
ip 命令是配置网络接口的强大工具，任何 Linux 系统管理员都应该知道。它用于启动或关闭接口、分配和删除地址和路由、管理 ARP 缓存等等。
ip 常用的子命令有：
link (l) 网络接口管理 address (a) IP地址管理 route (r) 路由表管理 neigh (n) arp表管理 各系统下的包名与安装
Ubuntu/Debian: iproute2 ；apt install iproute2 CentOS/Fedora: iproute2 ；yum install -y iproute2 Apline：iproute2 ；apk add iproute2 ip link ip link 用于管理和显示网络接口</description>
    </item>
    <item>
      <title>istio sidecar流量处理机制及配置</title>
      <link>https://www.oomkill.com/istio-sidecar-mechnisim/</link>
      <pubDate>Sat, 09 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/istio-sidecar-mechnisim/</guid>
      <description>sidecar 介绍 在istio的流量管理等功能，都需要通过下发的配置应用到应用运行环境执行后生效，负责执行配置规则的组件在service mesh中承载应用代理的实体被称为side-car
Istio对流量策略管理等功能无须对应用程序做变动，
这种对应用服务完全非侵入的方式完全依赖于Side-car，应用的流量有Sidecar拦截并进行认证、鉴权、策略执行等治理功能。在Kubernetes平台中，Side-car容器于应用容器在同一个Pod中并共享网络名词控件，因此Side-car容易可以通过iptables规则拦截进出流量进行管理。
sidecar的注入 sidecar是service mesh无侵入式架构的应用模式，在使用sidecar部署服务网格时，无需再每个应用节点运行服务代理，但是需要在每个应用程序中部署一个sidecar容器，来接管所有进出流量。
Sidecar会将额外容器注入到 Pod 模板中。Istio中的数据平面组件所需的容器有：
istio-init 用于设置容器的iptables规则，目的是为了接管进出流量。在应用容器前启动并运行完成其生命周期，多个init容器按顺序依次完成。 istio-proxy 基于envoy的sidecar的代理。 sidecar被注入的方式 手动注入，使用 istioctl 修改容器模板并添加前面提到的两个容器的配置。不论是手动注入还是自动注入，Istio 都从 istio-sidecar-injector 和的 istio 两个 Configmap 对象中获取配置。 refer-istio-sidecar-injector
自动注入，在部署应用是，istio自动将sidecar注入到pod。这是istio推荐的方法，Istio在基于Kubernetes平台之上，需要在部署应用之前，对要标记部署应用程序的名称空间标记 kubectl label namespace default istio-injection=enabled 这个操作是对名称空间级别生效的。而后所部署的Pod中会注入sidecar执行上面sidecar容器的操作。
istio injector 注入原理 Sidecar Injector是Istio中实现自动注入Sidecar的组件，它是以Kubernetes准入控制器 AdmissionController 的形式运行的。Admission Controller 的基本工作原理是拦截Kube-apiserver的请求，在对象持久化之前、认证鉴权之后进行拦截。
Admission Controller有两种：一种是内置的，另一种是用户自定义的。
Kubernetes允许用户以Webhook的方式自定义准入控制器，Sidecar Injector就是这样一种特殊的MutatingAdmissionWebhook。
Sidecar Injector只在创建Pod时进行Sidecar容器注入，在Pod的创建请求到达 Kube-apiserver 后，首先进行认证鉴权，然后在准入控制阶段，Kube-apiserver以REST的方式同步调用Sidecar Injector Webhook服务进行init与istio-proxy容器的注入，最后将Pod对象持久化存储到etcd中。
sidecar容器 sidecar容器内部运行着 pilot-agent 与 envoy
Pilot-agent：基于kubernetesAPI资源对象为envoy初始化可用的bootstrap配置进行启动，在运行后管理envoy运行状态，如配置变更，出错重启等。
envoy：数据平面的执行层，由 pilot-agent 所启动的，从xDS API动态获取配置信息。Envoy并通过流量拦截机制处理入栈及出栈的流量。
envoy的listener 在运行在Kubernetes平台之上的istio，Envoy是通过Pilot将Kubernetes CRD资源 DestnationRule VirtualService Gateway等资源提供的配置，生成对应的Envoy配置。</description>
    </item>
    <item>
      <title>istio部署问题Q&amp;A</title>
      <link>https://www.oomkill.com/istio-deployment-qa/</link>
      <pubDate>Sun, 03 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/istio-deployment-qa/</guid>
      <description>端口绑定无权限 创建Gateway，提示绑定端口无权限。
text 1 2 3 2020-12-27T12:25:30.974288Z	warning	envoy config	gRPC config for type.googleapis.com/envoy.config.listener.v3.Listener rejected: Error adding/updating listener(s) 0.0.0.0_90: cannot bind &amp;#39;0.0.0.0:90&amp;#39;: Permission denied 问题原因：容器内默认权限不能使用非特权端口（&amp;lt;1024
导出部署清单部署失败 bash 1 istioctl manifest generate &amp;gt; generated-manifest.yaml 如果尝试使用来安装和管理Istio istioctl manifest generate，请注意以下警告：
Istio名称空间（istio-system默认情况下）必须手动创建。 istioctl install 会从Kubernetes上下文中自动检测特定于环境的设置。如需手动安装需要执行如下步骤： --set values.global.jwtPolicy=third-party-jwt --set values.global.jwtPolicy=first-party-jwt refer
token
Generate a manifest</description>
    </item>
    <item>
      <title>动态路由 - OSPF</title>
      <link>https://www.oomkill.com/dynamic-routing-ospf/</link>
      <pubDate>Sat, 02 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/dynamic-routing-ospf/</guid>
      <description>Open Shortest Path First OSPF，开放的最短路径优先协议，是IETF组织开发的一个基于链路状态的内部网关协议，它的使用不受任何厂商限制，所有人都可以使用，所以称为开放的，而最短路径优先（SPF）只是OSPF的核心思想，其使用的算法是Dijkstra算法，最短路径优先并没有太多特殊的含义，并没有任何一个路由协议是最长路径优先的，所有协议，都会选最短的。
OSPF针对IPv4协议使用的是OSPF Version 2（RFC2328）；针对IPv6协议使用OSPF Version 3（RFC2740）
目的：
在OSPF出现前，网络上广泛使用RIP（Routing Information Protocol）作为内部网关协议。
由于RIP是基于距离矢量算法的路由协议，存在着收敛慢、路由环路、可扩展性差等问题，所以逐渐被OSPF取代。
OSPF作为基于链路状态的协议，能够解决RIP所面临的诸多问题。此外，OSPF还有以下优点：
OSPF采用组播形式收发报文，这样可以减少对其它不运行OSPF路由器的影响。 OSPF支持无类型域间选路（CIDR）。 OSPF支持对等价路由进行负载分担。 OSPF支持报文加密。 由于OSPF具有以上优势，使得OSPF作为优秀的内部网关协议被快速接收并广泛使用。
OSPF协议特点：
OSPF把自治系统AS（Autonomous System）划分成逻辑意义上的一个或多个区域； OSPF通过LSA（Link State Advertisement）的形式发布路由； OSPF依靠在OSPF区域内各设备间交互OSPF报文来达到路由信息的统一； OSPF报文封装在IP报文内，可以采用单播或组播的形式发送。 OSPF工作流程 寻找邻居
OSPF协议运行后，先寻找网络中可与自己交互链路状态信息的周边路由器，可以交互链路状态信息的路由器互为邻居
建立邻居关系
邻接关系可以想象为一条点到点的虚链路，他是在一些邻居路由器之间构成的。只有建立了可靠邻接关系的路由器才相互传递链路状态信息。
链路状态信息传递
OSPF路由器将建立描述网络链路状态的LSA Link State Advertisement，链路状态公告，建立邻接关系的OSPF路由器之间将交互LSA，最终形成包含网络完整链路状态的配置信息。
计算路由
获得了完整的LSBD后，OSPF区域内的每个路由器将会对该区域的网络结构有相同的认识，随后各路由器将依据LSDB的信息用SPF算法独立计算出路由。
Router ID OSPF Router-ID用于在OSPF domain中唯一地表示一台OSPF路由器，从OSPF网络设计的角度，我们要求全OSPF域内，禁止出现两台路由器拥有相同的Router-ID。
OSPF Router-ID的设定可以通过手工配置的方式，或者通过协议自动选取的方式。当然，在实际网络部署中，强烈建议手工配置OSPF的Router-ID，因为这关系到协议的稳定。
实验：单区域OSPF配置 配置两台路由器
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 [Huawei]sysname R2 [R2]interface lo0 [R2-LoopBack0]ip add 2.</description>
    </item>
    <item>
      <title>深入理解Kubernetes Pod网络原理 - 网络名称空间</title>
      <link>https://www.oomkill.com/netspace/</link>
      <pubDate>Sat, 02 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/netspace/</guid>
      <description>本文是关于深入理解Kubernetes网络原理系列第1章 深入理解Kubernetes Pod网络原理 - 网络名称空间 深入理解Kubernetes Pod网络原理 - Linux虚拟网络技术 深入理解Kubernetes Pod网络原理 - CNI 深入理解Kubernetes Pod网络原理 - 跟随 flannel 学习CNI原理 深入理解Kubernetes Pod网络原理 - 跟随 flannel + multus 剖析 Chained Plugins 深入理解Kubernetes Pod网络原理 - 从零实现一个 CNI Plugin part 1 (Shell) 深入理解Kubernetes Pod网络原理 - 从零实现一个 CNI Plugin part 2 (libcni) 深入理解Kubernetes Pod网络原理 - Kubernetes网络模型 1 深入理解Kubernetes Pod网络原理 - Kubernetes网络模型 2 深入理解Kubernetes Pod网络原理 - Pod网络排错思路 Linux namespace namespace是Linux内核的一项功能，该功能对内核资源进行分区，以使一组进程看到一组资源，而另一组进程看到另一组资源。该功能通过为一组资源和进程具有相同的名称空间而起作用，但是这些名称空间引用了不同的资源。资源可能存在于多个空间中。
Linux namespaces 是对全局系统资源的一种封装隔离，使得处于不同 namespace 的进程拥有独立的全局系统资源，改变一个namespace中的系统资源只会影响当前 namespace 里的进程，对其他 namespace 中的进程没有影响。</description>
    </item>
    <item>
      <title>网络实验 - VLAN</title>
      <link>https://www.oomkill.com/experiment-vlan/</link>
      <pubDate>Sat, 02 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/experiment-vlan/</guid>
      <description>虚拟局域网VLAN（Virtual Local Area Network），是将一个物理的LAN在逻辑上划分成多个广播域的通信技术。
VLAN内的主机间可以直接通信，而VLAN间不能直接通信，从而将广播报文限制在一个VLAN内。
以太网是一种基于CSMA/CD（Carrier Sense Multiple Access/Collision Detection）的共享通讯介质的数据网络通讯技术。当主机数目较多时会导致冲突严重、广播泛滥、性能显著下降甚至造成网络不可用等问题。通过交换机实现LAN互连虽然可以解决冲突严重的问题，但仍然不能隔离广播报文和提升网络质量。
在这种情况下出现了VLAN技术，这种技术可以把一个LAN划分成多个逻辑的VLAN，每个VLAN是一个广播域，VLAN内的主机间通信就和在一个LAN内一样，而VLAN间则不能直接互通，这样，广播报文就被限制在一个VLAN内。
VLAN的作用 限制广播域：广播域被限制在一个VLAN内，节省了带宽，提高了网络处理能力。
增强局域网的安全性：不同VLAN内的报文在传输时是相互隔离的，即一个VLAN内的用户不能和其它VLAN内的用户直接通信。
提高了网络的健壮性：故障被限制在一个VLAN内，本VLAN内的故障不会影响其他VLAN的正常工作。
灵活构建虚拟工作组：用VLAN可以划分不同的用户到不同的工作组，同一工作组的用户也不必局限于某一固定的物理范围，网络构建和维护更方便灵活。
VLAN Tag 要使交换机能够分辨不同VLAN的报文，需要在报文中添加标识VLAN信息的字段。IEEE 802.1Q协议规定，在以太网数据帧的目的MAC地址和源MAC地址字段之后、协议类型字段之前加入4个字节的VLAN标签（又称VLAN Tag，简称Tag），用以标识VLAN信息。
VLAN Tag各字段含义：
字段 长度 含义 取值 TPID 2Byte Tag Protocol Identifier（标签协议标识符），表示数据帧类型。 表示帧类型，取值为0x8100时表示IEEE 802.1Q的VLAN数据帧。如果不支持802.1Q的设备收到这样的帧，会将其丢弃。各设备厂商可以自定义该字段的值。当邻居设备将TPID值配置为非0x8100时， 为了能够识别这样的报文，实现互通，必须在本设备上修改TPID值，确保和邻居设备的TPID值配置一致。 PRI 3bit Priority，表示数据帧的802.1p优先级。 取值范围为0～7，值越大优先级越高。当网络阻塞时，设备优先发送优先级高的数据帧。 CFI 1bit Canonical Format Indicator（标准格式指示位），表示MAC地址在不同的传输介质中是否以标准格式进行封装，用于兼容以太网和令牌环网。 CFI取值为0表示MAC地址以标准格式进行封装，为1表示以非标准格式封装。在以太网中，CFI的值为0。 VID 12bit VLAN ID，表示该数据帧所属VLAN的编号。 VLAN ID取值范围是0～4095。由于0和4095为协议保留取值，所以VLAN ID的有效取值范围是1～4094。 其中，数据帧中的VID（VLAN ID）字段标识了该数据帧所属的VLAN，数据帧只能在其所属VLAN内进行传输。
对于交换机来说，其内部处理的数据帧都带有VLAN标签，而现网中交换机连接的设备有些只会收发Untagged帧，要与这些设备交互，就需要接口能够识别Untagged帧并在收发时给帧添加、剥除VLAN标签。同时，现网中属于同一个VLAN的用户可能会被连接在不同的交换机上，且跨越交换机的VLAN可能不止一个，如果需要用户间的互通，就需要交换机间的接口能够同时识别和发送多个VLAN的数据帧。
VLAN PVID 缺省VLAN又称PVID（Port Default VLAN ID）。设备处理的数据帧都带Tag，当设备收到UNTagged帧时，就需要给该帧添加Tag，添加什么Tag，就由接口上的缺省VLAN决定。一个物理端口只能拥有一个PVID，当一个物理端口拥有了一个PVID的时候，必定会拥有和PVID相等的VID，而且在这个VID上，这个物理端口必定是Untagged Port。
因此，根据接口连接对象以及对收发数据帧处理的不同，华为定义了4种接口的链路类型：Access、Trunk、Hybrid和QinQ，以适应不同的连接和组网：
Access接口：一般用于和不能识别Tag的用户终端（如用户主机、服务器等）相连，或者不需要区分不同VLAN成员时使用。Access接口大部分情况只能收发Untagged帧，且只能为Untagged帧添加唯一的VLAN Tag。 Trunk接口：一般用于连接交换机、路由器、AP以及可同时收发Tagged帧和Untagged帧的语音终端。它可以允许多个VLAN的帧带Tag通过，但只允许一个VLAN的帧从该类接口上发出时不带Tag（即剥除Tag）。 Hybrid接口：既可以用于连接不能识别Tag的用户终端（如用户主机、服务器等）和网络设备（如Hub、傻瓜交换机），也可以用于连接交换机、路由器以及可同时收发Tagged帧和Untagged帧的语音终端、AP。它可以允许多个VLAN的帧带Tag通过，且允许从该类接口发出的帧根据需要配置某些VLAN的帧带Tag（即不剥除Tag）、某些VLAN的帧不带Tag（即剥除Tag）。 使用QinQ（802.1Q-in-802.1Q）协议，一般用于私网与公网之间的连接，也被称为Dot1q-tunnel接口。它可以给帧加上双层Tag，即在原来Tag的基础上，给帧加上一个新的Tag，从而可以支持多达4094×4094个VLAN。 接口类型 对接收不带Tag的报文处理 对接收带Tag的报文处理 发送帧处理过程 Access接口 接收该报文，并打上缺省的VLAN ID。 当VLAN ID与缺省VLAN ID相同时，接收该报文。当VLAN ID与缺省VLAN ID不同时，丢弃该报文 先剥离帧的PVID Tag，然后再发送。 Trunk接口 打上缺省的VLAN ID，当缺省VLAN ID在允许通过的VLAN ID列表里时，接收该报文。打上缺省的VLAN ID，当缺省VLAN ID不在允许通过的VLAN ID列表里时，丢弃该报文。 当VLAN ID在接口允许通过的VLAN ID列表里时，接收该报文。当VLAN ID不在接口允许通过的VLAN ID列表里时，丢弃该报文 当VLAN ID与缺省VLAN ID相同，且是该接口允许通过的VLAN ID时，去掉Tag，发送该报文。当VLAN ID与缺省VLAN ID不同，且是该接口允许通过的VLAN ID时，保持原有Tag，发送该报文。 Hybrid接口 打上缺省的VLAN ID，当缺省VLAN ID在允许通过的VLAN ID列表里时，接收该报文。打上缺省的VLAN ID，当缺省VLAN ID不在允许通过的VLAN ID列表里时，丢弃该报文。 当VLAN ID在接口允许通过的VLAN ID列表里时，接收该报文。当VLAN ID不在接口允许通过的VLAN ID列表里时，丢弃该报文。 当VLAN ID是该接口允许通过的VLAN ID时，发送该报文。可以通过命令设置发送时是否携带Tag。 由上面各类接口添加或剥除VLAN标签的处理过程可见：</description>
    </item>
    <item>
      <title>网络实验 - VxLAN</title>
      <link>https://www.oomkill.com/experiment-vxlan/</link>
      <pubDate>Sat, 02 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/experiment-vxlan/</guid>
      <description>vXlan概念 实验 什么是VxLAN RFC定义了虚拟扩展局域网 VXLAN （Virtual eXtensible Local Area Network，）扩展方案，是对传统VLAN协议的一种扩展。VXLAN采用 （MACin UDP（User Datagram Protocol）封装方式，是NVO3（Network Virtualization over Layer 3）中的一种网络虚拟化技术。VXLAN的特点是将L2的以太帧封装到UDP报文（即L2 over L4）中，并在L3网络中传输。
VXLAN本质上是一种隧道技术，在源网络设备与目的网络设备之间的IP网络上，建立一条逻辑隧道，将用户报文经过特定的封装后通过这条隧道转发。从用户的角度来看，接入网络的服务器就像是连接到了一个虚拟的二层交换机的不同端口上（可把蓝色虚框表示的数据中心VXLAN网络看成一个二层虚拟交换机），可以方便地通信。
为什么需要VxLAN 虚拟机规模受网络设备表项规格的限制
在传统二层网络环境下，数据报文是通过查询MAC地址表进行二层转发。服务器虚拟化后，VM的数量比原有的物理机发生了数量级的增长，伴随而来的便是VM网卡MAC地址数量的空前增加。而接入侧二层设备的MAC地址表规格较小，无法满足快速增长的VM数量。
网络隔离能力有限
VLAN作为当前主流的网络隔离技术，在标准定义中只有12比特，因此可用的VLAN数量仅4096个。对于公有云或其它大型虚拟化云计算服务这种动辄上万甚至更多租户的场景而言，VLAN的隔离能力无法满足。
虚拟机迁移范围受限
由于服务器资源等问题（如CPU过高，内存不够等），虚拟机迁移已经成为了一个常态性业务。
什么是虚拟机动态迁移？
所谓虚拟机动态迁移，是指在保证虚拟机上服务正常运行的同时，将一个虚拟机系统从一个物理服务器移动到另一个物理服务器的过程。该过程对于最终用户来说是无感知的，从而使得管理员能够在不影响用户正常使用的情况下，灵活调配服务器资源，或者对物理服务器进行维修和升级。
在服务器虚拟化后，虚拟机动态迁移变得常态化，为了保证迁移时业务不中断，就要求在虚拟机迁移时，不仅虚拟机的IP地址、MAC地址等参数保持不变，而且虚拟机的运行状态也必须保持原状（例如TCP会话状态），所以虚拟机的动态迁移只能在同一个二层域中进行，而不能跨二层域迁移。
VxLAN方案 为了应对传统数据中心网络对服务器虚拟化技术的限制，VXLAN技术应运而生，其能够很好的解决上述问题。
针对虚拟机规模受设备表项规格限制
VXLAN将管理员规划的同一区域内的VM发出的原始报文封装成新的UDP报文，并使用物理网络的IP和MAC地址作为外层头，这样报文对网络中的其他设备只表现为封装后的参数。因此，极大降低了大二层网络对MAC地址规格的需求。
针对网络隔离能力限制
在传统的VLAN网络中，标准定义所支持的可用VLAN数量只有4000个左右。VXLAN引入了类似VLAN ID的用户标识，称为VXLAN网络标识VNI（VXLAN Network Identifier），由24比特组成，支持多达16M的VXLAN段，有效得解决了云计算中海量租户隔离的问题。
针对虚拟机迁移范围受限
VXLAN将VM发出的原始报文进行封装后通过VXLAN隧道进行传输，隧道两端的VM不需感知传输网络的物理架构。这样，对于具有同一网段IP地址的VM而言，即使其物理位置不在同一个二层网络中，但从逻辑上看，相当于处于同一个二层域。即VXLAN技术在三层网络之上，构建出了一个虚拟的大二层网络，只要虚拟机路由可达，就可以将其规划到同一个大二层网络中。这就解决了虚拟机迁移范围受限问题。
VxLAN与VLAN之间的区别 VLAN是传统的网络隔离技术，在标准定义中VLAN的数量只有4096，无法满足大型数据中心的租户间隔离需求。另外，VLAN的二层范围一般较小且固定，无法支持虚拟机大范围的动态迁移。
VXLAN完美地弥补了VLAN的上述不足，一方面通过VXLAN中的24比特VNI字段，提供多达16M租户的标识能力，远大于VLAN的4096；另一方面，VXLAN本质上在两台交换机之间构建了一条穿越数据中心基础IP网络的虚拟隧道，将数据中心网络虚拟成一个巨型“二层交换机”，满足虚拟机大范围动态迁移的需求。
VXLAN Header
增加VXLAN头（8字节），其中包含24比特的VNI字段，用来定义VXLAN网络中不同的租户。此外，还包含VXLAN Flags（8比特，取值为00001000）和两个保留字段（分别为24比特和8比特）。
UDP Header
VXLAN头和原始以太帧一起作为UDP的数据。UDP头中，目的端口号（VXLAN Port）固定为4789，源端口号（UDP Src. Port）是原始以太帧通过哈希算法计算后的值。
Outer IP Header
封装外层IP头。其中，源IP地址（Outer Src. IP）为源VM所属VTEP的IP地址，目的IP地址（Outer Dst. IP）为目的VM所属VTEP的IP地址。
Outer MAC Header
封装外层以太头。其中，源MAC地址（Src. MAC Addr.）为源VM所属VTEP的MAC地址，目的MAC地址（Dst. MAC Addr.</description>
    </item>
    <item>
      <title>istio流量管理：非侵入式流量治理</title>
      <link>https://www.oomkill.com/istio-introduction/</link>
      <pubDate>Wed, 30 Dec 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/istio-introduction/</guid>
      <description>在服务治理中，流量管理是一个广泛的话题，一般情况下，常用的包括：
动态修改服务访问的负载均衡策略，比如根据某个请求特征做会话保持； 同一个服务有多版本管理，将一部分流量切到某个版本上； 对服务进行保护，例如限制并发连接数、限制请求数、隔离故障服务实例等； 动态修改服务中的内容，或者模拟一个服务运行故障等。 在Istio中实现这些服务治理功能时无须修改任何应用的代码。较之微服务的SDK方式，Istio以一种更轻便、透明的方式向用户提供了这些功能。用户可以用自己喜欢的任意语言和框架进行开发，专注于自己的业务，完全不用嵌入任何治理逻辑。只要应用运行在Istio的基础设施上，就可以使用这些治理能力。
总结Istio流量治理的目标：以基础设施的方式提供给用户非侵入的流量治理能力，用户只需关注自己的业务逻辑开发，无须关注服务访问管理。
istio流量治理的核心组件Pilot 在istio1.8中，istio的分为 envoy （数据平面） 、istiod （控制平面） 、addons（管理插件） 及 istioctl （命令行工具，用于安装、配置、诊断分析等操作）组成。
Pilot是Istio控制平面流量管理的核心组件，管理和配置部署在Istio服务网格中的所有Envoy代理实例。
pilot-discovery为envoy sidecar提供服务发现，用于路由及流量的管理。通过kubernetes CRD资源获取网格的配置信息将其转换为xDS接口的标准数据格式后，通过gRPC分发至相关的envoy sidecar
Pilot组件包含工作在控制平面中的 pilot-discovery 和工作与数据平面的pilot-agent 与Envoy(istio-proxy)
pilot-discovery主要完成如下功能：
从service registry中获取服务信息 从apiserver中获取配置信息。 将服务信息与配置信息适配为xDS接口的标准数据格式，通过xDS api完成配置分发。 pilot-agent 主要完成如下功能
基于kubernetes apiserver为envoy初始化可用的boostrap配置文件并启动envoy。
管理监控envoy的云兄状态及配置重载。
envoy
每个sidecar中的envoy是由pilot-agent基于生产的bootstrap配置进行启动，并根据指定的pilot地址，通过xDS api动态获取配置。 sidecar形式的envoy通过流量拦截机制为应用程序实现入站和出站的代理功能。 Pilot的实现 在istio中的管理策略都是基于Kubernetes CRD的实现，其中有关于流量管理的CRD资源包括 VirtualService EnvoyFilter Gateway ServiceEntry Sidecar DestinationRule WorkloadEntry WorkloadGroup。reference istio-networking-crd-resouces
VirtualServices：用于定义路由，可以理解为envoy的 listener =&amp;gt; filter =&amp;gt; route_config
DestinationRule：用于定义集群，可以理解为envoy 的 cluster
Gateway：用于定义作用于istio-ingress-gateway
ServiceEntry：用于定义出站的路由，作用于istio-egress-gateway
EnvoyFilter：为envoy添加过滤器或过滤器链。
Sidecar：用于定义运行在sidecar之上的envoy配置。
Virtual Services和 Destination Rules是Istio流量路由功能的核心组件</description>
    </item>
    <item>
      <title>goland在mod模式下不从vendor文件夹查找依赖</title>
      <link>https://www.oomkill.com/go-vendor-file-in-goland/</link>
      <pubDate>Sun, 13 Dec 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-vendor-file-in-goland/</guid>
      <description>goland使用vendor作为获取依赖源 软件版本：
system：windows10 1709 terminal： wsl ubuntu1804 goland：201903 goland 打开项目时使用mod模式，无法识别外部包的依赖
根据goland官方提示，开启时，将忽略go.mod依赖描述，所以就找不到相对应的依赖，但是编译时正常的。可以看到下图中，external libraries 并没有加载外部的库导致了无法识别。
此时想要正常使用的话，可以按照提示操作
将 goland 改为gopath模式，执行go mod vendor 将依赖同步到vendor 。此时正常。
当依赖更新时，可以手动添加对应的依赖库，go mod tidy 后 。因为vendor中没有新的依赖，需要手动执行下go mod vendor即可正常使用。
使用vendor编译 在编译时，可以使用 -mod=vendor 标记，使用代码主目录文件夹下vendor目录满足依赖获取，go build -mod=vendor。此时，go build 忽略go.mod 中的依赖，（这里仅使用代码root目录下的vendor其他地方的将忽略）
GOFLAGS=-mod=vendor 设置顶级vendor作为依赖 go env -w GOFLAGS=&amp;quot;-mod=vendor&amp;quot; 进行设置。 取消 go env -w GOFLAGS=&amp;quot;-mod=&amp;quot;</description>
    </item>
    <item>
      <title>海信A6/A6L A7Pro/CC A5PRO/A5PRO CC  安装gms google service指南</title>
      <link>https://www.oomkill.com/hisense-a6l-gms-install/</link>
      <pubDate>Mon, 16 Nov 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/hisense-a6l-gms-install/</guid>
      <description>用过海信双面屏或者eink手机的朋友都知道，海信手机就是死活安装不了谷歌全家桶，因为海信的领导说跟谷歌有协议不能安装谷歌框架（还说后期google审核坚决不给安装，人家其他ov mui都可以安装）。不信的朋友可以去海信论坛求证，杠精走开。
海信手机没有安装GSM Google Mobile Service 也没有 youtube，gmail，google map。在国外的朋友们用起来很难受，别说打游戏了，就日常出行也离不开google service，也是找了很久找到一个国外大神对海信A7 Pro下安装的教程，尝试在A6l也可以装，后面 Hisense A5PRO/CC Hisense A7/CC A6/A6L A2/A2Pro 其实都是通用的。
不过这个大神的教程并不是root来安装，对于在保的小伙伴们还是依然可以享受保修，系统升级（虽然海信基本百年不更新的），现在开始介绍下如何让海信eink系列获得GMS
安装步骤 下载 adb 关闭一堆系統內建的 垃圾 Apps 的功能(可以不关闭看自己了) 下载 Aurora Store (这步骤完全没用上，看个人了，国外大神推荐要下载) 先依照順序 安裝 4个基础服务 apk，安装完成后可以正常登陆google账号了 再 按照顺序 安裝 3个 其他服务 apk（可以不按照顺序，国外大神说的是需要按照顺序） 前置步驟：开启开发者模式 打开 开发者模式
步骤1：下载安装 adb 程序 Mac可以直接输入命令：brew install android-platform-tools 具体 brew 是啥自行百度
Windows 平台参考：
先从这里下载 adb，然后下一步，下一步就行，到安装完成。
安装好后启动 adb，这里只介绍几个命令，对于装个 GAPPS 已经足够了。
查看设备：adb devices 看到xxxxxx device即表示连接成功 查看手机IP: adb shell ifconfig wlan0 通过IP地址连接手机：adb connect &amp;lt;device-ip-address&amp;gt; 断开连接：adb disconnect &amp;lt;device-ip-address&amp;gt; 设备监听：adb tcpip 5555 这里差不多了，更多可以参考下这里，下面开始介绍如何连接手机</description>
    </item>
    <item>
      <title>如何将systemd服务的输出重定向到指定文件</title>
      <link>https://www.oomkill.com/systemd-output/</link>
      <pubDate>Fri, 13 Nov 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/systemd-output/</guid>
      <description>有一种更优雅的方法可以解决systemd输出到指定文件而非/var/log/message，需要使用systemd参数与rsyslog过滤器。并指示syslog过滤器按程序名称拆分其输出。
systemd所需参数为 SyslogIdentifier：required，设置日志标识符(发送日志消息时加在行首的字符串)(&amp;ldquo;syslog tag&amp;rdquo;)。 默认值是进程的名称。此选项仅在 StandardOutput= 或 StandardError= 的值包含 journal(+console), syslog(+console), kmsg(+console) 之一时才有意义， 并且仅适用于输出到标准输出或标准错误的日志消息。 StandardOutput：required，设置进程的标准输出(STDOUT)。 可设为 inherit, null, tty, journal, syslog, kmsg, journal+console, syslog+console, kmsg+console, file:path, append:path, socket, fd:name 之一。 StandardError：设置进程的标准错误(STDERR)。 取值范围及含义与 StandardOutput= 相同。但有如下例外： (1) inherit 表示使用 StandardOutput= 的值。 (2) fd:name 的默认文件描述符名称为 &amp;ldquo;stderr&amp;rdquo; rsyslog过滤器设置 使用rsyslog条件选择器。如果不改变rsyslog目前工作模式，按照如下操作：
新建/etc/rsyslog.d/xx.conf文件。
在新建文件内写入内容如下
单一条件处理。
text 1 2 3 if $programname == &amp;#39;programname&amp;#39; then /var/log/programname.log # 停止往其他文件内写入，如果不加此句，会继续往/var/log/message写入。 if $programname == &amp;#39;programname&amp;#39; then stop 多条件处理
会根据不同应用名称将不同的输出日志重定向到不同的文件内。
text 1 2 3 4 5 6 7 8 9 10 11 12 13 if ($programname == &amp;#39;apiserver&amp;#39;) then { action(type=&amp;#34;omfile&amp;#34; file=&amp;#34;/var/log/apiserver.</description>
    </item>
    <item>
      <title>awesome git command</title>
      <link>https://www.oomkill.com/awesome-git-command/</link>
      <pubDate>Sun, 08 Nov 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/awesome-git-command/</guid>
      <description>Tag command describe git tag 列出所有tag git tag -l v1.* 列出符合条件的tag（筛选作用） git tag [tag_name] 创建轻量tag（无-m标注信息） git push REMOTE TAG 推送一个tag到远端 git push origin &amp;ndash;tags* 推送所有本地tag到远程 git push origin :refs/tags/[REMOTE TAG]
git push &amp;ndash;delete REMOTE TAG 删除远程指定tag git fetch origin [remote_tag_name] 拉取远程指定tag git show [tag_name] 显示指定tag详细信息 git push origin [local_tag_name] 推送指定本地tag到远程 git tag NEW_TAG OLD_TAG
git tag -d OLD_TAG 重命名本地tag git tag -d [local_tag_name] 删除本地指定tag git ls-remote &amp;ndash;tags origin 查询远程tags git tag -a [tag_name] 创建含注解的tag git fetch origin [remote_tag_name]git checkout [remote_tag_name] git branch checkout远端tag到本地 Checking 检查工作目录与暂存区的状态</description>
    </item>
    <item>
      <title>适用于windows10 Linux子系统的安装管理配置</title>
      <link>https://www.oomkill.com/linux-subsystem-in-win10/</link>
      <pubDate>Sun, 08 Nov 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/linux-subsystem-in-win10/</guid>
      <description>什么是WSL Windows Subsystem for Linux 简称WSL，适用于Linux的Windows子系统，可以直接在Windows上运行Linux环境（包括大部分命令行工具）
Linux containers与Windows Subsystem for Linux（WSL）区别 此处以docker与wsl进行一些比较，主要为个人的理解之处。
docker与wsl同样运行在本机环境中运行，不依赖其他管理程序与虚拟化。 docker与wsl同样为应用容器。
安装WSL 在Windows10上，用于Linux的Windows子系，可运行受支持的Linux版本（例如Ubuntu，OpenSuse，Debian等），而无需设置操作系统的复杂性。虚拟机或其他计算机。
使用设置为Linux启用Windows子系统 打开设置 点击“应用”。 在“相关设置”部分下，单击“程序和功能”选项 单击左窗格中的“打开或关闭Windows功能”选项。 检查Windows Subsystem for Linux选项。 完成这些步骤后，将配置该环境以下载并运行Windows 10上的Linux版本。
使用Microsoft Store安装Linux发行版 要在Windows 10上安装Linux发行版，请使用以下步骤：
打开Microsoft Store。搜索要安装的Linux发行版。一些可用的发行版包括：
Ubuntu OpenSuse Kali Linux Debian Alpine WSL Suse Linux Enterprise 选择要在您的设备上安装的Linux发行版。 单击获取（或安装）按钮。 Microsoft Store安装Linux发行版 单击启动按钮。为Linux发行版创建一个用户名，然后按Enter键。 指定发行版的密码，然后按Enter。 重复密码，然后按Enter确认。 完成以上步骤后，即完成安装了WSL（没有图形界面），在开始菜单 运行 wsl 启动。
离线安装WSL 官网指导手册内包含所支持的Linux离线安装包
这里下载的为Ubuntu 18.04，下载后，文件格式为appx格式，本次使用的操作系统为，windows1709企业版，并且卸载了所有的 UWP应用。因此只能使用命令行进行安装。
非LTSC企业版或卸载windows store的可以直接双击安装
管理员打开Powershell 运行以下命令，将路径替换为下载的离线安装包路径。本次安装的 wsl 默认安装到C盘
powershell 1 Add-AppxPackage .\app_name.appx 查看已经安装的子系统</description>
    </item>
    <item>
      <title>常用加密算法学习总结之散列函数(hash function)</title>
      <link>https://www.oomkill.com/hash-function/</link>
      <pubDate>Wed, 04 Nov 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/hash-function/</guid>
      <description>散列函数（Hash function）又称散列算法、哈希函数，散列函数把消息或数据压缩成摘要，使得数据量变小，将数据的格式固定下来。该函数将数据打乱混合，重新创建一个叫做散列值（hash values）的指纹。这种转化是一种压缩映射，也就是散列值的空间通常远小于输入值的空间，不同的输入可能会散列成相同的输出，二不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要函数。
散列函数性质 通过使用单向散列函数，即便是确认几百MB大小的文件的完整性，也只要对比很短的散列值就可以了。那么，单向散列函数必须具备怎样的性质呢？我们来整理一下。
根据任意长度的消息计算出固定长度的散列值
能够快速计算出散列值
计算散列值所花费的时间短。尽管消息越长，计算散列值的时间也会越长，但如果不能在现实的时间内完成计算就没有意义了。
消息不同散列值也不同
难以发现碰撞的性质称为抗碰撞性（collisionresistance）。密码技术中所使用的单向散列函数，都需要具备抗碰撞性。强抗碰撞性，是指要找到散列值相同的两条不同的消息是非常困难的这一性质。在这里，散列值可以是任意值。密码技术中的单向散列函数必须具备强抗碰撞性。
具备单向性
单向散列函数必须具备单向性（one-way）。单向性指的是无法通过散列值反算出消息的性质。根据消息计算散列值可以很容易，但这条单行路是无法反过来走的。
散列函数的应用 散列函数应用具有多样性
安全加密：
保护资料，散列值可用于唯一地识别机密信息。这需要散列函数是抗碰撞(collision-resistant)的，意味着很难找到产生相同散列值的资料。如数字签名、消息认证码。 数据校验：
确保传递真实的信息：消息或数据的接受者确认消息是否被篡改的性质叫数据的真实性，也称为完整性。 错误校正：使用一个散列函数可以很直观的检测出数据在传输时发生的错误。 负载均衡：
通过hash算法，对客户端IP进行计算hash值，将取到值与服务器数量进行取模运算。 分布式存储：如一致性hash。
常用单项散列函数 MD4 MD5 MD5在1996年后被证实存在弱点，可以被加以破解，对于需要高度安全性的资料，专家一般建议改用其他算法，如SHA-2。2004年，证实MD5算法无法防止碰撞攻击，因此不适用于安全性认证，如SSL公开密钥认证或是数字签名等用途。
SHA-1 SHA-2 SHA-1：1995年发布，SHA-1在许多安全协议中广为使用，包括TLS、GnuPG、SSH、S/MIME和IPsec，是MD5的后继者。但SHA-1的安全性在2010年以后已经不被大多数的加密场景所接受。2017年荷兰密码学研究小组CWI和Google正式宣布攻破了SHA-1。
SHA-2：2001年发布，包括SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。SHA-2目前没有出现明显的弱点。虽然至今尚未出现对SHA-2有效的攻击，但它的算法跟SHA-1基本上仍然相似。 比特币使用的sha-256进行的数字签名
算法和变体 输出散列值长度 （bits） 中继散列值长度 （bits） 资料区块长度 （bits） 最大输入消息长度 （bits） MD5 128 128 (4 × 32) 512 无限 SHA-0 160 160 (5 × 32) 512 264 − 1 SHA-1 160 160 (5 × 32) 512 264 − 1 SHA-2 SHA-224 SHA-256 224 256 256 (8 × 32) 512 SHA-384 SHA-512 SHA-512/224 SHA-512/256 384 512 224 256 512 (8 × 64) 1024 2128 − 1 Go语言中使用散列函数 Go语言使用MD5 方式一：</description>
    </item>
    <item>
      <title>常用加密算法学习总结之数字签名</title>
      <link>https://www.oomkill.com/digital-signature/</link>
      <pubDate>Tue, 03 Nov 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/digital-signature/</guid>
      <description>数字签名（Digital Signature），通俗来讲是基于非对称加密算法，用秘钥对内容进行散列值签名，在对内容与签名一起发送。
更详细的解说 更详细的解说 - 中文
数字签名的生成个验证 签名
⑴ 对数据进行散列值运算。 ⑵ 签名：使用签名者的私钥对数据的散列值进行加密。 ⑶ 数字签名数据：签名与原始数据。
图：数字签名 Source：https://cheapsslsecurity.com/blog/digital-signature-vs-digital-certificate-the-difference-explained/ 验证 ⑴ 接收数据：原始数据&amp;amp;数字签名。 ⑵ 使用公钥进行解密得到散列值。 ⑶ 将原始数据的散列值与解密后的散列值进行对比。
Go语言中使用RSA进行数字签名 ⑴ pem解码：使用pem对私钥进行解码, 得到pem.Block结构体 ⑵ 获得私钥：使用GO x509接口pem.Block据解析成私钥结构体 ⑶ 计算hash值：对明文进行散列值计算 ⑷ 使用秘钥对散列值签名
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 package main import ( &amp;#34;crypto&amp;#34; &amp;#34;crypto/rand&amp;#34; &amp;#34;crypto/rsa&amp;#34; &amp;#34;crypto/sha256&amp;#34; &amp;#34;crypto/x509&amp;#34; &amp;#34;encoding/pem&amp;#34; &amp;#34;fmt&amp;#34; ) var ( private = `-----BEGIN 私钥----- MIICXQIBAAKBgQDc73afIxqYOHg80puDIMYrqUAiTi8EiTVDEiO9YE3+VxRvN0sa pe3zx1UdhgIn3iCPUzyI2vwNADId3LjuIjkdCcdB2fHrBTbcy6u0545HnY42F9aQ 7cAr168bHcqhQoKcna9i9nukO+w7So1J9C6Wr8J4e4923q7+T7z7bZeXywIDAQAB AoGBAItX5KLdywoyo3MJCdgcNaCX8MEyOmlL+HHC4ROxx78gQN0cLJw0Bu33zHEA ch+e8z4yKz3Nj6bLdtBqw6A9qXLBCfWfD/p9YKDZNFP/6+u9teUirOgiBSq7kXWy mtBm0I3pz33EomCuSJzLj/Mj/fkKs+425jPFcZboJdZpCyBhAkEA8mtGUGYuAZwV RKBDkf1bz5EyPBGV+9CyXa6pd6md61APY0j+qhb1w9ADfHKkAzfoilhpucznRhaz kAheqMPAMwJBAOlQEx2Ytc8TxfFqhF8RPTODe2N0jBBvsvJ85k7vNiQ+hnmaAray XS6pCbZdvmGHYKlz3MVGeis/UJKDdSzE0gkCQQCoZijkNPcEmz6S+5m00oFywXRa EgVUdndRaMHEpIlVK7pkyBJQab60Fc42JxUUP0RExoI7VcHbCG4YQhgvuDvNAkBQ CUolcwebe/sBcDrsqetGyqn/WjHaSZcnnDUdiu4VzOUwveaEafeRVCeiydHPfzNn rflkK2MphtTLDhGaRAKRAkASKlhV8aTBzTty/V3XMQfFVIAdHCyEIGMdjDDSzPly shZCn66IyIze8j5Q4ZLcRz6GPglHdrkBnyt4QFuGurpl -----END 私钥-----` public = `-----BEGIN 公钥----- MIGJAoGBANzvdp8jGpg4eDzSm4MgxiupQCJOLwSJNUMSI71gTf5XFG83Sxql7fPH VR2GAifeII9TPIja/A0AMh3cuO4iOR0Jx0HZ8esFNtzLq7TnjkedjjYX1pDtwCvX rxsdyqFCgpydr2L2e6Q77DtKjUn0Lpavwnh7j3berv5PvPttl5fLAgMBAAE= -----END 公钥-----` ) func digitalSign(privateKey, plainText string) (signText []byte, err error) { var ( pemBlock, _ = pem.</description>
    </item>
    <item>
      <title>prometheus operator使用</title>
      <link>https://www.oomkill.com/prometheus-operator/</link>
      <pubDate>Mon, 02 Nov 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/prometheus-operator/</guid>
      <description>什么是 Operator？ Operator是由CoreOS公司开发的，用来扩展kubernetes APi的特定的应用程序控制器，Operator基于Kubernetes的资源和控制器概念之上构建，但同时又包含了对相应应用程序特定的一些专业知识。创建operator的关键是 CRD（CustomResourceDefinition）的设计。
Prometheus Operator Prometheus Operator 是CoreOS公司提供的基于Prometheus及其相关监视组件对Kubernetes集群组件的管理，该Operator目的是简化和自动化针对Kubernetes集群的基于Prometheus的管理及配置。
Prometheus Operator架构组件 Operator：作为Prometheus Operator的核心组件，也即是自定义的控制器，用来监视和部署管理Prometheus Operator CRD资源对象，监控并维持CRD资源状态。 Prometheus Server：Operator 根据自定义资源 Prometheus 类型中定义的内容而部署的Prometheus Cluster Prometheus Operator CRD： Prometheus：以CRD资源提供给Operator的类似于Pod资源清单定位的资源。 ServiceMonitor：声明定义对Kubernetes Services资源进行监控，使用标签选择器来选择所需配置的监控，后端是Service的Endpoint，通过Service标签选择器获取EndPoint对象。 PodMonitor：使用标签选择器，选择对匹配Pod进行监控 Alertmanager：声明定义了Alertmanager在Kubernetes中运行所提供的配置。 PrometheusRule: 声明定义了Prometheus在Kubernetes中运行所需的Rule配置。 reference
Prometheus-Operator-design
Prometheus Operator监控二进制kubernetes 查看兼容性列表选择对应的版本来下载，此处kubernetes集群为1.8.10 。
对应地址为 https://github.com/prometheus-operator/kube-prometheus.git ，可以在域名后添加.cnpmjs.org 访问中国的github加速。
bash 1 git clone https://github.com.cnpmjs.org/prometheus-operator/kube-prometheus.git 资源清单在项目目录 manifests CRD在 manifests/setup 需要先安装CRD 和 Operator 对象
kube-controller-manager 和 kube-scheduler 无监控数据 二进制部署的Kubernetes集群中部署Prometheus Operator，会发现在prometheus server的页面上发现kube-controller和kube-schedule的target为0/0。匹配不到节点信息，这是因为serviceMonitor是根据label去选取svc的。此处svc并没有kube-controller和kube-schedule 需要手动创建。
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 apiVersion: v1 kind: Service metadata: namespace: kube-system name: kube-controller-manager labels: k8s-app: kube-controller-manager component: kube-controller-manager spec: selector: k8s-app: kube-controller-manager component: kube-controller-manager ports: - name: https-metrics port: 10252 targetPort: 10252 --- apiVersion: v1 kind: Endpoints metadata: namespace: kube-system name: kube-controller-manager labels: k8s-app: kube-controller-manager component: kube-controller-manager subsets: - addresses: - ip: &amp;#34;10.</description>
    </item>
    <item>
      <title>常用加密算法学习总结之非对称加密</title>
      <link>https://www.oomkill.com/asymmetric/</link>
      <pubDate>Mon, 02 Nov 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/asymmetric/</guid>
      <description>公开密钥密码学（英语：Public-key cryptography）也称非对称式密码学（英语：Asymmetric cryptography）是密码学的一种演算法。常用的非对称加密算法有 RSA DSA ECC 等。公开密钥加密
非对称加密算法使用公钥、私钥来加解密。
公钥与私钥是成对出现的。 多个用户（终端等）使用的密钥交公钥，只有一个用户（终端等）使用的秘钥叫私钥。 使用公钥加密的数据只有对应的私钥可以解密；使用私钥加密的数据只有对应的公钥可以解密。 非对称加密通信过程 下面我们来看一看使用公钥密码的通信流程。假设Alice要给Bob发送一条消息，Alice是发送者，Bob是接收者，而这一次窃听者Eve依然能够窃所到他们之间的通信内容。 参考自维基百科
⑴ Alice与bob事先互不认识，也没有可靠安全的沟通渠道，但Alice现在却要透过不安全的互联网向bob发送信息。 ⑵ Alice撰写好原文，原文在未加密的状态下称之为明文 plainText。 ⑶ bob使用密码学安全伪随机数生成器产生一对密钥，其中一个作为公钥 publicKey，另一个作为私钥 privateKey。 ⑷ bob可以用任何方法传送公钥publicKey 给Alice，即使在中间被窃听到也没问题。 ⑸ Alice用公钥publicKey把明文plainText进行加密，得到密文 cipherText ⑹ Alice可以用任何方法传输密文给bob，即使中间被窃听到密文也没问题。 ⑺ bob收到密文，用私钥对密文进行解密，得到明文 plainText。 由于其他人没有私钥，所以无法得知明文；如果Alice，在没有得到bob私钥的情况下，她将重新得到原文。
RSA RSA是一种非对称加密算法，是由罗纳德·李维斯特（Ron Rivest）、阿迪·萨莫尔（Adi Shamir）和伦纳德·阿德曼（Leonard Adleman）在1977年一起提出，并以三人姓氏开头字母拼在一起组成的。
RSA公钥和密钥的获取：随机选择两个大的素数，p q $N = p*q$ RSA加密过程：$cipherText = plainText ^ E mod N$，$(N,e)$为公钥，$(N,d)$为私钥。 RSA解密过程：$plainText = cipherText^ D mod N$
Go语言中RSA的应用 在Go语言中生成公钥与私钥 生成秘钥流程 ⑴ 使用crypto/rsa中的GenerateKey(random io.Reader, bits int)方法生成私钥（结构体） ⑵ 因为X509证书采用了ASN1描述结构，需要通过Go语言API将的到的私钥（结构体），转换为BER编码规则的字符串。 ⑶ 需要将ASN1 BER 规则转回为PEM数据编码。pem.</description>
    </item>
    <item>
      <title>常用加密算法学习总结之对称加密</title>
      <link>https://www.oomkill.com/symmetric/</link>
      <pubDate>Sat, 31 Oct 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/symmetric/</guid>
      <description>对称加密，又称为 共享密钥加密算法，是指加密和解密方使用相同密钥的加密算法。对称加密算法的优点在于加解密的高速度和使用长密钥时的难破解性。
对称加密算法 DES DES（Data Encryption Standard）：数据加密标准，速度较快，适用于加密大量数据的场合。1977年被美国联邦政府的国家标准局确定为联邦资料处理标准（FIPS）
DES的加密和解密 DES是一种将64bit（8Byte）的明文加密成64bit的密文的对称密码算法，==它的密钥长度是56比特==。从规格上来说，DES的密钥长度是64bit，但由于每隔7bit会设置一个用于==错误检查==的比特，因此实质上其密钥长度是56bit。
DES是以64bit的明文（比特序列）为一个单位来进行加密的，这个64bit的单位称为分组。一般来说，以分组为单位进行处理的密码算法称为分组密码（blockcipher），DES就是分组密码的一种。
DES每次只能加密64比特的数据，如果要加密的明文比较长，就需要对DES加密进行迭代（反复），而迭代的具体方式就称为模式（mode）。
3DES 3DES（Triple DES）：是三重数据加密算法（TDEA，Triple Data Encryption Algorithm）块密码的通称。是基于DES，对一块数据用三个不同的密钥进行三次加密，强度更高。
3DES是基于计算机的运算能力的增强，基于DES算法，增强秘钥进行多绪加密，而不是一种块密码算法。
AES AES（Advanced Encryption Standard）：高级加密标准，是美国联邦政府采用的一种区块加密标准。
分组密码模式 **分组密码（blockcipher）**是每次只能处理特定长度的一块数据的一类密码算法，这里的一块&amp;quot;就称为分组（block）。此外，一个分组的比特数就称为分组长度（blocklength）。
例如，DES和3DES的分组长度都是64比特。这些密码算法一次只能加密64比特的明文．并生成64比特的密文。
AES的分组长度可以从128比特、192比特和256比特中进行选择。当选择128比特的分组长度时，AES一次可加密128比特的明文，并生成128比特的密文。
分组密码算法只能加密固定长度的分组，但是我们需要加密的明文长度可能会超过分组密码的分组长度，这时就需要对分组密码算法进行迭代，以便将一段很长的明文全部加密。而迭代的方法就称为分组密码的模式（mode）。
分组密码的模式有很多种类，分组密码的主要模式有以下5种：
明文与密文分组 **明文分组: **是指分组密码算法中作为加密对象的明文。明文分组的长度与分组密码算法的分组长度是相等的。 **密文分组: **是指使用分组密码算法将明文分组加密之后所生成的密文。 ECB模式：Electronic Code Book mode（电子密码本模式） ECB是最简单的加密模式，明文消息被分成固定大小的块（分组），并且每个块被单独加密。 每个块的加密和解密都是独立的，且使用相同的方法进行加密，所以可以进行并行计算，但是这种方法一旦有一个块被破解，使用相同的方法可以解密所有的明文数据，安全性比较差。 适用于数据较少的情形，加密前需要把明文数据填充到块大小的整倍数。
使用ECB模式加密时，相同的明文分组会被转换为相同的密文分组，因此ECB模式也称为电子密码本模式当最后一个明文分组的内容小于分组长度时（如一个分组8bit），需要用一特定的数据进行填充（padding），让值一个分组长度等于分组长度。
ECB模式是所有模式中最简单的一种。ECB模式中，明文分组与密文分组是一一对应的关系，因此，如果明文中存在多个相同的明文分组，则这些明文分组最终都将被转换为相同的密文分组。这样一来，只要观察一下密文，就可以知道明文中存在怎样的重复组合，并可以以此为线索来破译密码，因此ECB模式是存在一定风险的。
CBC模式：Cipher Block Chaining mode（密码分组链接/密码块 模式） 1976年，IBM发明了密码分组链接CBC。CBC模式中每一个分组要先和前一个分组加密后的数据进行XOR异或操作，然后再进行加密。 这样每个密文块依赖该块之前的所有明文块，为了保持每条消息都具有唯一性，在第一个块进行加密之前需要用初始化向量 IV 进行异或操作。 CBC模式是一种最常用的加密模式，它主要缺点是加密是连续的，不能并行处理，并且与ECB一样消息块必须填充到块大小的整倍数。
**当加密第一个明文分组时，由于不存在 “前一个密文分组&amp;quot;，因此需要事先准备一个长度为一个分组的比特序列来代替“前一个密文分组&amp;quot;，这个比特序列称为初始化向量（initialization vector）**通常缩写为 IV。一般来说，每次加密时都会随机产生一个不同的比特序列来作为初始化向量。
CFB模式：Cipher FeedBack mode（密文反馈模式） 密文反馈模式 CFB；在CFB模式中，前一个分组的密文加密后和当前分组的明文XOR异或操作生成当前分组的密文。所谓反馈，这里指的就是返回输入端的意思，即前一个密文分组会被送回到密码算法的输入端。
在ECB和CBC中，明文分组都是通过密码算法进行加密的，然而，在CFB模式中，明文分组和密文分组之间并没有经过&amp;quot;加密&amp;quot;这一步骤，明文分和密文分组之间只有一个XOR。
OFB模式：Output FeedBack mode（输出反馈模式） 输出反馈模式, OFB。在OFB模式中，上一个分组密码算法的输出是当前分组密码算法的输入（下图）
CTR模式：CounTeR mode（计数器模式） CTR是一种通过将逐次累加的计数器进行加密来生成密钥流的流密码；即每个分组对应一个逐次累加的计数器，并通过对计数器进行加密来生成密钥流。也就是说，最终的密文分组是通过将计数器加密得到的比特序列，与明文分组进行XOR而得到的。</description>
    </item>
    <item>
      <title>将traefik部署为传统web架构模式</title>
      <link>https://www.oomkill.com/traefik-on-physical/</link>
      <pubDate>Sun, 04 Oct 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/traefik-on-physical/</guid>
      <description>traefik概述 traefik-现代反向代理，也可称为现代边缘路由；traefik原声兼容主流集群，Kubernetes，Docker，AWS等。官方的定位traefik是一个让开发人员将时间花费在系统研发与部署功能上，而非配置和维护。并且traefik官方也提供自己的服务网格解决方案
作为一个 modern edge router ，traefik拥有与envoy相似的特性
基于go语言研发，目的是为了简化开发人员的配置和维护 tcp/udp支持 http L7支持 GRPC支持 服务发现和动态配置 front/ edge prory支持 可观测性 流量管理 &amp;hellip; traefik 术语 要了解trafik，首先需要先了解一下 有关trafik中的一些术语。
EntryPoints 入口点，是可以被下游客户端连接的命名网络位置，类似于envoy 的listener和nginx的listen services 服务，负载均衡，上游主机接收来自traefik的连接和请求并返回响应。 类似于nginx upstream envoy的clusters Providers 提供者，提供配置文件的后端，如文件，consul，redis，etcd等，可使traefik自动更新 routers 路由器，分析请求，将下游主机的请求处理转入到services middlewares: 中间件，在将下游主机的请求转入到services时进行的流量调整 traefik部署安装 traefik为go语言开发的，可以直接下载运行即可。此处介绍直接运行二进制程序
后端环境准备,此处为docker运行的两个后端。
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 version: &amp;#39;3&amp;#39; services: webserver1: image: sealloong/envoy-end:latest ports: - 91:90 networks: envoymesh: aliases: - v1_server - default_server environment: - VERSION=v1 - COLORFUL=blue expose: - 90 webserver2: image: sealloong/envoy-end:latest ports: - 92:90 networks: envoymesh: aliases: - v1_server - default_server environment: - VERSION=v1 - COLORFUL=blue expose: - 90 networks: envoymesh: {} traefik配置说明 Traefik中的配置可以引用两种不同的内容：</description>
    </item>
    <item>
      <title>windows下Docker Desktop安装管理</title>
      <link>https://www.oomkill.com/windows10-install-docker-desktop/</link>
      <pubDate>Fri, 02 Oct 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/windows10-install-docker-desktop/</guid>
      <description>检查要求 Windows 10 企业版、专业版或教育版 （必须windows10 1903版本以上）版本号 18362.1049+ 或 18363.1049+ ，次版本＃大于.1049。最好是最新版（新版windows可以hype-v wsl2 vmvare共存，但安卓模拟器目前还没稳定的共存版本）。建议使用wsl2，安装包容量会比起hype-v小很多 。 Windows开启wsl2，建议 Windows 10 2004（版本号不低于 19041.264），可wsl2与vmvare共存。 CPU 支持并开启虚拟化（Intel VT-c 或 AMD SVM）。 最少 4 GB 内存。 对于专业版、企业版、教育版可以使用docker desktop wsl2模式，此处无需开启Hype-v
对于Win10 家庭版，Win10 19041.264之前版本，及 Win7 8用户，可以使用docker desktop Hype-v 后端。
修改安装盘 Docker Desktop 默认安装到 C:\Program Files\Docker 并不可更改，这样很不友好，可以通过软连接的方式改变Docker Desktop 默认安装盘。
text 1 mklink /J &amp;#34;C:\Program Files\Docker&amp;#34; &amp;#34;D:\Program Files\Docker&amp;#34; 限制wsl2运行最大内存 WSL 是 Microsoft 提供的一项功能，可以使开发人员能够直接在 Windows 上运行 GNU/Linux 环境，无需修改，无需传统虚拟机或双引导设置，减少了开发人员的使用复杂度
在 Docker Desktop 使用了 WSL 2 中的动态内存分配特性，极大地提高了资源消耗。这意味着，Docker Desktop 仅使用其所需的 CPU 和内存资源量，同时使 CPU 和内存密集型任务（例如构建容器）运行得更快。</description>
    </item>
    <item>
      <title>zimbra安装故障记录</title>
      <link>https://www.oomkill.com/zimbra-troubleshooing/</link>
      <pubDate>Fri, 02 Oct 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/zimbra-troubleshooing/</guid>
      <description>启动故障：zimbra postsuper: fatal: scan_dir_push: open directory defer: Permission denied bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Host mail.domain.com Starting ldap...Done. Starting zmconfigd...Done. Starting dnscache...Done. Starting logger...Done. Starting mailbox...Done. Starting memcached...Done. Starting proxy...Done. Starting amavis...Done. Starting antispam...Done. Starting antivirus...Done. Starting opendkim...Done. Starting snmp...Done. Starting spell...Done. Starting mta...Failed. Starting saslauthd...done. postsuper: fatal: scan_dir_push: open directory defer: Permission denied postfix failed to start Starting stats.</description>
    </item>
    <item>
      <title>Envoy：TLS双向认证</title>
      <link>https://www.oomkill.com/envoy-mutual-tls/</link>
      <pubDate>Tue, 29 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/envoy-mutual-tls/</guid>
      <description>环境准备 主机 角色 数量 front-envoy front envoy 1 service envoy 作为内部后端的envoy 2 end 后端应用程序 2 访问 / front-envoy ==&amp;gt; end * 2 访问 /red/colorful ==&amp;gt; end red 不验证客户端证书 单项tls 访问 /gray/colorful ==&amp;gt; end gray 验证客户端证书 双项tls
docker-compose text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 version: &amp;#39;3&amp;#39; services: front-envoy: image: envoyproxy/envoy-alpine:v1.</description>
    </item>
    <item>
      <title>Centos7 dbus问题总结</title>
      <link>https://www.oomkill.com/centos7-dbus-troubleshooting/</link>
      <pubDate>Wed, 23 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/centos7-dbus-troubleshooting/</guid>
      <description>Authorization not available. Check if polkit text 1 2 3 4 Authorization not available. Check if polkit service is running or see debug message for more information. dbus.socket failed to listen on sockets: Address family not supported by protocol Failed to listen on D-Bus System Message Bus Socket. 这个问题是因为dbus.socket状态异常，所有依赖dbus的启动都会去通过systemcall连接 dbus，当服务不可用时，所有服务无法以systemd方式正常启动/关闭。需要检查dbus.socket是否正常。本地使用需保证unix套接字的监听时启动的
Did not receive a reply text 1 Failed to open connection to &amp;#34;system&amp;#34; message bus: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.</description>
    </item>
    <item>
      <title>Envoy开启访问日志 access_log</title>
      <link>https://www.oomkill.com/envoy-access-log/</link>
      <pubDate>Tue, 22 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/envoy-access-log/</guid>
      <description> text 1 2 3 4 5 6 7 access_log: - name: envoy.listener.accesslog typed_config: &amp;#34;@type&amp;#34;: type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog path: /var/log/envoy.log log_format: text_format: &amp;#34;[%START_TIME%] \&amp;#34;%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\&amp;#34; %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% \&amp;#34;%REQ(X-FORWARDED-FOR)%\&amp;#34; \&amp;#34;%REQ(USER-AGENT)%\&amp;#34; \&amp;#34;%REQ(X-REQUEST-ID)%\&amp;#34; \&amp;#34;%REQ(:AUTHORITY)%\&amp;#34; \&amp;#34;%UPSTREAM_HOST%\&amp;#34;\n&amp;#34; </description>
    </item>
    <item>
      <title>记录经过envoy代理后获取客户端真实IP</title>
      <link>https://www.oomkill.com/envoy-real-ip/</link>
      <pubDate>Tue, 22 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/envoy-real-ip/</guid>
      <description>在envoy作为前端代理时，用户ip的获取很重要，一般获取ip的方式。都是通过Header中的 X-Forward-For、 X-Real-IP或 Remote addr 等属性获取，但是如果确保Envoy可以获取到的ip是真实的用户ip呢？本篇继续解密！
概念说明 Remote Address 是nginx与客户端进行TCP连接过程中，获得的客户端真实地址。Remote Address 无法伪造，因为建立 TCP 连接需要三次握手，如果伪造了源 IP，无法建立 TCP 连接，更不会有后面的 HTTP 请求。 一般情况下，在Envoy作为最外层代理时，此IP为真实的IP客户端IP
X-Real-IP 是一个自定义头。X-Real-Ip 通常被 HTTP 代理用来表示与它产生 TCP 连接的设备 IP，这个设备可能是其他代理，也可能是真正的请求端。X-Real-Ip 目前并不属于任何标准，代理和 Web 应用之间可以约定用任何自定义头来传递这个信息。
X-Forwarded-For X-Forwarded-For 是一个扩展头。HTTP/1.1（RFC 2616）协议并没有对它的定义，它最开始是由 Squid 这个缓存代理软件引入，用来表示 HTTP 请求端真实 IP，现在已经成为事实上的标准，被各大 HTTP 代理、负载均衡等转发服务广泛使用，并被写入 RFC 7239（Forwarded HTTP Extension）标准之中。通常，X-Forwarded-For可被伪造，并且使用CDN会被重写
Envoy中如何获取真实IP 在Envoy中，涉及到客户端IP的配置如下： use_remote_address： 默认值false，设置为true，使用客户端连接的真实远程地址，false是使用x-forwarded-for skip_xff_append： 设置为true，则不会将远程地址附加到x-forwarded-for中 request_headers_to_add 添加请求头 request_headers_to_remove 删除一个请求头
实验环境配置准备 yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 admin: access_log_path: /dev/null address: socket_address: { address: 0.</description>
    </item>
    <item>
      <title>使用alpine为基础镜像Q&amp;A</title>
      <link>https://www.oomkill.com/alpine-trouble-q-and-a/</link>
      <pubDate>Sun, 20 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/alpine-trouble-q-and-a/</guid>
      <description>作为go应用存在二进制文件却不能执行 明明镜像中有对应的二进制文件，但是执行时却提示 not found 或 no such file 或 standard_init_linux.go:211: exec user process caused &amp;quot;no such file or directory&amp;quot;
网上常说都是因为windows换行符编码问题。此处实际问题是该二进制文件是使用动态链接方式编译.
解决方法：
text 1 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build --ldflags &amp;#34;-extldflags -static&amp;#34; 注意：CGO_ENABLED=0 GOOS=linux GOARCH=amd64 和 cgo_enabled=0 goos=linux goarch=amd64 是有区别的。
保存信息
诸如此类信息都是上述问题
text 1 2 3 4 standard_init_linux.go:211: exec user process caused &amp;#34;no such file or directory&amp;#34; /tmp # ./envoy_end /bin/sh: ./envoy_end: not found 替换为国内源 text 1 RUN sed -i &amp;#39;s@http://dl-cdn.alpinelinux.org/@https://mirrors.aliyun.com/@g&amp;#39; /etc/apk/repositories 基于alpine制作PHP镜像 alpine包搜索 https://pkgs.</description>
    </item>
    <item>
      <title>centos配置</title>
      <link>https://www.oomkill.com/centos-configration/</link>
      <pubDate>Thu, 17 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/centos-configration/</guid>
      <description>CentOS7 / CentOS8 设置终端屏幕分辨率 Centos7 修改文件 /boot/grub2/grub.cfg
搜索 linux16
text 1 2 vmlinuz-3.10.0-123.el7.x86_64 root=UUID=881ac4e6-4a55-47b1-b864-555de7051763 ro rd.lvm.lv=centos/swap vconsole.font=latarcyrheb-sun16 rd.lvm.lv=centos/root crashkernel=auto vconsole.keymap=us rhgb quiet LANG=en_US.UTF-8 添加如下,???具体看下表
text 1 2 3 vga=0x??? vga=0x340 CentOS 8 CentOS8 使用了 blsgcfg来解析文件生成菜单项。菜单项配置文件在/boot/loader/entries/下，每一个文件表示一个启动项。
这里需要修改启动项的参数，这里修改options，实际上是修改了 /boot/grub2/grubenv对应的值。
text 1 options $kernelopts $tuned_params 可以直接修改/etc/sysconfig/grub中的GRUB_CMDLINE_LINUX值后增加=加vga=0x??? （对照分辨率表修改???）。
修改完成后执行 grub2-mkconfig -o /boot/grub2/grub.cfg 重启即修改了/boot/grub2/grubenv对应的值。
centos7 启动引导顺序 查看默认启动项 grub2-editenv list 查看启动项列表 awk -F\&#39; &#39;$1==&amp;quot;menuentry &amp;quot; {print $2}&#39; /etc/grub2.cfg 设置默认引导 grub2-set-default &#39;Windows 10&#39; 设置默认启动项 grub2-set-default 2 需要按照启动项列表顺序 重新生成grub2.</description>
    </item>
    <item>
      <title>Envoy 离群检测</title>
      <link>https://www.oomkill.com/outlier-detection/</link>
      <pubDate>Tue, 15 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/outlier-detection/</guid>
      <description>outlier detection 在异常检测领域中，常常需要决定新观察的点是否属于与现有观察点相同的分布（则它称为inlier），或者被认为是不同的（称为outlier）。离群是异常的数据，但是不一定是错误的数据点。
在Envoy中，离群点检测是动态确定上游集群中是否有某些主机表现不正常，然后将它们从正常的负载均衡集群中删除的过程。outlier detection可以与healthy check同时/独立启用，并构成整个上游运行状况检查解决方案的基础。
此处概念不做过多的说明，具体可以参考官方文档与自行google
监测类型 连续的5xx 连续的网关错误 连续的本地来源错误 更多介绍参考官方文档 outlier detection
离群检测测试 说明，此处只能在单机环境测试更多还的参考与实际环境
环境准备 docker-compose 模拟后端5个节点
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 version: &amp;#39;3&amp;#39; services: envoy: image: envoyproxy/envoy-alpine:v1.</description>
    </item>
    <item>
      <title>Envoy的主动健康监测</title>
      <link>https://www.oomkill.com/initiative-health-check/</link>
      <pubDate>Mon, 14 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/initiative-health-check/</guid>
      <description>实验文件 docker-compose
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 version: &amp;#39;3&amp;#39; services: envoy: image: envoyproxy/envoy-alpine:v1.15-latest environment: - ENVOY_UID=0 - HEALTHY=ok ports: - 80:80 - 443:443 - 82:9901 volumes: - .</description>
    </item>
    <item>
      <title>Envoy V3APi 开启 TLS</title>
      <link>https://www.oomkill.com/envoy-v3-api-tls/</link>
      <pubDate>Sun, 13 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/envoy-v3-api-tls/</guid>
      <description>方案架构 本次实例与官方Envoy front_proxy Example相似，首先会有一个Envoy单独运行。ingress的工作是给其他地方提供一个入口。来自外部的传入连接请求到这里，前端代理将会决定他们在内部的转发路径。 图源自Envoy官网文档 front_proxy
生成证书 text 1 openssl req -nodes -new -x509 -keyout certs/server.key -out certs/server.crt -days 365 -subj &amp;#34;/C=CN/ST=Guangdong/L=Guangzhou/O=studyenvoy/OU=studyenvoy/CN=*.studyenvoy.cn&amp;#34; envoy配置说明 v3 api中envoy去掉了tls_context的配置，配置tls首先需要熟悉envoy的如下两个术语
Downstream：下游主机连接到 Envoy，发送请求并或获得响应。 Upstream：上游主机获取来自 Envoy 的链接请求和响应。 本次使用的是ingress的代理，需要配置的即为 Downstream
v3api中使用的是transport_socket，transport_socket为 listeners 当中某一个 filter_chains 中上线文中的配置。
transport_socket 官方说明为： (config.core.v3.TransportSocket) Optional custom transport socket implementation to use for downstream connections. To setup TLS, set a transport socket with name tls and DownstreamTlsContext in the typed_config. If no transport socket configuration is specified, new connections will be set up with plaintext.</description>
    </item>
    <item>
      <title>envoy官方example运行失败问题处理</title>
      <link>https://www.oomkill.com/envoy-example-failed/</link>
      <pubDate>Sat, 12 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/envoy-example-failed/</guid>
      <description>镜像内安装包失败处理 方法一：修改Dockerfile，在Dockerfile中增加如下
ubuntu示例
text 1 2 RUN sed -i &amp;#39;s/archive.ubuntu.com/mirrors.aliyun.com/g&amp;#39; /etc/apt/sources.list RUN sed -i &amp;#39;s/security.ubuntu.com/mirrors.aliyun.com/g&amp;#39; /etc/apt/sources.list apline示例
text 1 RUN sed -i &amp;#39;s@http://dl-cdn.alpinelinux.org/@https://mirrors.aliyun.com/@g&amp;#39; /etc/apk/repositories 方法二：使用http代理，
ubuntu 参考 命令行使用代理
下载镜像失败处理 方法一：docker宿主机使用ss，开启局域网可连接。同局域网中的都可直接连此代理 方法二： docker systemd的 service文件中增加http代理
可看到已经可以成功运行envoy example示例
cannot bind &amp;lsquo;0.0.0.0:80&amp;rsquo;: Permission denied docker-compose文件
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 version: &amp;#39;3&amp;#39; services: envoy: image: envoyproxy/envoy-alpine:v1.15-latest volumes: - .</description>
    </item>
    <item>
      <title>Envoy TLS 配置</title>
      <link>https://www.oomkill.com/envoy-tls-configuration/</link>
      <pubDate>Wed, 02 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/envoy-tls-configuration/</guid>
      <description>official front proxy
在一个Services Mash内部中，都会存在一到多个微服务，为了将南北向流量统一引入网格内部管理，通常存在单独运行的envoy实例。
Envoy的listener支持面向下游客户端一侧的TLS会话，并可选地支持验正客户端证书；
listener中用到的数字证书可于配置中静态提供，也可借助于SDS动态获取;
tls_context 是 listeners 当中某一个 filter_chains 中上线文中的配置，tls_context 配置在哪个 listeners当中就隶属于哪个listeners。
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 listeners: ... filter_chains: - filters: .. tls_context: common_tls_context: {} # 常规证书相关设置； tls_params: {} # TLS协议版本，加密套件等； tls_certifcates: [] # 用到的证书和私钥文件； - certifcate_chain: {} filename: # 证书文件路径; private_key: {} # 私钥; filename: # 私钥文件路径; password: {} # 私钥口令； filename: # 口令文件路径； tls_certifcate_sds_secret_configs: [] # 要基于SDS API获取TLS会话的相关信息时的配置； require_client_certifcate: # 是否验证客户端证书； 例如，下面示例将前面的Ingress示例中的Envoy配置为通过TLS提供服务，并将所有基于http协议的请求重定向至https；</description>
    </item>
    <item>
      <title>Envoy部署</title>
      <link>https://www.oomkill.com/envoy-deployment/</link>
      <pubDate>Wed, 02 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/envoy-deployment/</guid>
      <description>常用的构建方法 https://skyao.io/learning-envoy/
手动配置构建环境，手动构建Envoy。
使用Envoy提供的预制于Docker中的构建环境进行手动构建二进制Envoy
使用Envoy提供的预制于Docker中的构建环境进行手动构建二进制Envoy，并直接将Envoy程序打包成Docker镜像
提供Bootstrap配置文件，存在使用xDS的动态资源时，还需要基于文件或管理服务器向其提供必须的配置信息
也可使用Envoy的配置生成器生成示例性配置 基于Bootstrap配置文件启动Envoy实例
直接启动二进制Envoy 于Kubernetes平台基于Sidecar的形式运行Envoy，或运行单独的Envoy Pod（Edge Proxy） 启动Envoy 启动Envoy时，需要通过（-c 选项为其指定初始配置文件以提供引导配置（Bootstrap configuration），这也是使用v2APl的必然要求；
text 1 envoy -c &amp;lt;path to config&amp;gt;.{json,yaml,pb,pb_text} 扩展名代表了配置信息的组织格式；
引导配置是Envoy配置信息的基点，用于承载Envoy的初始配置，它可能包括静态资源和动态资源的定义
静态资源（static_resources）于启动直接加载
动态资源（dynamic_resources）则需要通过配置的xDS服务获取并生成
通常，Listener 和 Cluster 是Envoy得以运行的基础，而二者的配置可以全部为静态格式，也可以混合使用动态及静态方式提供，或者全部配置为动态；
一个yaml格式纯静态的基础配置框架类似如下所示：
yaml 1 2 3 4 5 6 7 8 9 10 11 static_resources: linteners: - name: ... address: {} filter_chains: [] clusters: - name: ... type: ... connect_timeout: {} lb_policy: ... load_assignment: {} Listener 简易静态配置 侦听器主要用于定义Envoy监听的用于接收Down streams请求的套接字、用于处理请求时调用的过滤器链及相关的其它配置属性;目前envoy仅支持tcp的协议
yaml 1 2 3 4 listeners: - name: address: socket_address: { address: .</description>
    </item>
    <item>
      <title>Envoy管理</title>
      <link>https://www.oomkill.com/envoy-administartion/</link>
      <pubDate>Wed, 02 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/envoy-administartion/</guid>
      <description>envoy内建了一个管理接口，它支持查询和修改操作，甚至有可能暴露私有数据（例如统计数据、集群名称和证书信息等）因此非常有必要精心编排期访问控制机制，以避免非授权访问。
administration interface 属于 bootstrap 配置文件中的==顶级配置字段==使用。
administration interface offical document
yaml 1 2 3 4 5 6 7 8 admin: access_log_path: .. # 管理接口的访问日志文件路径，无须记录访问日志使用/dev/null profile_path: ... # cpu_profile的输出路径，默认为/var/log/envoy/envoy.prof; address: socket_address: # 监听的套接字 protocol: .. address: ... prot_value: ... 下面是一个简单的配置示例
yaml 1 2 3 4 admin: access_log_path: /tmp/admin_access.log address: socket_address: { address: 127.0.0.1, port_value: 9901 } admin接口内置了多个 /path ，不同的path可能会分别接受不同的GET或POST请求
GET /help ：打印所有可用选项； / : Admin home page /certs : GET 列出在的所有TLS相关的信息； /clusters : upstream cluster status GET，格外支持使用 /clusters?</description>
    </item>
    <item>
      <title>Envoy基础</title>
      <link>https://www.oomkill.com/envoy-fundamental/</link>
      <pubDate>Wed, 02 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/envoy-fundamental/</guid>
      <description>服务网格的基本功能
控制服务间通信：熔断、重试、超时、故障注入、负载均衡和故障转移等。 服务发现：通过专用的服务总监发现服务端点。 可观测：指标数据采集、监控、分布式日志记录和分布式追踪。 安全性：TLS/SSL通信和秘钥管理。 身份认证和授权检查：身份认证，以及基于黑白名单或RBAC的访问控制功能。 部署：对容器技术的原生支持，例如Docker和Kubernetes等。 服务间的通信协议：HTTP1.1 HTTP2.0和gRPC等。 健康状态监测：监测上游服务的健康状态。 &amp;hellip;. 服务网格的部署模式有两种：主机共享代理和Sidecar容器
主机共享代理 适用于同一主机存在许多容器的场景，并且还可以利用连接池来提高吞吐量。 带一个代理进程故障将终止其所在主机上的整个容器队列，受影响的不仅仅是单个服务。 实现方式中，常见的是允许为Kubernetes之上的 DaemonSet。 Sidecar容器 代理进程注入每个Pod定义以与住容器一同运行。 Sidecar进程应该尽可能轻量且功能完善。 实现方案：Linkerd、Envoy和Conduit。 What IS Enovy Enovy是工作与OSI模型的7层代理
在实现上，数据平面的主流解决方案有Linkerd、Nginx、Envoy、HAProxy和Traefik等，而控制平面的实现主要有Istio、Nelson和SmartStack等几种口Linkerd ●由Buoyant公司于2016年率先创建的开源高性能网络代理程序（数据平面），是业界第一款Service Mesh产品，引领并促进了相关技术的快速发展 ·Linkerd使用Namerd提供控制平面，实现中心化管理和存储路由规则、服务发现配置、支持运行时动态路由等功能
Envoy
核心功能在于数据平面，于2016年由Lyft公司创建并开源，目标是成为通用的数据平面
云原生应用，既可用作前端代理，亦可实现Service Mesh中的服务间通信
Envoy常被用于实现APIGateway（如Ambassador）以及Kubernetes的Ingress Controller（例如gloo等），不过，基于Envoy实现的Service Mesh产品Istio有着更广泛的用户基础
Istio ·相比前两者来说，lstio发布时间稍晚，它于2017年5月方才面世，但却是目前最火热的Service Mesh解决方案，得到了Google、IBM、Lyt及Redhat等公司的大力推广及支持 ·目前仅支持部署在Kubernetes之上，其数据平而由Envoy实现
envoy适用于现代大型面向服务架构的动态组织应用程序的7层代理应用程序，其典型特性：
运行在架构进程之外 支持3/4层过滤器 支持HTTP协议7层过滤器 支持HTTP协议7层高级路由功能 envoy在现代服务体系架构当中的适用位置既可以为一组服务提供代理，作为整个服务统一的api网关来进行接入，同时也可以对每一个微服务单独实现作为代理，此时需要以sidecar的形式运行在应用程序前端。进而与最前端的apigateway组织成所谓的服务网格（Sevice Mesh）。而在每一个Envoy实例内部都要接受请求。这个请求可能是来自互联网或服务网格之外的客户端，称之为南北流量；也可能是来自网格当中的其他服务的请求，称之为东西流量。
在Envoy当中类似于Nginx或者haproxy的功能术语：
listeners ：面向客户端一侧提供监听并接受客户端请求的组件。类似于nginx的server或haproxy的frontend 。 cluster：面向后端测，将多个被代理的实例分成组，统一进行负载均衡调度的组。 cluster definltions：cluster的归类。 filter chains：过滤器链，可以将多个链以流水线方式依次进行处理。 面向客户端提供服务/监听的套接字，lintener内部包含一到多个filter组成filter chains，称之为过滤器链。过滤器是lintener内部的子组件。envoy支持4层过滤器和7层过滤器。
envoy 术语
主机（Host）：能够进行网络通信的实体（如手机，服务器等上的应用程序）。在这个文档中，主机是一个逻辑网络应用程序。一个物理硬件可能有多个主机上运行，只要他们可以独立寻址。
下游（Downstream）：下游主机连接到Envoy，发送请求并接收响应。
上游（Upstream）：上游主机接收来自Envoy的连接和请求并返回响应。
监听器（Listener）：侦听器是可以被下游客户端连接的命名网络位置（例如，端口，unix域套接字等）。Envoy公开一个或多个下游主机连接的侦听器。 filters chains，过滤器链L4/L7 route：完成对客户请求进行分类 群集（Cluster）：群集是指Envoy连接到的一组逻辑上相似的上游主机。Envoy通过服务发现发现一个集群的成员。它可以通过主动健康检查来确定集群成员的健康度，从而Envoy通过负载均衡策略将请求路由到相应的集群成员。
网格（Mesh）：协调一致以提供一致的网络拓扑的一组主机。在本文档中，“Envoy mesh”是一组Envoy代理，它们构成了由多种不同服务和应用程序平台组成的分布式系统的消息传递基础。</description>
    </item>
    <item>
      <title>Envoy健康状态监测</title>
      <link>https://www.oomkill.com/envoy-health-check/</link>
      <pubDate>Wed, 02 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/envoy-health-check/</guid>
      <description>官方文档 healthy_check
Envoy的服务发现并未采用完全一致的机制，而是假设主机以最终一致的方式加入或离开网格，它结合主动健康状态检查机制来判定集群的健康状态；
健康与否的决策机制以完全分布式的方式进行，因此可以很好地应对网络分区； 为集群启用主机健康状态检查机制后，Envoy基于如下方式判定是否路由请求到一个主机； 发现失败，单健康检查正常，此时，无法添加新主机，但现有主机将继续正常运行。 Discovery Status Health Check OK Health Check Failed Discovered Route Dont&amp;rsquo;t Route Absent Route Don&amp;rsquo;t Route / Delete 故障处理机制 Envoy提供了一系列开箱即用的故障处理机制：
超时（timeout） 有限次数的重试，并支持可变的重试延迟 主动健康检查与异常探测 连接池 断路器 所有这些特性，都可以在运行时动态配置；结合流量管理机制，用户可为每个服务/版本定制所需的故障恢复机制；
健康状态监测 健康状态检测用于确保代理服务器不会将下游客户端的请求代理至工作异常的上游主机；
Envoy支持两种类型的健康状态检测，二者均基于集群进行定义：
主动检测（Active Health Checking）：Envoy周期性地发送探测报文至上游主机，并根据其响应判断其健康状态；Envoy目前支持三种类型的主动检测：
HTTP：向上游主机发送HTTP请求报文 L3/L4：向上游主机发送L3/L4请求报文，基于响应的结果判定其健康状态，或仅通过连接状态进行判定； Redis：向上游的redis服务器发送Redis PING； 被动检测（Passive Health Checking）：Envoy通过异常检测（Outlier Detection）机制进行被动模式的健康状态检测；
目前，仅htp router、tcp proxy和redis proxy三个过滤器支持异常值检测；
Envoy支持以下类型的异常检测：
连续5XX：意指所有类型的错误，非htp router过滤器生成的错误也会在内部映射为5xx错误代码； 连续网关故障：连续5XX的子集，单纯用于http的502、503或504错误，即网关故障； 连续的本地原因故障：Envoy无法连接到上游主机或与上游主机的通信被反复中断； 成功率：主机的聚合成功率数据阀值； 主动健康状态监测 集群的主机健康状态检测机制需要显式定义，否则，发现的所有上游主机即被视为可用；
定义语法
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 clusters: - name: .</description>
    </item>
    <item>
      <title>envoy流量管理</title>
      <link>https://www.oomkill.com/envoy-traffic-management/</link>
      <pubDate>Wed, 02 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/envoy-traffic-management/</guid>
      <description>灰度发布 概述 新版本上线时，无论是出于产品稳定性还是用户接受程度等方面因素的考虑，直接以新代旧都充满风险；于是，通行做法是新老版本同时在线，且一开始仅分出较小比例的流量至新版本，待确认新版本没问题后再逐级加大流量切换。
灰度发布是迭代的软件产品在生产环境安全上线的一种重要手段，对于Envoy来说，灰度发布仅是流量治理的一种典型应用；以下是几种常见的场景口金丝雀发布
- 蓝绿发布- A/B测试- 流量镜像灰度策略 需要在生产环境发布一个新的待上线版本时，需要事先添加一个灰度版本，而后将原有的生产环境的默认版本的流量引流一部分至此灰度版本，配置的引流机制即为灰度策略，经过评估稳定后，即可配置此灰度版本接管所有流量，并下线老版本。
常用的策略类型大体可分为 “基于请求内容发布”和“基于流量比例发布”两种类型
基于请求内容发布：配置相应的请求内容规则，满足相应规则服务流量会路由到灰度版本；例如对于http请求，通过匹配特定的Cookie标头值完成引流
Cookie内容：
完全匹配：当且仅当表达式完全符合此情况时，流量才会走到这个版本；
正则匹配：此处需要您使用正则表达式来匹配相应的规则；
自定义Header：
完全匹配：当且仅当表达式完全符合此情况时，流量才会走到这个版本；
正则匹配：此处需要您使用正则表达式来匹配相应的规则；可以自定义请求头的key和value，value支持完全匹配和正则匹配；
基于流量比例发布：对灰度版本配置期望的流量权重，将服务流量以指定权重比例引流到灰度版本；例如10%的流量分配为新版本，90%的流量保持在老版本。这种灰度策略也可以称为AB测试；
注：所有版本的权重之和为100；
灰度发布的实现方式 基于负载均衡器进行灰度发布
在服务入口的支持流量策略的负载均衡器上配置流量分布机制
仅支持对入口服务进行灰度，无法支撑后端服务需求
基于Kubernetes进行灰度发布
根据新旧版本应用所在的Pod数量比例进行流量分配，不断滚动更新旧版本Pod到新版本（先增后减、先减后增、又增又减）；服务入口通常是Service或Ingress。
基于服务网格进行灰度发布
对于Envoy或lstio来说，灰度发布仅是流量治理机制的一种典型应用。通过控制平面，将流量配置策略分发至对目标服务的请求发起方的envoy sidecar上即可。
支持基于请求内容的流量分配机制，例如浏览器类型、cookie等。
服务访问入口通常是一个单独部署的Envoy Gateway。
Envoy中流量转移 新版本上线时，为兼顾到产品的稳定性及用户的接受程度，让新老版本同时在线，将流量按需要分派至不同的版本；
蓝绿发布 A/B测试 金丝雀发布 流量镜像 &amp;hellip;. HTTP路由器能够将流量按比例分成两个或多个上游集群中虚拟主机中的路由，从而产生两种常见用例：
版本升级：路由时将流量逐渐从一个集群迁移至另一个集群，实现灰度发布；
通过在路由中定义路由相关流量的百分比进行；
A/B测试或多变量测试：同时测试多个相同的服务，路由的流量必须在相同服务的不同版本的集群之间分配；通过在路由中使用基于权重的集群路由完成；另外，匹配条件中，结合指定标头或也能够完成基于内容的流量管理；
流量迁移是指，通过在路由中配置运行时对象选择特定路由以及相应集群的概率的变动，从而实现将虚拟主机中特定路由的流量逐渐从一个集群迁移到另一个集群。
runtime_fraction
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 route: - match: prefix|path|regex: runtime_faction:	# 额外匹配指定的运行时键值，每次评估匹配路径时，必须低于此字段指示的百分比，支持渐进式修改。 default_value: # 运行时键值不可用时，则使用此默认值。 numerator: # 指定分子，默认0 denominator: # 指定分母，小于分母时，最终百分比为1， 分母可使用 HUNDRED（默认） TEN_THOUSAND和MILLION， runtime_key: routing.</description>
    </item>
    <item>
      <title>Envoy路由管理</title>
      <link>https://www.oomkill.com/envoy-router-management/</link>
      <pubDate>Wed, 02 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/envoy-router-management/</guid>
      <description>HTTP 链接管理 envoy处理用户请求逻辑
① 用户请求报文到达七层过滤器链处理机制后，首先根据请求HTTP报文中的 Host 首部来完成虚拟主机的选择；② 由此虚拟机主机内部的 Route 表项进行处理。③ 后由 match 进行匹配; Match 是与请求URL的 PATH 组成部分或请求报文的标头部分 header 。④ 最后才可到达 Route 进行 direct_response 、redirect 等。
官方手册
Envoy通过内置的L4过滤器HTTP连接管理器将原始字节转换为HTTP应用层协议级别的消息和事件，例如接收到的标头和主体等，以及处理所有HTTP连接和请求共有的功能，包括访问日志、生成和跟踪请求ID，请求/响应头处理、路由表管理和统计信息等；
支持HTTP/1.1、WebSockets和HTTP/2，但不支持SPDY; 关联的路由表可静态配置，亦可经由 xDS API 中的 RDS 动态生成； 内建重试插件，可用于配置重试行为; Host Predicates Priority Predicates 内建支持302重定向，它可以捕获302重定向响应，合成新请求后将其发送到新的路由匹配（match）所指定的上游端点，并将收到的响应作为对原始请求的响应返回客户端
支持适用于HTTP连接及其组成流（constituent streams）的多种可配置超时机制
连接级别：空闲超时和排空超时（GOAWAY）； 流级别：空闲超时、每路由相关的上游端点超时和每路由相关的 gRPC 最大超时时长； 基于自定义集群的动态转发代理； HTTP协议相关的功能通过各HTTP过滤器实现，这些过滤器大体可分为编码器、解码器和编/解码器三类；
router envoy.router 是最常的过滤器之一，它基于路由表完成请求的转发或重定向，以及处理重试操作和生成统计信息等；
HTTP 路由 Envoy基于HTTP router过滤器基于路由表完成多种高级路由机制，例如:
将域名映射到虚拟主机； path的前级 prefix 匹配、精确匹配或正则表达式匹配； 虚拟主机级别的TLS重定向； path级别的 path/host 重定向； direct_response ，由Envoy直接生成响应报文 ； 显式 host rewrite； prefix rewrite； 基于HTTP标头或路由配置的请求重试与请求超时； 基于运行时参数的流量迁移； 基于权重或百分比的跨集群流量分割； 基于任意标头匹配路由规则； 基于优先级的路由； 基于hash策略的路由； 路由配置和虚拟主机 路由配置中的顶级元素是虚拟主机</description>
    </item>
    <item>
      <title>服务网格安全体系</title>
      <link>https://www.oomkill.com/service-mesh-security/</link>
      <pubDate>Wed, 02 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/service-mesh-security/</guid>
      <description>服务网格安全框架 Microservice Security Basics 零信任安全 | 什么是零信任网络？ 零信任是一种安全模型，其基础是维护严格的访问控制并且默认不信任任何人，即便是已在网络边界内的人。零信任安全
IAAA (Identification and Authentication, Authorization and Accountability Identification: 必须支持多个身份和属性
Your name, username, ID number, employee number, SSN etc. “I am Thor”. Authentication: 必须支持多种认证方式以及委托认证方式
Authorization: 对于单个请求的授权可以在请求路径中的多个点确认
Accountability: 从API中捕获相关安全数据或元数据
服务网格常见安全解决方案 网络级别控制 Network Level Contros local isolation 主机隔离
Network segementation 网络分割
意味着新人底层的服务器及网络设施，信任隔离机制及实现过程且信任网段内的所有组件； SSL/TLS
mTLS、spiffe/spire 应用级别控制 Network Level Contros 传统网络令牌认证 Traditional Web Tokens API-oriented Tokens OAuth 2.0 OpenID Connect JWT TokenTypes Opaque tokens Transparent tokens 基于cookie的会话 cookie based sessions SAML Security Assertion Markup Language 一种基于XML开源标准的数据格式，它在当事方之间交换身份验证和授权数据，尤其是在身份提供者和服务提供者之间交换。 Envoy的身份认证机制 传输认证 传输认证：即服务组件的认证，它基于双向TLS实现传输认证（即mTLS），包括双向认证、信道安全和证书自动管理；每个服务都需要有其用于服务间双向认证的标识，以实现此种认证机制；</description>
    </item>
    <item>
      <title>istio安装</title>
      <link>https://www.oomkill.com/istio-install/</link>
      <pubDate>Thu, 20 Aug 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/istio-install/</guid>
      <description>Istio用于提供统一方式来集成微服务的开放平台，管理微服务之间的流量，执行策略和汇总遥测数据。Istio的控制平面在基础集群管理平台（例如Kubernetes）上提供了一个抽象层。
Istio组成：
在Istio1.8中，istio由以下组件组成：istio-component
istio服务网格分为数据平面和控制平面
数据平面：数据平面是由一组代理组成
envoy：Sidecar Proxy 每个微服务代理来处理入口/出口业务服务之间的集群中，并从外部服务的服务。代理形成一个*安全的微服务网格，*提供了丰富的功能集合 控制平面：管理与配置代理的流量规则。
istiod：istio的控制平面，提供了服务发现，配置和证书管理，包含如下组件： Pilot ：负责运行时配置，（服务发现，智能路由） Citadel：负责证书的颁发与轮替 Galley：负责配置的管理（验证，提取，分发等功能） istio卸载
bookinfo卸载
text 1 kubectl delete -f samples/bookinfo/platform/kube/bookinfo.yaml istio卸载
text 1 istioctl manifest generate|kubectl delete -f - addons
text 1 2 3 4 kubectl delete -f samples/addons/prometheus.yaml kubectl delete -f samples/addons/jaeger.yaml kubectl delete -f samples/addons/kiali.yaml kubectl delete -f samples/addons/grafana.yaml </description>
    </item>
    <item>
      <title>istio命令</title>
      <link>https://www.oomkill.com/istio-cli/</link>
      <pubDate>Thu, 20 Aug 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/istio-cli/</guid>
      <description>显示配置文件中的差异 istioctl profile diff default demo
显示对应配置的profile istioctl profile dump demo
显示可用的配置 istioctl profile list
安装指定配置的istio istioctl install --set profile=demo
生成配置清单 istioctl manifest generate
istioctl验证安装: istioctl manifest generate --set profile=demo |istioctl verify-install -
istio的非侵入式流量治理
流量治理是一个非常宽泛的话题，例如：
◎ 动态修改服务间访问的负载均衡策略，比如根据某个请求特征做会话保持；
◎ 同一个服务有两个版本在线，将一部分流量切到某个版本上；
◎ 对服务进行保护，例如限制并发连接数、限制请求数、隔离故障服务实例等；
◎ 动态修改服务中的内容，或者模拟一个服务运行故障等。
在Istio中实现这些服务治理功能时无须修改任何应用的代码。较之微服务的SDK方式，Istio以一种更轻便、透明的方式向用户提供了这些功能。用户可以用自己喜欢的任意语言和框架进行开发，专注于自己的业务，完全不用嵌入任何治理逻辑。只要应用运行在Istio的基础设施上，就可以使用这些治理能力。 一句话总结 Istio 流量治理的目标：以基础设施的方式提供给用户非侵入的流量治理能力，用户只需 关注自己的业务逻辑开发，无须关注服务访问管理。
istio服务架构 在istio1.8中，istio的分为 envoy （数据平面） 、istiod （控制平面） 、addons（管理插件） 及 istioctl （命令行工具，用于安装、配置、诊断分析等操作）组成。
Pilot Pilot是Istio控制平面流量管理的核心组件，管理和配置部署在Istio服务网格中的所有Envoy代理实例。
pilot-discovery为envoy sidecar提供服务发现，用于路由及流量的管理。通过kubernetes CRD资源获取网格的配置信息将其转换为xDS接口的标准数据格式后，通过gRPC分发至相关的envoy sidecar
Pilot组件包含工作在控制平面中的 pilot-discovery 和工作与数据平面的pilot-agent 与Envoy(istio-proxy)
pilot-discovery主要完成如下功能：
从service registry中获取服务信息 从apiserver中获取配置信息。 将服务信息与配置信息适配为xDS接口的标准数据格式，通过xDS api完成配置分发。 pilot-agent 主要完成如下功能</description>
    </item>
    <item>
      <title>常用加密算法之数字证书与TLS/SSL</title>
      <link>https://www.oomkill.com/openssl-x509/</link>
      <pubDate>Sun, 02 Aug 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/openssl-x509/</guid>
      <description>数字证书 互联网上任意双方之间实现通信时，证书的目的有两种，
主机证书，主要实现主机与主机之间进程间通信的。 个人证书，主要用作个人通信的，主要用作加密的数据的发送。 主机类证书所拥有的标识主要为主机名，主机证书名称一定要与互联网之上访问名称一致，否则此证书为不可信证书。
对于一个安全的通信，应该有以下特征：
完整性：消息在传输过程中未被篡改 身份验证：确认消息发送者的身份 不可否认：消息的发送者无法否认自己发送了信息 显然，数字签名和消息认证码是不符合要求的，这里就需要数字证书来解决其弊端。
数字证书（digital certificate）又称公开密钥认证 PKC（英语：Public key certificate）。是在互联网通信中，方式数字签名的秘钥被篡改，是用来证明公开密钥拥有者的身份。此文件包含了公钥信息、拥有者身份信息（主体）、以及数字证书认证机构（发行者）对这份文件的数字签名，以保证这个文件的整体内容正确无误。
数字证书认证机构 CA (Certificate Authority)：是负责发放和管理数字证书的权威机构。
公钥证书的格式标准 X.509是密码学中公钥明证PKC的格式标准，所有的证书都符合ITU-T X.509国际标准。X.509证书的结构是用ASN1 (Abstract Syntax Notation One)进行描述数据结构，并使用ASN.1语法进行编码。
证书规范 X.509指的是ITU和ISO联合制定的（RFC5280）里定义的的 X.509 v3
前使用最广泛的标准为X.509的 v3版本规范 (RFC5280）, 一般遵从X.509格式规范的证书，会有以下的内容：
证书组成结构
结构 说明 版本 现行通用版本是 V3， 序号 用来识别每一张证书，用来追踪和撤销证书。只要拥有签发者信息和序列号，就可以唯一标识一个证书，最大不能过20个字节；由CA来维护 主体 拥有此证书的法人或自然人身份或机器，包括：
国家（C，Country） 州/省（S，State）** 地域/城市（L，Location） 组织/单位（O，Organization） 通用名称（CN，Common Name）：在TLS应用上，此字段一般是域名 发行者 以数字签名形式签署此证书的数字证书认证机构 有效期(Validity) 此证书的有效开始时间，在此前该证书并未生效；此证书的有效结束时间，在此后该证书作废。 公开密钥用途 指定证书上公钥的用途，例如数字签名、服务器验证、客户端验证等 公开密钥 公开密钥指纹 数字签名 使用信任的CA对内容进行 主体别名 例如一个网站可能会有多个域名（www.jd.com www.360buy.com..）
一个组织可能会有多个网站（*.baidu.com tieba.baidu.com），不同的网域可以一并使用同一张证书，方便实现应用及管理。 互联网上任意双方之间实现通信时，证书的目的有两种，
主机证书，主要实现主机与主机之间进程间通信的。 个人证书，主要用作个人通信的，主要用作加密的数据的发送。 主机类证书所拥有的标识主要为主机名，主机证书名称一定要与互联网之上访问名称一致，否则此证书为不可信证书。
数字证书文件格式 X.</description>
    </item>
    <item>
      <title>脚本在公网的加密执行</title>
      <link>https://www.oomkill.com/ciper-script/</link>
      <pubDate>Mon, 18 May 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ciper-script/</guid>
      <description>openssl 可以加密解密，当然也可以为文件加密解密
bash 1 sudo openssl des3 -e -k d36b6b41f36c87963676005ddfb931c7 -in /data/init_app.sh -out /data/rpm/init_app 解密
bash 1 curl http://47.244.200.140:8181/init_app|openssl des3 -d -k d36b6b41f36c87963676005ddfb931c7|sudo bash -s jdk8 </description>
    </item>
    <item>
      <title>Powershell阻止确认</title>
      <link>https://www.oomkill.com/powershell-confirm/</link>
      <pubDate>Sun, 19 Apr 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/powershell-confirm/</guid>
      <description>要阻止弹出确认提示，需要设置-Confirm为false,
text 1 new-VM -Name $hostname -Template $template -VMHost 10.11.31.5 -OSCustomizationspec TestLinux -Confirm:$false 获得当前确认级别
text 1 $ConfirmPreference 查看确认级别（$ConfirmPreference）支持的选项，类型为枚举
text 1 [ENUM]::GetNames($ConfirmPreference.GetType()) 设置确认级别
text 1 $ConfirmPreference=&amp;#34;None&amp;#34; </description>
    </item>
    <item>
      <title>named主从部署</title>
      <link>https://www.oomkill.com/bind9-master-slave/</link>
      <pubDate>Mon, 17 Feb 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/bind9-master-slave/</guid>
      <description>text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 // // named.</description>
    </item>
    <item>
      <title>zimbra安装三方颁发的证书</title>
      <link>https://www.oomkill.com/zimbra-install-buisness-cert/</link>
      <pubDate>Thu, 09 Jan 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/zimbra-install-buisness-cert/</guid>
      <description>步骤1：取得SSL凭证 证书需要取的从根证书每一级的证书
步骤2：合成SSL证书 将中级、根证书合成为一个证书
顺序：按照从后到前合成为一个证书 如，三级 ==》二级 ==》 根
合成后的格式如下
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 -----BEGIN CERTIFICATE----- 你的crt內容 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw 7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- 步骤3：验证你的商业证书 复制生成的所有证书到目录 /opt/zimbra/ssl/zimbra/commercial 下，（合成后的根证书、证书、与秘钥）
切換到 zimbra 用戶
text 1 2 3 4 5 6 7 8 $ zmcertmgr verifycrt comm {{privkey.</description>
    </item>
    <item>
      <title>zimbra启用SMTP认证</title>
      <link>https://www.oomkill.com/zimbra-enable-smtp-authentication/</link>
      <pubDate>Wed, 08 Jan 2020 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/zimbra-enable-smtp-authentication/</guid>
      <description> text 1 2 zmprov modifyServer {{ you domain }} zimbraMtaTlsAuthOnly FALSE zmcontrol restart 查看对应配置
text 1 zmprov getServer {{ you domain }} | grep Auth 查看SMTP是否开启成功
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 $ telnet localhost 25 Trying 127.0.0.1... Connected to localhost. Escape character is &amp;#39;^]&amp;#39;. 220 xxxx ESMTP Postfix ehlo xxxx 250-xxxxx 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-STARTTLS 250-AUTH LOGIN PLAIN #SMTP认证相关参数 250-AUTH=LOGIN PLAIN #SMTP认证相关参数 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN </description>
    </item>
    <item>
      <title>使用ldap客户端创建zimbra ldap用户的格式</title>
      <link>https://www.oomkill.com/zimbra-ldap-createaccount/</link>
      <pubDate>Mon, 16 Dec 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/zimbra-ldap-createaccount/</guid>
      <description>命令如下
ldif cat &amp;lt;&amp;lt; EOF | ldapadd -x -W -H ldap://:389 -D &amp;#34;uid=zimbra,cn=admins,cn=zimbra&amp;#34;dn: uid=jak1,ou=people,dc=mail,dc=xxxxx2021,dc=comzimbraAccountStatus: activedisplayName: jak1givenName: jak1sn: jak1zimbraMailStatus: enabledobjectClass: inetOrgPersonobjectClass: zimbraAccountobjectClass: amavisAccountzimbraId: e2214a66-3ga2-4241-9223-44f222ce0522zimbraCreateTimestamp: 20191102062818.876ZzimbraMailHost: mail.xxxx2021.comzimbraMailTransport: lmtp:mail.xxxx2021.com:7025zimbraMailDeliveryAddress: scott8@mail.xxxx2021.commail: jak1@mail.xxxx2021.comcn: jak1uid: jak1userPassword:: e1NTSEE1MTJ9ZzBzZGlXRlBjbDQxa2xmZ200YXc1ZkJzSGQzVXNBdVBydUlKRnZLTExYby9HWXBoUkNTMzZYMEx5VnpCZUJPMGJNTCtTV2IwSnhkaHdudTViR0c1bTJabFVhU3R1N1J3EOF zimbraAccountStatus 为账户设置中的状态 zimbraId 唯一的值 givenName 姓 displayName 显示名字 bash 1 ldapsearch -LLL -w 99tJFkhVfn -H ldap://172.31.110.115:389 -D &amp;#34;uid=zimbra,cn=admins,cn=zimbra&amp;#34;|less </description>
    </item>
    <item>
      <title>Kubernetes包管理 - Helm</title>
      <link>https://www.oomkill.com/helm/</link>
      <pubDate>Wed, 27 Nov 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/helm/</guid>
      <description>什么是 Helm Helm 是一个用于管理 Kubernetes 应用程序的包管理工具。它允许您定义、安装和升级 Kubernetes 应用程序，以简化应用程序部署和管理的过程。
在 Kubernetes 中，应用程序被打包为一个或多个称为 &amp;ldquo;Charts&amp;rdquo; 的 Helm 资源。一个 Chart 是一个预定义的目录结构，包含了用于部署应用程序的 Kubernetes 资源清单模板。Chart 可以包含 Deployment、Service、ConfigMap、Ingress 等 Kubernetes 资源的定义。
使用 Helm，您可以将应用程序打包为一个 Chart，并使用 Helm 客户端来安装和管理 Chart。这使得应用程序的部署过程更加简单、可重复和可扩展。您可以根据需要部署多个实例，轻松地进行升级和回滚操作，并使用 Helm 提供的值覆盖机制来自定义每个实例的配置。
最重要的是，Helm 支持使用 Helm 仓库来共享和发布 Charts。Helm 仓库是一个集中存储 Charts 的地方，供用户从中搜索和安装 Charts。Helm 仓库可以是公共的，也可以是私有的，您可以自己搭建私有仓库来管理自己的 Charts。
Helm 所作的事情 Helm 管理名为 chart 的Kubernetes包的工具。故 Helm 可以做以下的事情：
创建一个新的 chart 将 chart 打包成归档 (tgz) 文件 与存储 chart 的仓库进行交互 在现有的 Kubernetes 集群中安装和卸载 chart 管理与Helm一起安装的 chart 的发布周期 Helm中的术语 chart：类似于rpm包，deb包，包含Kubernetes资源所需要的必要信息。 repo：chart仓库，类似于yum的仓库，chart仓库是一个简单的HTTP服务。 values：提供了自定义信息用来覆盖模板中的默认值。 release ：chart安装后的版本记录。 Helm 与 YAML 资源清单比有什么优势？ 模板化和参数化: Helm 使用 Go 的模板引擎来创建 Kubernetes 资源清单。这使得您可以在 Chart 中使用模板来定义资源配置的部分内容，例如标签、名称、端口等。同时，Helm 还支持使用参数化的值，允许您根据不同的环境或需求来自定义 Chart 的配置。这样一来，您可以根据需要生成不同的 Kubernetes 资源清单，而无需手动编辑每个清单文件。 可重用性: Helm 提供了一种将应用程序打包为 Chart 的方式，可以将 Chart 存储在 Helm 仓库中进行共享和重用。这样，您可以使用其他人创建的 Charts 来快速部署常见的应用程序，避免从头开始编写和管理 Kubernetes 资源清单。同时，您也可以将自己的应用程序打包为 Chart，方便自己和团队在不同环境中部署和管理。 版本管理和升级: 使用 Helm，您可以对已安装的 Chart 进行版本管理和升级。当应用程序的配置或代码发生变化时，您可以通过升级 Chart 来自动应用这些更改，而无需手动修改和重新部署 Kubernetes 资源清单。Helm 还提供了回滚功能，允许您在升级出现问题时快速回退到之前的版本。 依赖管理: Helm 允许您在 Chart 中定义和管理依赖关系。这意味着您可以在部署应用程序时自动解析和安装它所依赖的其他 Charts。这样，您可以轻松地管理应用程序所需的其他资源，减少手动处理依赖关系的工作。 部署的一致性和标准化: Helm 提供了一种标准的部署方式，使得不同团队或开发者之间可以使用相同的工具和流程来管理应用程序的部署。这样可以确保在不同环境中的一致性，并降低由于不同部署方式导致的错误和配置差异。 可管理的 Charts: Helm Charts 是可管理的，您可以在 Chart 中定义预先配置的模板、默认值、钩子和配置验证。这使得管理应用程序的配置和部署过程更加灵活和可控。 社区支持和生态系统: Helm 是一个活跃的开源项目，拥有庞大的用户社区和丰富的生态系统。这意味着您可以轻松地找到文档、示例、教程和问题解答，并从社区中获取支持和贡献。 可扩展性和插件支持: Helm 提供了插件机制，允许您扩展 Helm 的功能。您可以使用插件来添加自定义的命令、功能和工作流程，以满足特定需求或自动化常见的任务。 可视化界面和用户友好性: Helm 可以与各种第三方工具和平台集成，提供可视化界面和用户友好的操作方式。这使得非技术人员或不熟悉命令行的开发人员也能够方便地部署和管理应用程序。 安装helm Helm 安装主要官方提供了几种安装方式</description>
    </item>
    <item>
      <title>Ceph集群安装 - ceph-deploy</title>
      <link>https://www.oomkill.com/ch02-3-install-ceph-with-ceph-deploy/</link>
      <pubDate>Mon, 18 Nov 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch02-3-install-ceph-with-ceph-deploy/</guid>
      <description>本文是Ceph集群部署系列第3章 使用cephadm纯离线安装Ceph集群 使用cephadm纯离线安装Ceph集群 2 Ceph集群安装 - ceph-deploy Ceph集群安装 - ceph-deploy下线rgw 环境配置 Ceph 是一个开源去中心化存储平台，专为满足现代存储需求而设计。 Ceph可扩展至 EB 级，并且设计为无单点故障，使其成为需要高度可用的灵活存储的应用程序的理想选择。
下图显示了具有 Ceph 存储的示例 3 节点集群的布局。 两个网络接口可用于增加带宽和冗余，这有助于保持足够的带宽来满足存储要求，而不影响客户端应用程序。
图：Ceph存储集群 Source：https://www.jamescoyle.net/how-to/1244-create-a-3-node-ceph-storage-cluster
图中架构表示了一个无单点故障的 3 节点 Ceph 集群，以提供高度冗余的存储。 每个节点都配置了两个磁盘； 一台运行 Linux 操作系统，另一台将用于 Ceph 存储。 下面的输出显示了可用的存储空间，每个主机上的存储空间完全相同。 /dev/sda 是包含操作系统安装的根分区， /dev/sdb 是一个未触及的分区，将用于部署 Ceph 集群，对应的硬件信息如下表所示。
主机名 public IP cluster IP 数据盘 ceph-nautilus01 10.0.0.50 10.0.0.50 /dev/sda
/dev/sdb ceph-nautilus02 10.0.0.51 10.0.0.51 /dev/sda/dev/sdb ceph-nautilus03 10.0.0.52 10.0.0.52 /dev/sda/dev/sdb ceph-control 10.0.0.49 10.0.0.49 /dev/sda 部署工具 ceph-deploy 工具是在 “管理节点” (ceph-admin) 上的目录中运行。</description>
    </item>
    <item>
      <title>ch1 VPN与OpenVPN应用场景分析</title>
      <link>https://www.oomkill.com/ch1-introduction/</link>
      <pubDate>Mon, 18 Nov 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch1-introduction/</guid>
      <description>什么是VPN VPN ( Virtual Private Network) 虚拟专用网络，是依靠ISP和其他的NSP，在公共网络中建立专用的数据通信网络的技术，可以为企业与企业之间或者个人与企业之间提供安全的数据传输隧道服务。在VPN中任意两点之间的连接并没有传统专网所需的端到端的物理链路，而是利用公共网络资源动态组成的，可以理解为通过私有的隧道技术在公共数据网络上模拟出来的和专网有同样功能的点到点的专线技术，所谓虚拟是指不需要去拉实际的长途物理线路，而是借用了公共Internet网络实现。
vpn直观的形象图：
VPN Server/Client &lt;---------------------------------&gt; VPN Server/ClientVPN的作用 VPN功能可以帮助公司里的远程用户(出差，家里)、公司的分支机构、商业合作伙伴及供应商等公司和自己的公司内部网络之间建立可信的安全连接或者是局域网连接，确保数据的加密安全传输和业务访问，对至运维工程师来说，还可以连接不同的机房为局域网，处理相关的业务流。我们可以通过一张网络逻辑图来描述VPN的作用。
图：OpenVPN架构Source：https://www.slideteam.net/vpn-tunnel-architecture-connecting-corporate-and-branch-office.html
VPN的分类 我们根据VPN的常见企业应用，将VPN分为以下4类应用
远程访问VPN服务 即通过个人电脑远程拨号到企业办公网络。
一般为企业内部员工出差、休假或特殊情况下在远离办公室的时候，又有需求访问公司的内部网络获取相关资源，就可以通过VPN拨号到公司内部.此时远程拨号的员工和办公室内的员工以及其他拨号的员工之间都相当于一个局域网络内。例如:访问内部的域控制器，文件服务器，OA系统，ERP, HTTP服务，内网聊天工具等局域网服务应用。
对于运维人且就是需要个人电脑远程拨号到企业网站IDC机房，远程维护内网服务器（一般无外网IP）。
此点是技术人员特别是运维人且在工作中会经常用这个方法维护大量的机房内无外网的服务器及网络设备。
企业内部网络之间VPN服务 在公司的分支机构的局域网和公司总部LAN之间的VPN连接。通过公网Internet建立VPN将公司在各地的分支机构的LAN连接到公司总部的LAN。例如:各大超市之间业务结算等。
这是由于地域的原因而产生的VPN的需求，通过VPN让不同地域内的机器可以互相访问，就好像是一个局域网一样。例如：办公室互联协同办公，机房互联数据同步及业务访问等。
互联网公司多IDC机房之间VPN服务 此处是运维架构人员需要考虑的问题。不同机房之间业务管理和业务访问，数据流动。
企业外部VPN服务 在供应商、合作伙伴的LAN和本公司的LAN之间建立的VPN服务。
访问外国网站 翻墙的应用
常贝隧道协议介绍 PPTP 点对点隧道协议(PPTP)是由包括微软和3Com等公司组成的PPTP论坛开发的一种点对点隧道协议，基于拨号使用的PPP协议，使用PAP或CHAP之类的加密算法，或者使用Microsoft的点对点加密算法MPPE。其通过跨越基于TCP/IP的数据网络创建VPN。实现了从远程客户端到专用企业服务器之间数据的安全传输。PPTP支持通过公共网络(例如Internet)建立按需的、多协议的、虚拟专用网络。PPTP允许加密IP通讯，然后在要跨越公司IP网络或公共IP网络(如Internet)发送的IP头中对其进行封装。典型的linux平台的开源软件为pptp。
PPTP属于点对点方式的应用，比较适合远程的企业用户拨号到企业进行办公等的应用。
L2TP L2TP第2层隧道协议(L2TP)是IETF基于L2F (Cisco的第二层转发协议)开发的PPTP的后续版本。是一种工业标准Internet隧道协议，其可以为跨越面向数据包的媒体发送点到点协议(PPP)框架提供封装。PPTP和L2TP都使用PPP协议对数据进行封装，然后添加附加包头用于数据在互联网络上的传输。PPTP只能在两端点间建立单一隧道。L2TP支持在两端点间使用多隧道，用户可以针对不同的服务质量创建不同的隧道。L2TP可以提供隧道验证，而PPTP则不支持隧道验证。但是当L2TP或PPTP 与 IPSEC 共同使用时，可以由IPSEC提供隧道验证，不需要在第2层协议上验证隧道使用L2TP。PPTP要求互联 网络为IP网络。L2TP只要求隧道媒介提供面向数据包的点对点的连接，L2TP可以在IP(使用UDP)，帧中继永久虚拟电路(PVCs)，X.25虚拟电路(VCs)或ATM VCs网络上使用。
L2TP (Layer 2 Tunneling Protocol)
在计算机网络中，第2层隧道协议（L2TP）是一种隧道协议，用于支持虚拟专用网络（VPN）或作为ISP提供服务的一部分。它本身不提供任何加密或机密性。相反，它依靠它在隧道内传递的加密协议来提供隐私。
由于L2TP协议缺乏固有的机密性，因此通常与IPsec一起实施。这被称为L2TP / IPsec，并在IETF RFC 3193中进行了标准化。
Reference L2TP
IPSec IP安全协议(IPSec: IP Security)实际上是一套协议包而不是一个独立的协议。从1995年开始IPSec的研究以来，IETF IPSec工作组在它的主页上发布了几十个Internet草案文献和12个RFC文件。其中，比较重要的有RFC2409 IKE(互连网密钥交换)、RFC2401 IPSec协议、RFC2402 AH验证包头、RFC2406 ESP加密数据等文件。
IPSec隧道模式隧道是封装、路由与解封装的整个过程。隧道将原始数据包隐藏(或封装)在新的数据包内部。该新的数据包可能会有新的寻址与路由信息，从而使其能够通过网络传输。隧道与数据保密性结合使用时，在网络上窃听通讯的人将无法获取原始数据包数据(以及原始的源和目标)。封装的数据包到达目的地后，会删除封装，原始数据包头用于将数据包路由到最终目的地。
隧道本身是封装数据经过的逻辑数据路径，对原始的源和目的端，隧道是不可见的，而只能看到网络路径中的点对点连接。连接双方并不关心隧道起点和终点之间的任何路由器、交换机、代理服务器或其他安全网关。将隧道和数据保密性结合使用时，可用于提供VPN。</description>
    </item>
    <item>
      <title>ch2 从零开始安装OpenVPN</title>
      <link>https://www.oomkill.com/ch2-install-and-configuration/</link>
      <pubDate>Mon, 18 Nov 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch2-install-and-configuration/</guid>
      <description>OpenVPN安装环境需求 设备 IP 笔记本或PC
(adsl上网) 10.0.0.0/24 办公室（DHCP） OpenVPN Server双网卡 eth0:10.0.0.4/24（外网）
eth1:192.168.100.4（内网） IDC机房内部局域网服务器 192.168.100.0/24
IDC机房内网服务器无外网IP，又希望ADSL上网笔记本（运维人员），在不同的网络能够直接访问 实现需求：在远端通过VPN客户端(笔记本)拨号到VPN，然后在笔记本电脑上可以直接访问vpnserver所在局域网内的多个servers，进行维护管理 环境 VPN-Server eth0:10.0.0.4(外网IP)。GW:10.0.0.1, dns:10.0.0.1。
eth1:172.0.0.1(内网IP)。GW:不配
提示：检查是否可以ping通client eth0 IP。
App client Server:ethO:172.0.0.2。GW:路由器。提示：检查是否可以ping通VPN-Server eth1 IP。 OpenVPN 解决方案图解部署OpenVPN Server Reference download lzo
installing-openvpn
openvpn offical releases
openvpn github
安装前准备
openvpn支持的平台：
Linux kernel 2.6+ OpenBSD 5.1+ Mac OS X Darwin 10.5+ FreeBSD 7.4+ Windows (WinXP and higher) 下载地址：
openvpn-releases openvpn github 安装openvpn的依赖项：
0.9.8版或更高版本的OpenSSL库，对于加密是必需的 PolarSSL库，是加密的替代版本1.1或更高版本 LZO实时压缩库，连接压缩所需 bash 1 yum install openssl-devel lzo-devel pam-devel -y bash 1 2 3 4 5 6 .</description>
    </item>
    <item>
      <title>ch3 OpenVPN的高可用配置</title>
      <link>https://www.oomkill.com/ch3-high-availability/</link>
      <pubDate>Mon, 18 Nov 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch3-high-availability/</guid>
      <description>方案1：在Vpn 客户端使用多个配置文件实现（由用户选择拨号）类 方案1：需求分析与操作过程讲解。
基本说明：
生产场景中比较规范的做法是让所有的VPN SERVER尽可能共享同一套 server，ca证书或者连接同一个认证系统（即使是跨机房）。这样只需要一份客户端认证和文件和多份指定不同vpn client的配置文件即可实现vpn的负载均衡了。
总结结论：
1）该负载均衡方案操作简单，不引入多余服务（后面的方案都会引入服务），因此不会增加多余的单点故障，当用户连接的vpn不能使用时，用户就可以人工选择拨号其他的VPN服务器。
2）如果使用者为公司内部工作人员，此种方案是值得推荐的。老男孩老师推荐。
3）从广义上讲这是在用户端实现的负载均衡方案，类似早期的华军下载站一样，由用户选择下载站点，而不是用什么智能DNS等复杂的业务模式。
缺点：当一个vpnserver不能使用时，不能自动连上别的vpn server。
方案2：通过在客户端配置文件实现负载均衡（客户端文件里随机连接服务器） 提示：同方案1，所有VPN SERVER 需要共享同一套 server，ca证书。openvpn 服务器一套keys的多份拷贝方式式。
text 1 2 3 4 remote 10.0.0.28 52115 remote 10.0.0.552115 remote-random resolv-retry 20 implementing-a-load-balancing-failover-configuration
总结结论：
1）该负载均衡方案操作简单，不引入多余服务（后面的方案都会引入服务），因此不会增加多余的单点故障，，当用户连接的vpn不能使用时，电脑可以重新再次自动拨号连接VPN服务器。
2）如果使用者为公司内部工作人员，此种方案是值得推荐的。-老男孩老师推荐。如果是使用者为外部人员，那么这个方案依然是可以的。
3）本方案是比较标准的在VPN用户端，由客户端配置参数实现的负载均衡的方案，是非常值得推荐的方案。
4）和方案1对比，方案2的配置更简单，仅需一个配置文件多个remote参数，拨号时客户端会随机自动选择拨号，方案1则需要手动选择不同的配置文件拨号。当正在连接的VPN服务端右机时，那么此时方案2不需要人工干预，客户端的VPN会自动判断并且自动重新连接其他的可用vpn服务器。.
方案3：通过域名加DNS轮询的方式实现负载均衡（由DNS自动分配vpn） 总结结论：
1）通过dns轮询实现VPN负载均衡方案操作比较复杂，引入了DNS服务，因此增加了单点故障及维护成本，当用户连接的vpn不能使用时，用户也需要重新人工再次拨号。
2）如果使用者为公司内部工作人员，此种方案是不推荐的。如果是外部的用户可以考虑用这种方式，但是复杂度比方案1大了很多（如果存在DNS服务器加配置还可以）。
3）当机房多，配置文件多时，无需用户选择服务器，只需拨号即可。如果多个VPN在一个机房还好一些，如果多个VPN服务器不在一个机房，还需要通过IPSEC进行连接。 总之，此法很麻烦，中小型公司老男孩老师极不推荐。
4）DNS轮询会遭遇到客户端DNS缓存问题，从而导致服务切换失效。。
one-network-interface-on-a-public-network</description>
    </item>
    <item>
      <title>ch4 OpenVPN的统一身份认证方案及实现方法</title>
      <link>https://www.oomkill.com/ch4-authentication/</link>
      <pubDate>Mon, 18 Nov 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch4-authentication/</guid>
      <description>OpenVPN 2.0与更高版本允许OpenVPN服务器从客户端安全地获取用户名和密码，并将该信息用作认证基础。
方法1：通过本地证书密钥认证。 默认不配置，openvpn即使用证书进行身份认证。
（1）编辑主服务器配置文件/etc/openldap/slapd.conf，取消如下行的注释：
方法2：本地文件认证 在使用身份验证时，需要将 auth-user-pass 指令添加到客户端配置文件中，设置后OpenVPN客户端向用户索要用户名/密码，并将其通过安全的TLS通道传递给服务器进行验证。
服务端配置文件需要增加配置指令 auth-user-pass-verify auth-pam.pl via-file 使用脚本插件。auth-pam.pl 在源码包 sample/sample-script 路径下。
text 1 plugin /usr/share/openvpn/plugin/lib/openvpn-auth-pam.so login 生产环境下官方推荐使用 openvpn-auth-pam 插件进行验证，相比于 auth-pam.pl，openvpn-auth-pam 插件具有多个优点：
openvpn-auth-pam 使用拆分权限执行模型来提高安全性。 C编译的插件比脚本运行速度更快。 OpenVPN可以通过虚拟内存（而不是通过文件或环境）将用户名/密码传递给插件，这对于服务器上的本地安全性更好。 获取openvpn-auth-pam插件 openvpn-auth-pam插件在openvpn代码目录src/plugins/auth-pam 下，运行 make &amp;amp;&amp;amp; make install 进行安装，会自动复制到openvpn安装好的 lib/openvpn/plugins 目录下。
开启密码认证 默认情况下， 在服务器上使用 auth-user-pass-verify 或用户名/密码 插件 将启用双重身份验证，要求客户端证书和用户名/密码身份验证都必须成功，才能对客户端进行身份验证。可以选择关闭客户端证书认证。
text 1 2 client-cert-not-required username-as-common-name # 用户名作为通用名称 开启后需要在客户端注释 cert 和 key的配置
方法3：数据库认证 法2：利用的脚本程序（shell，php等）本地文件去读数据库。
法1：用pam_mysql
方法:4：ldap统一用户认证 openvpn-auth-ldap 利用第一个文件认证的思路，去LDAP查询，还可以和本地文件比较。如 ldap认证原理图配置openvpn服务端通过ldap进行身份验证 配置OpenVPN基 LDAP的身份验证，需要安装用于LDAP身份验证的OpenVPN插件。openvpn-auth-ldap，它通过LDAP为OpenVPN实现身份认证。
CentOS中 openvpn-auth-ldap 插件在EPEL中 ubuntu与Centos都可以通过对应的包管理工具进行插件安装。</description>
    </item>
    <item>
      <title>kubernetes应用 - Traefik Ingress Controller</title>
      <link>https://www.oomkill.com/traefik-ingresscontroller/</link>
      <pubDate>Wed, 23 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/traefik-ingresscontroller/</guid>
      <description>Kubernetes Ingress Kubernetes Ingress是路由规则的集合，这些规则控制外部用户如何访问Kubernetes集群中运行的服务。
在Kubernetes中，有三种方式可以使内部Pod公开访问。
NodePort：使用Kubernetes Pod的NodePort，将Pod内应用程序公开到每个节点上的端口上。 Service LoadBalancer：使用Kubernetes Service，改功能会创建一个外部负载均衡器，使流量转向集群中的Kubernetes Pod。 Ingress Controller： Node Port是在Kubernetes集群中每个节点（Node）上开放端口，Kubernetes直接将流量转向集群中Pod。Kubernetes集群中使用NodePort，则需要编辑防火墙规则，但是NodePort是范围在Kubernetes集群中默认设置的范围为 30000–32767，最终导致流量端口暴露在非标准端口之上。
LoadBalancer一般应用于云厂商提供的Kubernetes服务，如果自行在机器上部署Kubernetes集群，则需要自行配置LoadBalancer的实现，
Kubernetes Ingress，为Kubernetes中的抽象概念，实现为第三方代理实现，这种三方实现集合统称为Ingress Controller。Ingress Controller负责引入外部流量并将流量处理并转向对应的服务。
Kubernetes IngressController功能实现 上面只是说道，在Kubernetes集群中，如何将外部流量引入到Kubernetes集群服务中。
负载均衡 无论在Kubernetes集群中，无论采用什么方式进行流量引入，都需要在外部负载均衡完成，而后负载均衡将流量引入Kubernetes集群入口或内部中，
通常情况下，NodePort方式管理繁琐，一般不用于生产环境。
服务的Ingress选择 Kubernetes Ingress是选择正确的方法来管理引入外部流量到服务内部。一般选择也是具有多样性的。
Nginx Ingress Controller，Kubernetes默认推荐的Ingress，弊端①最终配置加载依赖config reload，②定制化开发较难，配置基本来源于config file。 Envoy &amp;amp; traefik api网关，支持tcp/udp/grpc/ws等多协议，支持流量控制，可观测性，多配置提供者。 云厂商提供的Ingress。AWS ALB，GCP GLBG/GCE，Azure AGIC Traefik介绍 traefik-现代反向代理，也可称为现代边缘路由；traefik原声兼容主流集群，Kubernetes，Docker，AWS等。官方的定位traefik是一个让开发人员将时间花费在系统研发与部署功能上，而非配置和维护。并且traefik官方也提供自己的服务网格解决方案
作为一个 modern edge router ，traefik拥有与envoy相似的特性
基于go语言研发，目的是为了简化开发人员的配置和维护 tcp/udp支持 http L7支持 GRPC支持 服务发现和动态配置 front/ edge prory支持 可观测性 流量管理 &amp;hellip; traefik 术语 要了解trafik，首先需要先了解一下 有关trafik中的一些术语。
EntryPoints 入口点，是可以被下游客户端连接的命名网络位置，类似于envoy 的listener和nginx的listen services 服务，负载均衡，上游主机接收来自traefik的连接和请求并返回响应。 类似于nginx upstream envoy的clusters Providers 提供者，提供配置文件的后端，如file，kubernetes，consul，redis，etcd等，可使traefik自动更新 routers 路由器，承上启下，分析请求，将下游主机的请求处理转入到services middlewares: 中间件，在将下游主机的请求转入到services时进行的流量调整 在Kubernetes中使用traefik网关作为Ingress Traefik于2019年9月发布2.</description>
    </item>
    <item>
      <title>centos安装powershell和powercli</title>
      <link>https://www.oomkill.com/centos-install-powershellpowercli/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/centos-install-powershellpowercli/</guid>
      <description>poershell github
本次采用github下载对应的rpm进行安装
windows下安装方法
离线安装包下载地址
text 1 yum install -y https://github.com/PowerShell/PowerShell/releases/download/v7.0.0/powershell-lts-7.0.0-1.rhel.7.x86_64.rpm 安装完成后再终端输入以下命令 pwsh。在一个PowerShell会话，您可以通过运行以下命令来检查的PowerShell的版本。
text 1 2 3 4 5 6 7 PS /root&amp;gt; $PSVersionTable.PSVersion Major Minor Patch PreReleaseLabel BuildLabel ----- ----- ----- --------------- ---------- 7 0 0 Set-PSRepository -Name &amp;#34;PSGallery&amp;#34; -InstallationPolicy &amp;#34;Trusted&amp;#34; 接下来，运行以下命令来安装VMware.PowerCLI模块。这将发现和在PSGallery安装最新版本的模块
text 1 Find-Module &amp;#34;VMware.PowerCLI&amp;#34; | Install-Module -Scope &amp;#34;CurrentUser&amp;#34; -AllowClobber 完成后，通过运行以下命令进行检查，以确保该模块安装。
text 1 2 3 4 5 6 7 8 9 10 11 12 13 Get-Module &amp;#34;VMware.PowerCLI&amp;#34; -ListAvailable | FT -Autosize PS /root&amp;gt; Get-Module &amp;#34;VMware.</description>
    </item>
    <item>
      <title>Go mod</title>
      <link>https://www.oomkill.com/go-mod/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-mod/</guid>
      <description>自从Go官方推出 1.11 之后，增加新的依赖管理模块并且更加易于管理项目中所需要的模块。模块是存储在文件树中的 Go 包的集合，其根目录中包含 go.mod 文件。 go.mod 文件定义了模块的模块路径，它也是用于根目录的导入路径，以及它的依赖性要求。每个依赖性要求都被写为模块路径和特定语义版本。
从 Go 1.11 开始，Go 允许在 $GOPATH/src 外的任何目录下使用 go.mod 创建项目。在 $GOPATH/src 中，为了兼容性，Go 命令仍然在旧的 GOPATH 模式下运行。从 ==Go 1.13== 开始，模块模式将成为默认模式。
使用模块开发 Go 代码时出现的一系列常见操作：
创建一个新模块。 添加依赖项。 升级依赖项。 删除未使用的依赖项。 要使用go module,首先要设置 ==GO111MODULE=on== ,如果没设置，执行命令的时候会有提示。
==GO111MODULE== 的取值为 off, on, or auto (默认值，因此前面例子里需要注意2个重点)。
off: GOPATH mode，查找vendor和GOPATH目录 on：module-aware mode，使用 go module，忽略GOPATH目录 auto：如果当前目录不在$GOPATH 并且 当前目录（或者父目录）下有go.mod文件，则使用GO111MODULE， 否则仍旧使用 GOPATH mode。 sh 1 2 export GO111MODULE=on export GOPROXY=https://goproxy.io ## 设置代理 go mod 参数说明 commond 说明 download download modules to local cache (下载依赖的module到本地cache)) edit edit go.</description>
    </item>
    <item>
      <title>go net/http使用</title>
      <link>https://www.oomkill.com/go-net/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-net/</guid>
      <description>Go语言标准库内建提供了net/http包，涵盖了HTTP客户端和服务端的具体实现。使用net/http包，我们可以很方便地编写HTTP客户端或服务端的程序。
http服务端的创建流程 在使用http/net包创建服务端只需要两个步骤 绑定处理器函数 func(ResponseWriter, *Request)与 启用监听 http.ListenAndServe。
go 1 2 3 4 5 6 7 8 9 10 package main import &amp;#34;net/http&amp;#34; func main() { http.HandleFunc(&amp;#34;/&amp;#34;, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(&amp;#34;123&amp;#34;)) }) http.ListenAndServe(&amp;#34;:8080&amp;#34;, nil) } 通过分析net/http包中server.go 在执行创建http服务端主要执行了下面几个步骤：
http.HandleFunc 绑定处理函数 所有的操作的方法都属于一个结构体 ServeMux m: 用户传入的路由和处理方法的映射表，路由和处理函数被定义为结构体muxEntry的属性 mu： 实例化出来的对象的读写锁 调用DefaultServeMux.Handle() 在DefaultServeMux.Handle()中调用DefaultServeMux.HandleFunc(pattern, handler) 在将传入http.HandleFunc()的回调函数，与路由的映射信息，放到该DefaultServeMux的属性中 映射map中 muxEntry http.ListenAndServe 启动服务监听 实例化一个server结构体 调用 ListenAndServe() ListenAndServe()中 net.Listen(&amp;quot;tcp&amp;quot;, addr) 启动tcp服务监听 Serve()中 appcet()处理用户连接，go c.serve(connCtx) 处理业务段（如判断信息，拼接http、找到对应处理函数） 综上所述，net/http server.go 一切的基础为ServeMux 和 Handler</description>
    </item>
    <item>
      <title>Go socket TCP协议实现</title>
      <link>https://www.oomkill.com/go-tcp-in-go/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-tcp-in-go/</guid>
      <description>在TCP/IP协议中，“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。“IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识，那么这两个socket组成的socket pair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。
常用的Socket类型有两种：流式Socket（SOCK_STREAM）和数据报式Socket（SOCK_DGRAM）。流式是一种面向连接的Socket，针对于面向连接的TCP服务应用；数据报式Socket是一种无连接的Socket，对应于无连接的UDP服务应用。
套接字通讯原理示意
TCP的C/S架构 在整个通信过程中，服务器端有两个socket参与进来，但用于通信的只有conn这个socket。它是由 listener创建的。隶属于服务器端。客户端有一个socket参与进来。
net.Listen() 建立一个用于连接监听的套接字 listen.Accept() // 阻塞监听客户端连接请求，成功用于连接，返回用于通信的socket net.Dial() 客户端向服务端发起连接建立一个socket连接
并发的C/S模型通信 Server Accept()函数的作用是等待客户端的链接，如果客户端没有链接，该方法会阻塞。如果有客户端链接，那么该方法返回一个Socket负责与客户端进行通信。所以，每来一个客户端，该方法就应该返回一个Socket与其通信，因此，可以使用一个死循环，将Accept()调用过程包裹起来。
需要注意，实现并发处理多个客户端数据的服务器，就需要针对每一个客户端连接，单独产生一个Socket，并创建一个单独的goroutine与之完成通信。
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;net&amp;#34; &amp;#34;strings&amp;#34; ) func handleConnect(conn net.</description>
    </item>
    <item>
      <title>Go 函数 function</title>
      <link>https://www.oomkill.com/go-function/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-function/</guid>
      <description>golang保留的函数 init(), main()是golang的保留函数，有如下特点：
main() 只能用在main包中，仅可定义一个，init() 可定义任意包，可重复定义，建议只定义一个 两个函数定义时不能有任何返回值 只能由go自动调用，不可被引用 init() 先于 main() 执行，并不能被其他函数调用，执行时按照main import顺序执行。 包的执行顺序 Go的初始化和执行总是从main.main函数（main包导入其它的包） 同包下的不同 .go 文件，按照以文件名或包路径名的字符串顺序“从小到大”排序顺序执行 其他的包只有被main包 import 才会执行，按照 import 的先后顺序执行; 如果某个包被多次导入的话，在执行的时候只会导入一次; 当一个包被导入时，如果它还导入了其它的包，则先将其它的包包含进来; 导入顺序与初始化顺序相反 main =&amp;gt; p1 =&amp;gt; p2 | p2 =&amp;gt; p1 =&amp;gt; p main被最后一个初始化，因其总是依赖其他包 函数 函数是将具有独立功能的代码组织成为一个整体，使其具有特殊功能的代码集。在Go语言中，函数是一种数据类型，其特性有如下：
支持匿名函数 支持带有变量名的返回值 支持多值返回 支持匿名函数 不支持重载，一个包中不能有两个名字一样的函数。 定义语法
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 func test(){ } func test(a int, b int){ } func test(a,b int){ } func test(a,b int list.</description>
    </item>
    <item>
      <title>Go 数据结构</title>
      <link>https://www.oomkill.com/go-datastruct/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-datastruct/</guid>
      <description>Go语言将数据类型分为四类：基础类型、复合类型、引用类型和接口类型。
基础数据类型包括：
基础类型： - 布尔型、整型、浮点型、复数型、字符型、字符串型、错误类型。 复合数据类型包括： - 指针、数组、切片、字典、通道、结构体、接口。 基础数据类型 布尔值和布尔表达式 布尔类型的变量取值结果要么是真，要么是假，用bool关键字进行定义
布尔类型默认值为 false
指定格式的输出 %t
语法 描述/结果 !b 逻辑非操作符 b值为true 则 操作结果为false a || b 短路逻辑或，只要布尔值 a b 中任何一个为true表达式结果都为true a &amp;amp;&amp;amp; b 短路逻辑与，两个表达式a b都为true，则整个表达式结果为true x &amp;gt; y 表达式x的值小于表达式Y的值，则表达式的结果为true 数值类型 go语言提供了大内置的数值类型，标准库也提供了big.Int类型的整数，和big.Rat类型的有理数，这些都是大小不限（只限于机器内存）
整型 GO语言提供了11种整型，包含5种有符号，和5种无符号的与一种用于存储指针的整数类型。Go语言允许使用byte来作为无符号uint8类型的同义词，在使用单个字符时提倡使用rune来替代 int32
类型 存储空间 取值范围 byte 8-bit 同uint8 int 系统决定 依赖不通平台实现，32位操作系统为int32的值范围，64位操作系统为int64的值范围 int8 8-bit [-128, 127] ，表示 UTF-8 字符串的单个字节的值，对应 ASCII 码的字符值 int16 16-bit [-32678, 32767] int32 32-bit [2147483648, 2147483647] int64 64-bit [-9223372036854775808 , 9223372036854775807] rune 32-bit 同uint32，表示 单个 Unicode 字符 uint 系统决定 依赖不通平台下的实现，可以是uint32或uint64 uint8 8-bit uint16 16-bit [0, 65535] uint32 32-bit [0, 4294967295] uint64 64-bit [0, 18446744073709551615] uintptr 系统决定 一个可以恰好容纳指针值得无符号整数类型（32位操作系统为uint32的值范围，64位系统为uint64的值范围） 浮点类型 Go语言提供了两种类型的浮点类型和两种类型的复数类型，</description>
    </item>
    <item>
      <title>Go 运算符</title>
      <link>https://www.oomkill.com/go-arithmetic/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-arithmetic/</guid>
      <description>算术运算符 运算符 示例 结果 + 10 + 5 15 - 10 - 5 5 * （除数不能为0） 10 * 5 50 / 10 / 5 2 % （除数不能为0） 10 % 3 1 ++ a = 0; a++ a = 1 &amp;ndash; a = 2; a&amp;ndash; a = 1 总结
除法/取余运算除数不能为0 只有后自增/减，没有前自增/减。没有 ++a 或 --a 只有 a++ 或 a-- 输入半径，计算圆的面积和周长并打印出来（PI为3.14）
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 package main import &amp;#34;fmt&amp;#34; func main() { const PI = 3.</description>
    </item>
    <item>
      <title>Go每日一库 - 时间格式化</title>
      <link>https://www.oomkill.com/golib-timeformat/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/golib-timeformat/</guid>
      <description>该文可以快速在Go语言中获得时间的计算。
在Go中获取时间 如何获取当前时间 go 1 2 3 4 now := time.Now() fmt.Printf(&amp;#34;current time is :%s&amp;#34;, now) current time is :2009-11-10 23:00:00 +0000 UTC m=+0.000000001 如何获取UNIX Timestamp go 1 2 cur_time := time.Now().Unix() fmt.Printf(&amp;#34;current unix timestamp is :%v\n&amp;#34;, cur_time ) 如何获取当日0:00:00 0:00:00 go 1 2 3 4 5 now := time.Now() date := time.Date(now.Year(), now.Month(), now.Day(),0, 0, 0, 0, time.Local) fmt.Printf(&amp;#34;date is :%s&amp;#34;, date) date is :2021-04-13 00:00:00 +0800 如何获取时区时间 标准时间 time.</description>
    </item>
    <item>
      <title>Go每日一库 - 使用go操作dbus</title>
      <link>https://www.oomkill.com/golib-gobus/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/golib-gobus/</guid>
      <description>github https://github.com/godbus/dbus
增加一个端口
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package main import ( &amp;#34;github.com/godbus/dbus/v5&amp;#34; ) func main() { cli, err := dbus.SystemBus() if err != nil { panic(err) } obj := cli.Object(&amp;#34;org.fedoraproject.FirewallD1&amp;#34;, &amp;#34;/org/fedoraproject/FirewallD1&amp;#34;) call := obj.Call(&amp;#34;oorg.fedoraproject.FirewallD1.zone.addPort&amp;#34;, 0, &amp;#34;public&amp;#34;, &amp;#34;81&amp;#34;, &amp;#34;tcp&amp;#34;, &amp;#34;30000&amp;#34;) if call.Err != nil { panic(call.Err) } } go-dbus 简单教程 https://blog.csdn.net/mathmonkey/article/details/38095289</description>
    </item>
    <item>
      <title>Go面向对象</title>
      <link>https://www.oomkill.com/go-object/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-object/</guid>
      <description>所谓的面向对象其实就是找一个专门做这个事的人来做，不用关心具体怎么实现的。所以说，面向过程强调的是过程，步骤。而面向对象强调的是对象，也就是干事的人。
Go语言：面向对象语言特性 方法
嵌入
接口
没有类
支持类型。 特别是， 它支持structs。 Structs是用户定义的类型。 Struct类型(含方法)提供类似于其它语言中类的服务。
Structs 一个struct定义一个状态。 这里有一个strudent struct。 它有一个Name属性和一个布尔类型的标志Real，告诉我们它是一个真实的strudent还是一个虚构的strudent。 Structs只保存状态，不保存行为。
go 1 2 3 4 type Creature struct { Name string Real bool } 为结构体添加方法 方法是对特定类型进行操作的函数。 它们有一个接收器条款，命令它们对什么样的类型可进行操作。 这里是一个Hello()方法，它可对student结构进行操作，并打印出它们的状态：
go 1 2 3 func (s Student) Hello() { fmt.Printf(&amp;#34;Name: &amp;#39;%s&amp;#39;, Real: %t\n&amp;#34;, s.Name, s.Real) } func (s Student) func_name(){} 这是一个不太常见的语法，但是它非常的具体和清晰，不像this的隐喻性。
一般在定义方法时，需要定义为结构体的指针，值类型的在修改结构体属性时，无法修改其内容
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package main import &amp;#34;fmt&amp;#34; type human struct { Name string Real bool } type Student struct { human Id int } func (h human) Hello() { fmt.</description>
    </item>
    <item>
      <title>Go协程安全</title>
      <link>https://www.oomkill.com/go-goroutine-security/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-goroutine-security/</guid>
      <description>多路复用 Go语言中提供了一个关键字select，通过select可以监听channel上的数据流动。select的用法与switch语法类似，由select开始一个新的选择块，每个选择条件由case语句来描述。只不过，select的case有比较多的限制，其中最大的一条限制就是每个case语句里必须是一个IO操作。
select 语法如下：
go 1 2 3 4 5 6 7 8 select { case &amp;lt;-chan1: // 如果chan1成功读到数据，则进行该case处理语句 case chan2 &amp;lt;- 1: // 如果成功向chan2写入数据，则进行该case处理语句 default: // 如果上面都没有成功，则进入default处理流程 } 在一个select语句中，会按顺序从头至尾评估每一个发送和接收的语句；如果其中的任意一语句可以继续执行(即没有被阻塞)，那么就从那些可以执行的语句中任意选择一条来使用。如果没有任意一条语句可以执行(即所有的通道都被阻塞)，那么有两种可能的情况：⑴ 如果给出了default语句，那么就会执行default语句，同时程序的执行会从select语句后的语句中恢复。⑵ 如果没有default语句，那么select语句将被阻塞，直到至少有一个channel可以进行下去。
在一般的业务场景下，select不会用default，当监听的流中再没有数据，IO操作就 会阻塞现象，如果使用了default，此时可以出让CPU时间片。如果使用了default 就形成了非阻塞状态，形成了忙轮训，会占用CPU、系统资源。
阻塞与非阻塞使用场景
阻塞： 如：在监听超时退出时，如果100秒内无操作，择退出，此时添加了default会形成忙轮训，超时监听变成了无效。 非阻塞： 如，在一个只有一个业务逻辑处理时，主进程控制进程的退出。此时可以使用default。 定时器 Go语言中定时器的使用有三个方法
time.Sleep() time.NewTimer() 返回一个时间的管道， time.C 读取管道的内容 time.After(5 * time.Second) 封装了time.NewTimer()，反回了一个 time.C的管道 示例
go 1 2 3 select { case &amp;lt;-time.After(time.Second * 10): } 锁和条件变量 Go语言中为了解决协程间同步问题，提供了标准库代码，包sync和sync/atomic中。
互斥锁 互斥锁是传统并发编程对共享资源进行访问控制的主要手段，它由标准库sync中的Mutex结构体类型表示。sync.Mutex类型只有两个公开的指针方法，Lock和Unlock。Lock锁定当前的共享资源，Unlock进行解锁。
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;runtime&amp;#34; &amp;#34;sync&amp;#34; &amp;#34;time&amp;#34; ) var mutex sync.</description>
    </item>
    <item>
      <title>Go协程通讯</title>
      <link>https://www.oomkill.com/go-goroutine-communication/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-goroutine-communication/</guid>
      <description>channel是Go语言中的一个核心数据类型，channel是一个数据类型，主要用来解决协程的同步问题以及协程之间数据共享（数据传递）的问题。在并发核心单元通过它就可以发送或者接收数据进行通讯，这在一定程度上又进一步降低了编程的难度。
goroutine运行在相同的内存地址空间，channel可以避开所有内存共享导致的坑；通道的通信方式保证了同步性。数据通过channel：同一时间只有一个协程可以访问数据：所以不会出现数据竞争，确保并发安全。
channel的定义 channel是对应make创建的底层数据结构的引用。 创建语法： make(chan Type, capacity)
go 1 2 3 4 5 6 7 channel := make(chan bool) //创建一个无缓冲的bool型Channel ，等价于make(chan Type, 0) channel := make(chan bool, 1024) //创建一个有缓冲，切缓冲区为1024的bool型Channel channel &amp;lt;- x //向一个Channel发送一个值 &amp;lt;- channel //从一个Channel中接收一个值 x = &amp;lt;- channel //从Channel c接收一个值并将其存储到x中 x, ok = &amp;lt;- channel //从Channel接收一个值，如果channel关闭了或没有数据，那么ok将被置为false channel是一个引用类型，当复制一个channel或用于函数参数传递时，我们只是拷贝了一个channel引用，因此调用者和被调用者将引用同一个channel对象。和其它的引用类型一样，channel的零值（定义未初始化）也是nil。
在默认情况下，channel接收和发送数据都是阻塞的，（channel &amp;lt;- 1，写端写数据，读端不在读。写端阻塞； str := &amp;lt;-channel 读端读数据， 同时写端不在写，读端阻塞。）除非另一端已经准备好，这样就使得goroutine同步变的更加的简单，而不需要显式的lock。
示例
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;runtime&amp;#34; &amp;#34;time&amp;#34; ) var c = make(chan int32) func printstr(s string) { for _, value := range s { fmt.</description>
    </item>
    <item>
      <title>go语言的并发编程gorouting</title>
      <link>https://www.oomkill.com/go-goroutine/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-goroutine/</guid>
      <description>并行和并发 并发编程是指在一台处理器上“同时”处理多个任务。
宏观并发：在一段时间内，有多个程序在同时运行。
微观并发：在同一时刻只能有一条指令执行，但多个程序指令被快速的轮换执行，使得在宏观上具有多个进程同时执行的效果，但在微观上并不是同时执行的，只是把时间分成若干段，使多个程序快速交替的执行。
并行 parallel：同一时刻，多条指令在多个处理器上同时执行。
并发 concurrency：在同一时刻只能有一条指令执行，但多个进程指令被快速的轮换执行，使得在宏观上具有多个进程同时执行的效果，但在微观上并不是同时执行的，只是把时间分成若干段，通过cpu时间片轮转使多个进程快速交替的执行。
通俗来讲，并行是两组队列同时使用一个进程；并发是两个队列分别交替使用两个进程
进程并发 程序，以Go语言为例，是指编译好的二进制文件，在磁盘上，不占用系统资源(cpu、内存、打开的文件、设备、锁&amp;hellip;.)
进程，是一个抽象的概念，与操作系统原理联系紧密。以Go语言为例，将编译好的程序运行起来，在内存空间中形成一个独立的内存体，内存体有自己的独立空间，上级挂靠单位是操作系统。
进程是操作系统进行资源分配和调度的一个独立单位，一般由程序，数据集合和进程控制块三部分组成。
程序：描述进程完成的功能，是控制进程执行的指令集； 数据集合：程序在执行时所需要的数据和工作区； 程序控制块PCB：Program Control Block，包含进程的描述信息和控制信息，是进程存在的唯一标志。 进程是活跃的程序，占用系统资源。在内存中执行。同一个程序也可以加载为不同的进程(彼此之间互不影响)
进程状态 进程基本的状态有5种。分别为初始态，就绪态，运行态，挂起态与终止态。其中初始态为进程准备阶段，常与就绪态结合来看。
线程的任务调度 大部分操作系统的任务调度是采用时间片轮转的抢占式调度方式。
时间片轮转是指，在一个进程中，当线程任务执行几毫秒后，由操作系统内核进行调度，通过硬件计数器终端处理器，让线程强行暂停，并将该线程的寄存器放入内存中，通过查看线程列表决定接下来执行哪一个线程，并从内存中恢复该线程的寄存器，最后恢复该线程的执行，从而去执行下一个任务。
在时间片轮转中，任务执行那段时间叫做时间片，任务正在执行时的状态叫运行状态，被暂停的线程任务状态叫做就绪状态，意为等待下一个属于它的时间片的到来。
由于CPU的执行效率非常高，（i5 6600 约200亿/秒，奔腾4 约13亿/秒）CPU preformance 时间片非常短，在各个任务之间快速地切换，给人的感觉就是多个任务在“同时进行”，这也就是我们所说的并发。多任务运行过程的示意图如下：
进程实现并发时会出现的问题呢 孤儿进程: 父进程先于子进程结束，则子进程成为孤儿进程，子进程的父进程成为init进程，称为init进程领养孤儿进程。
僵尸进程: 进程终止，父进程尚未回收，子进程残留资源（PCB）存放于内核中，变成僵尸（Zombie）进程。
线程并发 在早期操作系统当中，没有线程的概念，进程是最小分配资源与执行单位，可以看做是一个进程中只有一个线程，故进程即线程。所以线程LWP被称为：：Lightweight process，轻量级的进程，是程序执行中一个单一的顺序控制流程，在Linux操作系统下，线程的本质仍是进程。
线程有独立的PCB，但没有独立的地址空间，各个线程之间共享程序的内存空间。
进程和线程的区别 进程：最小分配资源单位，可看成是只有一个线程的进程。 线程：最小的执行单位 一个进程由一个或多个线程组成 进程之间相互独立，同一进程下的各个线程之间共享程序的内存空间 协程并发 协程 coroutines，是一种基于线程之上，但又比线程更加轻量级的存在，这种由程序来管理的轻量级线程叫做『用户空间线程』，具有对内核来说不可见的特性。
多数语言在语法层面并不直接支持协程，而是通过库的方式支持，但用库的方式支持的功能也并不完整，比如仅仅提供协程的创建、销毁与切换等能力。如果在这样的轻量级线程中调用一个同步 IO 操作，比如网络通信、本地文件读写，都会阻塞其他的并发执行轻量级线程，从而无法真正达到轻量级线程本身期望达到的目标。
协程和线程的区别 占用资源：线程，初始单位为1MB,固定不可变；协程初始一般为 2KB，可随需要而增大。 调度：线程，由操作系统内核完成，协程，由用户完成。 性能： 线程，占用资源高，频繁创建销毁带来性能问题。占用资源小，不会带来严重的性能问题。 数据： 线程，多线程需要锁机制确保数据一致性和可见性；而线程因为只有一个进程，不存在同时读/写冲突，协程中控制共享数据不用加锁，顾执行效率较线程高。 Go并发 goroutine Go语言在语言级别支持协程，叫goroutine。Go语言标准库提供的所有系统调用操作（包括所有同步IO操作），都会出让CPU给其他goroutine。这种轻量级线程的切换管理不依赖于系统的线程和进程，也不需要依赖于CPU的核心数量。
Go语言为并发编程而内置的上层API基于顺序通信进程模型CSP(communicating sequential processes)。这就意味着显式锁都是可以避免的，因为Go通过相对安全的通道发送和接受数据以实现同步，这大大地简化了并发程序的编写。
Go语言中的并发程序主要使用两种手段来实现。goroutine和channel。
什么是goroutine Go语言作者Rob Pike说， “Goroutine是一个与其他goroutines并发运行在同一地址空间的Go函数或方法。一个运行的程序由一个或更多个goroutine组成。它与线程、协程、进程等不同。它是一个goroutine*。</description>
    </item>
    <item>
      <title>Go语言数据类型转换</title>
      <link>https://www.oomkill.com/goskill-golang-type-convert/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/goskill-golang-type-convert/</guid>
      <description>string in mutual conversion go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // int to int64 m := int64(n) // int64 to int n := int(m) // string to int int,err := strconv.Atoi(string) // string to int64 int64, err := strconv.ParseInt(string, 10, 64) // int to string string := strconv.</description>
    </item>
    <item>
      <title>Go中的signal处理</title>
      <link>https://www.oomkill.com/go-signal/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-signal/</guid>
      <description>什么是信号 在计算机科学中，信号是Unix、类Unix以及其他POSIX兼容的操作系统中进程间通讯的一种有限制的方式。它是一种异步的通知机制，用来提醒进程一个事件已经发生。
当一个信号发送给一个进程，操作系统中断了进程正常的控制流程，如果进程定义了对信号的处理，此时，程序将进入捕获到的信号对应的处理函数，否则执行默认的处理函数。
Linux中信号的介绍 在Linux系统共定义了64种信号，分为两大类：实时信号与非实时信号，1-31为非实时，32-64种为实时信号。
非实时信号： 也称为不可靠信号，为早期Linux所支持的信号，不支持排队，信号可能会丢失, 比如发送多次相同的信号, 进程只能收到一次. 信号值取值区间为1~31； 实时信号： 也称为可靠信号，支持排队, 信号不会丢失, 发多少次, 就可以收到多少次. 信号值取值区间为32~64 Linux操作系统中，在终端上执行 kill -l 便可看到系统定义的所有信号
信号表 POSIX.1-1990标准信号 此表参考自：POSIX信号
信号 值 动作 说明 SIGHUP 1 Term 终端控制进程结束(终端连接断开) SIGINT 2 Term 用户发送INTR字符(Ctrl+C)触发 SIGQUIT 3 Core 用户发送QUIT字符(Ctrl+/)触发 SIGILL 4 Core 非法指令(程序错误、试图执行数据段、栈溢出等) SIGABRT 6 Core 调用abort函数触发 SIGFPE 8 Core 算术运行错误(浮点运算错误、除数为零等) SIGKILL 9 Term 无条件结束程序(不能被捕获、阻塞或忽略) SIGSEGV 11 Core 无效内存引用(试图访问不属于自己的内存空间、对只读内存空间进行写操作) SIGPIPE 13 Term 消息管道损坏(FIFO/Socket通信时，管道未打开而进行写操作) SIGALRM 14 Term 时钟定时信号 SIGTERM 15 Term 结束程序(可以被捕获、阻塞或忽略) SIGUSR1 30,10,16 Term 用户保留 SIGUSR2 31,12,17 Term 用户保留 SIGCHLD 20,17,18 Ign 子进程结束(由父进程接收) SIGCONT 19,18,25 Cont 继续执行已经停止的进程(不能被阻塞) SIGSTOP 17,19,23 Stop 停止进程(不能被捕获、阻塞或忽略) SIGTSTP 18,20,24 Stop 停止进程(可以被捕获、阻塞或忽略) SIGTTIN 21,21,26 Stop 后台程序从终端中读取数据时触发 SIGTTOU 22,22,27 Stop 后台程序向终端中写数据时触发 更多的信号说明请查阅man7</description>
    </item>
    <item>
      <title>jenkins pipline demo</title>
      <link>https://www.oomkill.com/jenkins-pipline-demo/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/jenkins-pipline-demo/</guid>
      <description>pipline demo https://jenkins.io/zh/doc/book/pipeline/syntax/ git 插件 https://jenkins.io/doc/pipeline/steps/git/ pipline pipeline{agent anystages{stage(&amp;#34;build&amp;#34;){steps{echo &amp;#34;11111&amp;#34;}}}} pipeline总体介绍 基本结构
以下每一个部分都是必须的，少一个Jenkins都会报错
pipline pipeline{agent anystages{stage(&amp;#34;build&amp;#34;){steps{echo &amp;#34;hellp&amp;#34;}}}} pipeline 代表整个流水线，包含整条流水线的逻辑 stage 阶段，代表流水线的阶段，每个阶段都必须有名称。 stages 流水线中多个stage的容器，stages部分至少包含一个stage. steps 代表stage中的一个活多个具体步骤的容器，steps部分至少包含一个步骤 agent 制定流水线的执行位置，流水线中每个阶段都必须在某个地方执行（master节点/slave节点/物理机/虚拟机/docker容器），agent部分指定具体在哪里执行。agent { label &#39;***-slave&#39;} 可选步骤
post 包含的是在整个pipeline或stage完成后的附件条件
always 论Pipeline运行的完成状态如何都会执行这段代码 changes 只有当前Pipeline运行的状态与先前完成的Pipeline的状态不同时，才能触发运行。 failure 当前状态为失败时执行 success 当前完成状态为成功时执行 demo
使用${test}，可以引入自定义变量
pipeline post {always {script {allure includeProperties: false, jdk: &amp;#39;&amp;#39;,report: &amp;#39;jenkins-allure-report&amp;#39;, results: [[path: &amp;#39;allure-results&amp;#39;]] }}failure {script {if (gitpuller == &amp;#39;noerr&amp;#39;) {mail to: &amp;#34;${email_list}&amp;#34;,subject: &amp;#34;[jenkins Build Notification] ${JOB_NAME} - Build # ${BUILD_NUMBER} 构建失败&amp;#34;,body: &amp;#34;&amp;#39;${env.</description>
    </item>
    <item>
      <title>jenkins的用户授权与管理</title>
      <link>https://www.oomkill.com/jenkins-user-authentication/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/jenkins-user-authentication/</guid>
      <description>需要安装的插件 Role-Based Strategy（可以对构建的项目进行授权管理，让不同的用户管理不同的项目，将测试和生产环境分开）
选择授权策略 当Role-based Authorization Strategy 这个插件安装好之后，授权策略会多出一个Role-Based Strategy 选项，选择此项
添加配置权限 系统设置 &amp;raquo; Manage and Assign Roles
Manage Roles 设置全局角色（全局角色可以对jenkins系统进行设置与项目的操作）
admin:对整个jenkins都可以进行操作 root:可以对所有的job进行管理 other:只有读的权限 other必须有，否则给用户分配角色时分配没有全局role会导致分配失效 Assign Roles为用户指派角色 项目角色是根据正则匹配的，</description>
    </item>
    <item>
      <title>jenkins历史比较</title>
      <link>https://www.oomkill.com/jenkins-recode-history/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/jenkins-recode-history/</guid>
      <description>文中的代码来自可以从github下载： https://github.com/ciandcd
插件 jobConfigHistory，可以查看job配置的修改历史。
安装后重启jenkins，然后对job的配置修改后，可以点击job config history连接查看修改历史。
选择需要比较的版本，可以diff两个版本间的差别。</description>
    </item>
    <item>
      <title>jenkins在Mac OS下的迁移记录</title>
      <link>https://www.oomkill.com/jenkens-migrant-in-macos/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/jenkens-migrant-in-macos/</guid>
      <description>修改启动用户
先停止jenkins服务
sh 1 2 sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist sudo vim /Library/LaunchDaemons/org.jenkins-ci.plist 授权jenkins工作目录和临时目录
text 1 2 sudo chown -R zhulangren:wheel /Users/Shared/Jenkins/ sudo chown -R zhulangren:wheel /var/log/jenkins/ 启动jenkins
text 1 sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist jenkins自启动文件路径
text 1 /Library/LaunchDaemons/org.jenkins-ci.plist 卸载脚本文件
text 1 /Library/Application\ Support/Jenkins/Uninstall.command 修改jenkins启动端口
text 1 sudo defaults write /Library/Preferences/org.jenkins-ci httpPort &amp;#39;9999&amp;#39; 读取jenkins配置文件
text 1 defaults read /Library/Preferences/org.jenkins-ci 设置自启动
text 1 sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.plis 取消自启动
text 1 sudo launchctl unload /Library/LaunchDaemons/org.</description>
    </item>
    <item>
      <title>lua cjson使用</title>
      <link>https://www.oomkill.com/lua-cjson/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/lua-cjson/</guid>
      <description>cjson下载
https://github.com/mpx/lua-cjson.git
下载解压后，编译需要根据自己的lua环境以及操作系统修改Makefile的一些配置，不然容易出错。 以下是Makefile中的一些配置。
c 1 2 3 4 5 6 7 8 LUA_VERSION = 5.2 TARGET = cjson.so PREFIX = /usr/local CJSON_LDFLAGS = -shared LUA_INCLUDE_DIR = $(PREFIX)/include LUA_CMODULE_DIR = $(PREFIX)/lib/lua/$(LUA_VERSION) LUA_MODULE_DIR = $(PREFIX)/share/lua/$(LUA_VERSION) LUA_BIN_DIR = $(PREFIX)/bin https://blog.gezhiqiang.com/2017/08/24/lua-cjson/
lua 1 2 3 4 5 6 7 8 9 10 11 12 13 local cjson = require(&amp;#34;cjson&amp;#34;) local obj = { id = 1, name = &amp;#34;zhangsan&amp;#34;, age = nil, is_male = false, hobby = {&amp;#34;zhangsan&amp;#34;,&amp;#34;lisi&amp;#34;,&amp;#34;wangwu&amp;#34;} } local str = cjson.</description>
    </item>
    <item>
      <title>lua nginx api</title>
      <link>https://www.oomkill.com/lua-nginx-api/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/lua-nginx-api/</guid>
      <description>lua 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 location = /reqq { default_type text/plain; content_by_lua_block { ngx.req.read_body() local data = ngx.req.get_body_data() local args, err = ngx.req.get_uri_args() if not args then ngx.say(&amp;#39;post fail&amp;#39;) return end for key,v in pairs(args) do ngx.say(key,&amp;#34;::&amp;#34;,v,&amp;#34;--&amp;#34;) end ngx.say(data) } } ngx.exec 内部重定向 lua 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 location = /bb { default_type text/plain; content_by_lua_block{ ngx.</description>
    </item>
    <item>
      <title>lua nginx module</title>
      <link>https://www.oomkill.com/lua-nginx-module/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/lua-nginx-module/</guid>
      <description>lua 1 2 3 4 5 6 7 8 9 10 package1 = {} package1.const = &amp;#34;测试常量&amp;#34; function package1.func1() io.write(&amp;#34;this is public func\n&amp;#34;) end return package1 req.lua
lua 1 2 3 require &amp;#34;package1&amp;#34; package1.func1() print(package1) text 1 2 3 lc@lc-virtual-machine:~/lua$ lua pack1.lua this is public func table: 0x5575766224a0 注意事项：
测试文件是和封装好的模块在同一个目录，否则引用时需要设置路径。
lua 1 2 3 4 5 6 7 package.path = &amp;#39;/home/lc/lua/1/package1.lua;&amp;#39;; require &amp;#34;package1&amp;#34; package1.func1() print(package1) 模块名称和文件名称必须相同</description>
    </item>
    <item>
      <title>powercli The SSL connection could not be established, see inner exception. 问题解决</title>
      <link>https://www.oomkill.com/powercli-the-ssl-connection-could-not-be-established-see-inner-exception/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/powercli-the-ssl-connection-could-not-be-established-see-inner-exception/</guid>
      <description> text 1 Connect-VIServer -Server 这里是“SSL连接不能建立&amp;hellip;&amp;hellip;”这实际上意味着你没有一个有效的证书。如果你想连接到vCenter没有一个有效的证书，您必须允许可以改变你的vCenter证书到受信任的一个，这是正确的解决方案，也可以忽略无效的证书，以规避所有的安全性，但使它现在的工作。
忽略无效证书
text 1 Set-PowerCLIConfiguration -InvalidCertificateAction:ignore 再次登陆可正常登陆 </description>
    </item>
    <item>
      <title>powercli常用命令</title>
      <link>https://www.oomkill.com/powercli-vsphere-command/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/powercli-vsphere-command/</guid>
      <description>pwsh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 Connect-VIServer -Server 10.11.17.20 -User administrator@vsphere.local -Password DC02@123456 Get-OSCustomizationSpec linux1|Get-OSCustomizationNicMapping|Set-OSCustomizationNicMapping -IpMode UseStaticIP -SubnetMask 255.255.255.0 -DefaultGateway 10.10.12.254 -IpAddress 10.10.12.114 new-VM -Name zy-ntw-prod-dbvm-pushredis01 -Template template-centos76 -VMHost 10.10.12.14 -OSCustomizationspec linux1 Get-VM -name zy-ntw-prod-dbvm-pushredis01|set-VM -MemoryGB 96 -NumCPU 16 get-vm zy-ntw-prod-dbvm-pushredis01|New-HardDisk -CapacityGB 100 New-Snapshot -Name &amp;#34;20200622&amp;#34; Connect-VIServer -Server 10.</description>
    </item>
    <item>
      <title>powercli创建虚拟机步骤及批量创建脚本</title>
      <link>https://www.oomkill.com/create-vm-with-powercli/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/create-vm-with-powercli/</guid>
      <description>文档中心 https://pubs.vmware.com/vsphere-51/index.jsp?topic=%2Fcom.vmware.powercli.cmdletref.doc%2FSet-OSCustomizationSpec.html https://blogs.vmware.com/PowerCLI/2014/05/working-customization-specifications-powercli-part-1.html http://powershelldistrict.com/powercli-oscustomizationspec/ https://powercli-core.readthedocs.io/en/latest/cmd_new.html#new-oscustomizationspec 官方文档中心
添加一块新硬盘
text 1 get-vm {vmname}|New-HardDisk -CapacityGB 300 批量设置硬件
text 1 Get-VM -name {hostname}*|set-VM -MemoryGB 4 -NumCPU 2 基于模板创建虚拟机
text 1 new-VM -Name {hostname} -Template template-centos76 -VMHost 10.112.131.5 -OSCustomizationspec TestLinux 设置规范模板
text 1 2 3 4 5 6 7 8 9 10 11 Get-OSCustomizationSpec TestLinux|Get-OSCustomizationNicMapping|Set-OSCustomizationNicMapping \ -IpMode UseStaticIP \ -SubnetMask 255.255.255.0 \ -DefaultGateway 10.11.121.254 \ -IpAddress 10.11.121.203 Get-OSCustomizationSpec TestLinux|Get-OSCustomizationNicMapping|Set-OSCustomizationNicMapping \ -IpMode UseStaticIP \ -SubnetMask 255.</description>
    </item>
    <item>
      <title>zimbra安装ssl证书</title>
      <link>https://www.oomkill.com/zimbra-ssl/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/zimbra-ssl/</guid>
      <description>zimbra在后台安装证书签发机构签发证书出现时候出现错误：{RemoteManager: mail.domain.com-&amp;gt;zimbra@mail.domain.com:22}
text 1 2 3 com.zimbra.common.service.ServiceException: system failure: exception during auth {RemoteManager: mail.domain.com-&amp;gt;zimbra@mail.domain.com:22} ExceptionId:qtp1068934215-357:https:https ://mail.domain.com:7071/service/admin/soap/GetMailQueueRequest: Code:service.FAILURE text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 com.zimbra.common.service.ServiceException: system failure: exception during auth {RemoteManager: mail.domain.com-&amp;gt;zimbra@mail.domain.com:22} ExceptionId:qtp1068934215-357:https:https ://mail.domain.com:7071/service/admin/soap/GetMailQueueRequest: Code:service.FAILURE at com.zimbra.common.service.ServiceException.FAILURE(ServiceException.java:286) at com.zimbra.cs.rmgmt.RemoteManager.getSession(RemoteManager.java:209) at com.zimbra.cs.rmgmt.RemoteManager.execute(RemoteManager.java:139) at com.zimbra.cert.GetCert.addCertsOnServer(GetCert.java:112) at com.zimbra.cert.GetCert.handle(GetCert.java:75) Caused by: java.io.IOException: There was a problem while connecting to mail.domain.com:22 at ch.ethz.ssh2.Connection.connect(Connection.java:699) at ch.ethz.ssh2.Connection.connect(Connection.java:490) at com.zimbra.cs.rmgmt.RemoteManager.getSession(RemoteManager.java:200) .</description>
    </item>
    <item>
      <title>zimbra修改ServerName</title>
      <link>https://www.oomkill.com/zimbra-change-servername/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/zimbra-change-servername/</guid>
      <description>文章概述了如何使用 zmsetservername 更改 Zimbra 服务器的主机名。请注意，此 CLI 命令的用法因您运行的 ZCS 版本而异。
语法：
bash 1 ./zmsetservername [-h] [-d] [-f] [-s] [-o &amp;lt;上一个服务器名称&amp;gt;] [-v+] -n &amp;lt;服务器名称&amp;gt; 参数说明
Name Description &amp;ndash;help 显示 zmsetservername 的使用选项。 &amp;ndash;force 强制重命名，绕过安全检查。 &amp;ndash;oldServerName 服务器以前的名称。默认为 LC zimbra_server_hostname。 &amp;ndash;newServerName 服务器的新名称。 &amp;ndash;deletelogger 删除旧服务器的记录器数据库。默认是将其数据重新映射到新主机名。 &amp;ndash;skipusers 跳过使用新服务器修改用户数据库。 &amp;ndash;usersonly 仅更新用户数据库。这样，您可以运行一次来完成所有服务器更新，然后运行第二次来更新帐户。可能需要 --force。 &amp;ndash;verbose 设置详细级别。可以多次指定以提高级别。 Reference zm设置服务器名称</description>
    </item>
    <item>
      <title>zimbra用户管理员脚本</title>
      <link>https://www.oomkill.com/zimbra-admin-script/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/zimbra-admin-script/</guid>
      <description>sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #!/bin/bash # $1 domain # $2 email zmprov ma $2 zimbraIsDelegatedAdminAccount TRUE zmprov ma $2 zimbraAdminConsoleUIComponents cartBlancheUI zimbraAdminConsoleUIComponents domainListView zimbraAdminConsoleUIComponents accountListView zimbraAdminConsoleUIComponents DLListView zmprov ma $2 zimbraDomainAdminMaxMailQuota 0 zmprov grantRight domain $1 usr $2 +createAccount zmprov grantRight domain $1 usr $2 +createAlias zmprov grantRight domain $1 usr $2 +createCalendarResource zmprov grantRight domain $1 usr $2 +createDistributionList zmprov grantRight domain $1 usr $2 +deleteAlias zmprov grantRight domain $1 usr $2 +listDomain zmprov grantRight domain $1 usr $2 +domainAdminRights zmprov grantRight domain $1 usr $2 set.</description>
    </item>
    <item>
      <title>如何使用golang通过进程ID找到进程名称</title>
      <link>https://www.oomkill.com/goskill-process-id/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/goskill-process-id/</guid>
      <description>一个很好的问题：How golang to get process name by process id (pid)?
目前看来go api并没有提供通过pid获取进程名称的方法，可以通过 /proc/&amp;lt;pid&amp;gt;/cmdline来获取对应的进程名称，也可以通过 readlink /proc/6530/exe 来获取
/proc/&amp;lt;pid&amp;gt;/cmdline 获取的为运行进程的名称，通常包含一些特殊字符。例如 &amp;quot;-bash\x00&amp;quot;，sshd: root@pts/0 readlink /proc/6530/exe 获取的为对应进程运行的程序的路径 go 1 2 pid := os.Getppid() contents, err := ioutil.ReadFile(fmt.Sprintf(&amp;#34;/proc/%d/cmdline&amp;#34;,pid)) go 1 2 pid := os.Getppid() contents, err := os.Readlink(fmt.Sprintf(&amp;#34;/proc/%d/cmdline&amp;#34;,pid)) Reference process name from pid</description>
    </item>
    <item>
      <title>使用go语言颁发CA证书</title>
      <link>https://www.oomkill.com/goskill-x509-in-go/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/goskill-x509-in-go/</guid>
      <description>本篇文章中，将描述如何使用go创建CA，并使用CA签署证书。在使用openssl创建证书时，遵循的步骤是 创建秘钥 &amp;gt; 创建CA &amp;gt; 生成要颁发证书的秘钥 &amp;gt; 使用CA签发证书。这种步骤，那么我们现在就来尝试下。
创建证书的颁发机构 首先，会从将从创建 CA 开始。CA 会被用来签署其他证书
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // 对证书进行签名 ca := &amp;amp;x509.Certificate{ SerialNumber: big.NewInt(2019), Subject: pkix.Name{ CommonName: &amp;#34;domain name&amp;#34;, Organization: []string{&amp;#34;Company, INC.&amp;#34;}, Country: []string{&amp;#34;US&amp;#34;}, Province: []string{&amp;#34;&amp;#34;}, Locality: []string{&amp;#34;San Francisco&amp;#34;}, StreetAddress: []string{&amp;#34;Golden Gate Bridge&amp;#34;}, PostalCode: []string{&amp;#34;94016&amp;#34;}, }, NotBefore: time.Now(), // 生效时间 NotAfter: time.Now().AddDate(10, 0, 0), // 过期时间 年月日 IsCA: true, // 表示用于CA // openssl 中的 extendedKeyUsage = clientAuth, serverAuth 字段 ExtKeyUsage: []x509.</description>
    </item>
    <item>
      <title>通过Go语言中阐述TCP Handshake</title>
      <link>https://www.oomkill.com/go-tcp-hadshake/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-tcp-hadshake/</guid>
      <description>TCP的三次握手 所谓三次握手 Three-Way Handshake 是指建立一个TCP连接时，需要客户端和服务端总共发送3个包以确认连接的建立。好比两个人在打电话：
当连接被建立或被终止，交换的报文段只包含TCP头部，而没有数据。
tcp报文头部结构 序号：seq序号，占32位，用来标识从TCP源端向目的端发送的字节流，发起方发送数据时对此进行标记。 确认序号：ack序号，占32位，只有ACK标志位为1时，确认序号字段才有效，确认方ack=发起方seq+1，两端配对。 标志位 ACK：确认序号有效。 FIN：释放一个连接。 RST：重置连接。 SYN：发起一个新连接。 PSH：接收方应该尽快将这个报文交给应用层。 URG：紧急指针（urgent pointer）有效。 第一次握手：客户端要向服务端发起连接请求，首先客户端随机生成一个起始序列号ISN(比如是100)，那客户端向服务端发送的报文段包含SYN标志位(也就是SYN=1)，序列号seq=100。
第二次握手：服务端收到客户端发过来的报文后，发现SYN=1，知道这是一个连接请求，于是将客户端的起始序列号100存起来，并且随机生成一个服务端的起始序列号(比如是300)。然后给客户端回复一段报文，回复报文包含SYN和ACK标志(也就是SYN=1,ACK=1)、序列号seq=300、确认号ack=101(客户端发过来的序列号+1)。
第三次握手：客户端收到服务端的回复后发现ACK=1并且ack=101,于是知道服务端已经收到了序列号为100的那段报文；同时发现SYN=1，知道了服务端同意了这次连接，于是就将服务端的序列号300给存下来。然后客户端再回复一段报文给服务端，报文包含ACK标志位(ACK=1)、ack=301(服务端序列号+1)、seq=101(第一次握手时发送报文是占据一个序列号的，所以这次seq就从101开始，需要注意的是不携带数据的ACK报文是不占据序列号的，所以后面第一次正式发送数据时seq还是101)。当服务端收到报文后发现ACK=1并且ack=301，就知道客户端收到序列号为300的报文了，就这样客户端和服务端通过TCP建立了连接。
四次挥手 比如客户端初始化的序列号ISA=100，服务端初始化的序列号ISA=300。TCP连接成功后客户端总共发送了1000个字节的数据，服务端在客户端发FIN报文前总共回复了2000个字节的数据。
第一次挥手：当客户端的数据都传输完成后，客户端向服务端发出连接释放报文(当然数据没发完时也可以发送连接释放报文并停止发送数据)，释放连接报文包含FIN标志位(FIN=1)、序列号seq=1101(100+1+1000，其中的1是建立连接时占的一个序列号)。需要注意的是客户端发出FIN报文段后只是不能发数据了，但是还可以正常收数据；另外FIN报文段即使不携带数据也要占据一个序列号。
第二次挥手：服务端收到客户端发的FIN报文后给客户端回复确认报文，确认报文包含ACK标志位(ACK=1)、确认号ack=1102(客户端FIN报文序列号1101+1)、序列号seq=2300(300+2000)。此时服务端处于关闭等待状态，而不是立马给客户端发FIN报文，这个状态还要持续一段时间，因为服务端可能还有数据没发完。
第三次挥手：服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文，报文包含FIN和ACK标志位(FIN=1,ACK=1)、确认号和第二次挥手一样ack=1102、序列号seq=2350(2300+50)。
第四次挥手：客户端收到服务端发的FIN报文后，向服务端发出确认报文，确认报文包含ACK标志位(ACK=1)、确认号ack=2351、序列号seq=1102。注意客户端发出确认报文后不是立马释放TCP连接，而是要经过2MSL(最长报文段寿命的2倍时长)后才释放TCP连接。而服务端一旦收到客户端发出的确认报文就会立马释放TCP连接，所以服务端结束TCP连接的时间要比客户端早一些。</description>
    </item>
    <item>
      <title>正则表达式在go中使用</title>
      <link>https://www.oomkill.com/go-regular-expression/</link>
      <pubDate>Wed, 02 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-regular-expression/</guid>
      <description>正则表达式是一种进行模式匹配和文本操纵的复杂而又强大的工具。虽然正则表达式比纯粹的文本匹配效率低，但是它却更灵活。按照它的语法规则，随需构造出的匹配模式就能够从原始文本中筛选出几乎任何你想要得到的字符组合。
Go语言通过regexp（regular expression）标准包为正则表达式提供了官方支持，包名采用regular expression的每个单词的前三个首字母组成。
Go语言的正则表达式实现的是RE2标准，Go语言的正则表达式与其他编程语言之间也有一些小的差异。
正则表达式规则 go语言中regexp包使用 简单来说，Go语言中使用正则表达式只需要两步即可：
解析、编译正则表达式 regexp.MustCompile() 返回一个regexp结构体 根据解析好的规则（结构体形式），从指定字符串中提取需要的信息。如 MatchString() FindAllSubmatch()等 go 1 2 3 4 5 6 7 8 9 10 11 12 13 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;regexp&amp;#34; ) func main() { rege := regexp.MustCompile(`(\d{1,3}\.){3}\d{1,3}`) str := rege.FindAllString(&amp;#34;SLAJDLKAJ192.168.0.1DASDASA1231&amp;#34;, -1) fmt.Println(str) } </description>
    </item>
    <item>
      <title>Ceph RBD - 初识块存储RBD</title>
      <link>https://www.oomkill.com/ch03-1-acquaintance-rdb/</link>
      <pubDate>Mon, 30 Sep 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch03-1-acquaintance-rdb/</guid>
      <description>什么是块存储 RBD Ceph RBD (RADOS Block Device) 是 Ceph 提供的三种存储类型之一 (块存储 RBD, 文件存储 CephFS, 对象存储 RGW)，也是另外两个存储类型 (文件存储 CephFS, 对象存储 RGW) 的底座，位于 RADOS 架构中的最底层，由下图可以看出
图：Ceph RADOS架构图Source：https://www.supportsages.com/ceph-part-3-technical-architecture-and-components/
RADOS 是可信赖的自动分布式对象存储 (Reliable Autonomous Distributed Object Store) 的简写，通俗来说，RADOS 代表的就是整个 Ceph 集群，数据对象在集群中的存储方式会“将对象复制为多副本” 以实现容错，所以 Ceph 集群的底座就是 RADOS，一个 RADOS 集群的组件通常包含三个，OSD Daemon , MDS, MON
Object Storage Device (OSD) Daemon：RADOS集群中负责存储守护进程，与 OSD (数据的物理或逻辑存储单元【通常指一个硬盘】)交互。集群中的每个 Ceph Node 都必须运行 OSD Daemon。对于每个 OSD，可以有一个关联的硬盘 (通常一个OSD Daemon 对应一个存储单元)。 MONITORS (Mon Daemon)：Monitor (ceph-mon) 不是集群存储组件的一部分，但它通过监视 OSD 状态并生成 “Cluster Map” 而成为 RADOS 不可或缺的一部分。它监视 OSD 并跟踪在给定时间点哪些 OSD 处于运行状态、哪些 OSD 处于对等状态、OSD 的状态等。一般来说，它充当存储集群中所有 OSD 的 Monitor Manager (MGR Daemon)：Manager (ceph-mgr) 是与 ceph-mon 一同运行的守护进程，为外部监控和管理系统提供额外的监视和接口。默认情况下，ceph-mgr 除了确保其正在运行之外不需要其他配置。如果没有运行 ceph-mgr，ceph -s 将会看到一条 WARN；不管是使用什么方式部署的集群 ( ceph-deploy, cephadm)，ceph-mgr 总会 与 ceph-mon 同时运行在一个节点上，也可单独运行在 Ceph Node 之上。 通常 Monitor (ceph-mon) 不构成“存储”集群的一部分，只是通过监视 OSD 状态并生成 Cluster map 而成为 ceph存储集群中不可缺少的组件。它通过监视 OSD 并跟踪在给定时间点哪些 OSD 处于运行状态、哪些 OSD 处于对等状态、OSD 的状态等。</description>
    </item>
    <item>
      <title>理解ldap - Linux系统接入OpenLDAP做认证后端</title>
      <link>https://www.oomkill.com/ch10-linux-with-ldap/</link>
      <pubDate>Mon, 30 Sep 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch10-linux-with-ldap/</guid>
      <description>openldap合集 ch1 理解ldap - 什么是ldap ch2 理解ldap - OpenLDAP安装 ch3 理解ldap - OpenLDAP客户端命令行使用 ch4 理解ldap - OpenLDAP架构与Schema设计 ch5 理解ldap - OpenLDAP使用SSL/TLS通信安全 ch6 理解ldap - OpenLDAP中的4种复制机制 ch7 理解ldap - OpenLDAP访问控制(ACL) ch8 理解ldap - OpenLDAP备份与恢复策略 ch9 理解ldap - openldap中的一些高级配置 ch10 理解ldap - Linux系统接入OpenLDAP做认证后端 ch11 理解ldap - 使用SSSD接入OpenLDAP实现身份验证 Overview 如果要使Linux账号通过LDAP进行身份认证，就需要配置Linux的 身份验证模块 (Pluggable Authentication Modules) 与 名称服务交换系统 (Name Service Switch) 与LDAP交互。
PAM 和 NSS [3] NSS (name service switch) 通俗理解为是一个数据库系统，他作用是用于如何将操作系统与各种名称的解析机制关联起来，例如主机名，用户名，组名等内容的查找；例如UID查找使用 passwd 库，GID的查找使用 group 库，并且还可以告知查找的来源，如文件，LDAP等</description>
    </item>
    <item>
      <title>理解ldap配置 - openldap中的一些高级配置</title>
      <link>https://www.oomkill.com/ch9-openldap-configuration/</link>
      <pubDate>Tue, 24 Sep 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch9-openldap-configuration/</guid>
      <description>openldap合集 ch1 理解ldap - 什么是ldap ch2 理解ldap - OpenLDAP安装 ch3 理解ldap - OpenLDAP客户端命令行使用 ch4 理解ldap - OpenLDAP架构与Schema设计 ch5 理解ldap - OpenLDAP使用SSL/TLS通信安全 ch6 理解ldap - OpenLDAP中的4种复制机制 ch7 理解ldap - OpenLDAP访问控制(ACL) ch8 理解ldap - OpenLDAP备份与恢复策略 ch9 理解ldap - openldap中的一些高级配置 ch10 理解ldap - Linux系统接入OpenLDAP做认证后端 ch11 理解ldap - 使用SSSD接入OpenLDAP实现身份验证 memberOf 默认情况下，openldap提供的Posixgroup组，实际上并不能很有效的区分组与用户之间的关系。而 memberOf 则可以有效地检索用户与组的关系
在OpenLDAP配置MemberOf模块 步骤一：可以检查在允许的slapd服务是否已经启用该模块
bash 1 $ slapcat -n 0 | grep olcModuleLoad 对于新部署的服务，可以按照如下方式添加
text 1 2 3 4 dn: cn=module,cn=config objectClass: olcModuleList cn: module olcModuleload: memberof.</description>
    </item>
    <item>
      <title>理解ldap - OpenLDAP备份与恢复策略</title>
      <link>https://www.oomkill.com/ch8-backup-and-restore/</link>
      <pubDate>Mon, 23 Sep 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch8-backup-and-restore/</guid>
      <description>openldap合集 ch1 理解ldap - 什么是ldap ch2 理解ldap - OpenLDAP安装 ch3 理解ldap - OpenLDAP客户端命令行使用 ch4 理解ldap - OpenLDAP架构与Schema设计 ch5 理解ldap - OpenLDAP使用SSL/TLS通信安全 ch6 理解ldap - OpenLDAP中的4种复制机制 ch7 理解ldap - OpenLDAP访问控制(ACL) ch8 理解ldap - OpenLDAP备份与恢复策略 ch9 理解ldap - openldap中的一些高级配置 ch10 理解ldap - Linux系统接入OpenLDAP做认证后端 ch11 理解ldap - 使用SSSD接入OpenLDAP实现身份验证 Overview 本章基于openldap 2.4+版本进行，主要讲解 openldap 的两种备份方法：备份openldap backend-database 文件，另一种方式为导出 LDIF 目录方式
Backup 备份部分将分为两种方式：使用基于 slapcat 导出目录文件方式，与直接备份数据库文件方式。
slapcat 是可用于导出 slapd 数据库中数据为LDAP交换格式的命令行工具，它可以导出 slapd 的配置也可以导出 slapd的数据。
slapcat 使用起来很简单，参数也是与 openldap 其他命令参数类似，</description>
    </item>
    <item>
      <title>理解ldap - OpenLDAP访问控制(ACL)</title>
      <link>https://www.oomkill.com/ch7-acl/</link>
      <pubDate>Sun, 22 Sep 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch7-acl/</guid>
      <description>openldap合集 ch1 理解ldap - 什么是ldap ch2 理解ldap - OpenLDAP安装 ch3 理解ldap - OpenLDAP客户端命令行使用 ch4 理解ldap - OpenLDAP架构与Schema设计 ch5 理解ldap - OpenLDAP使用SSL/TLS通信安全 ch6 理解ldap - OpenLDAP中的4种复制机制 ch7 理解ldap - OpenLDAP访问控制(ACL) ch8 理解ldap - OpenLDAP备份与恢复策略 ch9 理解ldap - openldap中的一些高级配置 ch10 理解ldap - Linux系统接入OpenLDAP做认证后端 ch11 理解ldap - 使用SSSD接入OpenLDAP实现身份验证 Overview 访问控制 (Access Control) 是对目录树中的IDT访问的权限控制。主要指 “谁” 应该能够 “访问记录” 在 “什么条件下” 他们应该能看到多少这样的记录，这些将是本节中阐述的问题 。
OpenLDAP控制目录数据访问的主要方法是 通过访问控制列表 (Access Control List)。使 slapd 服务端在处理来自客户端的请求时，会评估客户端是否具有访问所请求的 DIT 的权限。要执行此计算，slapd 将依次计算LDIF 中配置的每个ACL策略，以检查客户端是否有权限访问该 DIT。</description>
    </item>
    <item>
      <title>理解ldap配置 - OpenLDAP中的4种复制机制</title>
      <link>https://www.oomkill.com/ch6-replication/</link>
      <pubDate>Fri, 20 Sep 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch6-replication/</guid>
      <description>openldap合集 ch1 理解ldap - 什么是ldap ch2 理解ldap - OpenLDAP安装 ch3 理解ldap - OpenLDAP客户端命令行使用 ch4 理解ldap - OpenLDAP架构与Schema设计 ch5 理解ldap - OpenLDAP使用SSL/TLS通信安全 ch6 理解ldap - OpenLDAP中的4种复制机制 ch7 理解ldap - OpenLDAP访问控制(ACL) ch8 理解ldap - OpenLDAP备份与恢复策略 ch9 理解ldap - openldap中的一些高级配置 ch10 理解ldap - Linux系统接入OpenLDAP做认证后端 ch11 理解ldap - 使用SSSD接入OpenLDAP实现身份验证 LDAP复制概述 openldap的复制 ( replication) 是可以将 LDAP DIT (Directory Information Tree) 同步更新复制到一个或多个LDAP (“ slapd ”) 系统，主要是用于实现备份或提升性能场景。在 openldap中，需要注意的一点是 “复制” 级别属于DIT级别而非LDAP服务级别运行。因此，在运行的一个服务 (slapd) 中的多个DIT，每一个DIT都可以被复制到不同的其他服务中 (slapd) 。本章节只讲述 openldap 2.4+ 的四种复制模式。</description>
    </item>
    <item>
      <title>理解ldap配置 - OpenLDAP使用SSL/TLS通信安全</title>
      <link>https://www.oomkill.com/ch05-openldap-ssl/</link>
      <pubDate>Thu, 19 Sep 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch05-openldap-ssl/</guid>
      <description>openldap合集 ch1 理解ldap - 什么是ldap ch2 理解ldap - OpenLDAP安装 ch3 理解ldap - OpenLDAP客户端命令行使用 ch4 理解ldap - OpenLDAP架构与Schema设计 ch5 理解ldap - OpenLDAP使用SSL/TLS通信安全 ch6 理解ldap - OpenLDAP中的4种复制机制 ch7 理解ldap - OpenLDAP访问控制(ACL) ch8 理解ldap - OpenLDAP备份与恢复策略 ch9 理解ldap - openldap中的一些高级配置 ch10 理解ldap - Linux系统接入OpenLDAP做认证后端 ch11 理解ldap - 使用SSSD接入OpenLDAP实现身份验证 OpenLDAP TLS/SSL 配置 对于 TLS/SSL 方向的内容不过多阐述了，这里只阐述openldap TLS/SSL 配置方向的内容
openldap提供了两种方式进行 TLS/SSL 认证
自动模式：客户端通过 ldaps://hostname/ 形式的URL访问slapd，slapd默认为636端口提供 TLS 会话 主动定义：slapd标准端口389支持 TLS/SSL ，客户端通过显式配置 TLS/SSL 也可以使用 URL格式ldap://hostname/ 进行访问，需要注意的是，在同步时如果使用 ldap:// 格式URL需要指定参数 starttls=yes 或者 starttls=critical 使用 ldaps:// 则不需要指定该参数 生成自签名证书 创建CA证书</description>
    </item>
    <item>
      <title>telegram接收altermanager消息</title>
      <link>https://www.oomkill.com/telegram-bot-send-post-json/</link>
      <pubDate>Mon, 02 Sep 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/telegram-bot-send-post-json/</guid>
      <description>text 1 2 3 4 5 6 7 8 9 10 11 curl -XPOST https://api.telegram.org/bot977657989:AAF0QE88WhxRIdpFLOYO_9ldLun5VtpfCWw/getUpdates curl -X POST \ -H &amp;#39;Content-Type: application/json&amp;#39; \ -d &amp;#39;{&amp;#34;chat_id&amp;#34;: &amp;#34;850233746&amp;#34;, &amp;#34;text&amp;#34;: &amp;#34;This is a test from curl&amp;#34;, &amp;#34;disable_notification&amp;#34;: true}&amp;#39; \ https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage curl -X POST \ -H &amp;#39;Content-Type: application/json&amp;#39; \ -d &amp;#39;{&amp;#34;chat_id&amp;#34;: &amp;#34;850233746&amp;#34;, &amp;#34;text&amp;#34;: &amp;#34;This is a test from curl&amp;#34;, &amp;#34;disable_notification&amp;#34;: true}&amp;#39; \ https://api.telegram.org/bot1009139816:AAGTmFsJDkH9H3E0OVoFi4GyvYp0uMctvcE/sendMessage https://api.telegram.org/bot721202655:AAG_kN1IHP93Wmnd90RRaJC-dK9tKQHddRA/sendMessage
json 1 2 3 4 5 { &amp;#34;chat_id&amp;#34;: &amp;#34;-383641009&amp;#34;, &amp;#34;text&amp;#34;: &amp;#34;This is a test from curl&amp;#34;, &amp;#34;disable_notification&amp;#34;: true } alertmanager发送的消息类型如下：</description>
    </item>
    <item>
      <title>理解ldap配置 - OpenLDAP架构与Schema设计</title>
      <link>https://www.oomkill.com/ch4-schema/</link>
      <pubDate>Sun, 01 Sep 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch4-schema/</guid>
      <description>openldap合集 ch1 理解ldap - 什么是ldap ch2 理解ldap - OpenLDAP安装 ch3 理解ldap - OpenLDAP客户端命令行使用 ch4 理解ldap - OpenLDAP架构与Schema设计 ch5 理解ldap - OpenLDAP使用SSL/TLS通信安全 ch6 理解ldap - OpenLDAP中的4种复制机制 ch7 理解ldap - OpenLDAP访问控制(ACL) ch8 理解ldap - OpenLDAP备份与恢复策略 ch9 理解ldap - openldap中的一些高级配置 ch10 理解ldap - Linux系统接入OpenLDAP做认证后端 ch11 理解ldap - 使用SSSD接入OpenLDAP实现身份验证 什么是schema schema又称为数据模型，是openldap中用于来指定一个条目所包含的对象类(objectClass)以及每个对象类所包含的属性值(attribute)，其中属性值又包含必要属性和可选属性。
Notes：拥有schema的数据代表该数据是结构化数据，无论他是什么格式，甚至于是一个连续的字符串
如何理解schema 不管是在学习OpenLDAP时还是学习数据库时，都会遇到一个很迷糊的Schema的概念。
在数据库中，对数据库的设计可以称之为schema。即schema约束了数据库的设计结构，并提供了整个数据库的描述。schema仅展示数据库的设计，如表字段的类型，表与表之间的关联。
在ldap中schema与database中的schema一样，如列出的schema中，这些代表了对应的ldap结构的设计。
what-is-a-schema
schema overview
text 1 2 3 4 5 6 7 8 9 10 11 12 olcObjectClasses: ( 0.</description>
    </item>
    <item>
      <title>理解ldap - OpenLDAP客户端命令行使用</title>
      <link>https://www.oomkill.com/ch3-commandline/</link>
      <pubDate>Tue, 27 Aug 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch3-commandline/</guid>
      <description>openldap合集 ch1 理解ldap - 什么是ldap ch2 理解ldap - OpenLDAP安装 ch3 理解ldap - OpenLDAP客户端命令行使用 ch4 理解ldap - OpenLDAP架构与Schema设计 ch5 理解ldap - OpenLDAP使用SSL/TLS通信安全 ch6 理解ldap - OpenLDAP中的4种复制机制 ch7 理解ldap - OpenLDAP访问控制(ACL) ch8 理解ldap - OpenLDAP备份与恢复策略 ch9 理解ldap - openldap中的一些高级配置 ch10 理解ldap - Linux系统接入OpenLDAP做认证后端 ch11 理解ldap - 使用SSSD接入OpenLDAP实现身份验证 ldapsearch 查询api ldapsearch ldapsearch命令参数说明 语法
text 1 ldapsearch [options] filter [attributes] 参数 说 明 -W 指定密码，交互式，不需要在命令上写密码 -w 指定密码，需要命令上指定密码 -H ldapapi -D 所绑定的服务器的DN，如cn=admin,dc=etiantian,dc=org -f -f: filename.</description>
    </item>
    <item>
      <title>理解ldap - OpenLDAP安装</title>
      <link>https://www.oomkill.com/ch2-install/</link>
      <pubDate>Sun, 25 Aug 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch2-install/</guid>
      <description>openldap合集 ch1 理解ldap - 什么是ldap ch2 理解ldap - OpenLDAP安装 ch3 理解ldap - OpenLDAP客户端命令行使用 ch4 理解ldap - OpenLDAP架构与Schema设计 ch5 理解ldap - OpenLDAP使用SSL/TLS通信安全 ch6 理解ldap - OpenLDAP中的4种复制机制 ch7 理解ldap - OpenLDAP访问控制(ACL) ch8 理解ldap - OpenLDAP备份与恢复策略 ch9 理解ldap - openldap中的一些高级配置 ch10 理解ldap - Linux系统接入OpenLDAP做认证后端 ch11 理解ldap - 使用SSSD接入OpenLDAP实现身份验证 生产服务器硬件配置需求 ldap服务对系统环境的要求不高，一般在生产场景，ldap服务应该最少是两台，这样某一台物理服务器岩机才不会因单点问题影响生产业务故障，对于硬件要求，本质上openldap使用硬件资源并不大，网上有两个帖子提出了openldap的硬件需求：
2003年openldap官网留言，我想安装一个 LDAP 服务器来验证邮件服务器的用户，目前有200个用户需要多少内存和CPU？[1] 1GHZ PIII/512MB 足以 运行于Ubuntu LXC 之上的openldap，用户150,000，sladp进程常驻内存为200-300MB，mdb数据库文件大小为377MB，10 并发平均响应时间为 9-11 毫秒 [13] 操作系统：Centos7/8 64bit。
操 作 系 统 其 它 CentOS-7.6 当前很稳定且免费的Linux版本。 网卡及IP资源</description>
    </item>
    <item>
      <title>理解ldap - 什么是ldap</title>
      <link>https://www.oomkill.com/ch1-understanding-ldap/</link>
      <pubDate>Fri, 23 Aug 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch1-understanding-ldap/</guid>
      <description>openldap合集 ch1 理解ldap - 什么是ldap ch2 理解ldap - OpenLDAP安装 ch3 理解ldap - OpenLDAP客户端命令行使用 ch4 理解ldap - OpenLDAP架构与Schema设计 ch5 理解ldap - OpenLDAP使用SSL/TLS通信安全 ch6 理解ldap - OpenLDAP中的4种复制机制 ch7 理解ldap - OpenLDAP访问控制(ACL) ch8 理解ldap - OpenLDAP备份与恢复策略 ch9 理解ldap - openldap中的一些高级配置 ch10 理解ldap - Linux系统接入OpenLDAP做认证后端 ch11 理解ldap - 使用SSSD接入OpenLDAP实现身份验证 什么是目录服务？ ==目录是一类为了浏览和搜索数据而设计的特殊的数据库==，例如：为人所熟知的微软公 司的活动目录（active directory）就是目录数据库的一种，目录服务是按照==树状形式==存储信息的，目录包含基于属性的描述性信息，并且支持高级的过滤功能。
http://www.openldap.org/doc/admin24/intro.html 一般来说，目录不支持大多数事务型数据库所支持的高吞吐量和复杂的更新操作。目录进行更新操作，可以说是要么全部，要么都不的原子操作。目录服务适合的业务应用在于提供大量的查询和搜索操作，而不是大量的写入操作。Ldap可以说是活动目录在linux系统上的一个开源实现。
为了保证目录数据的可用性和可靠性，在确保使用目录服务提供快速查询和搜索操作的同时，目录服务还提供了==主从服务器同步目录数据信息的能力==，这相当于传统的MySQL数据库的主从同步功能一样，可以最大限度的确保基于目录业务的服务持续可用性与提供并发查询能力，微软公司的活动目录（active directory）就有主域和备份域的说法。
广义的目录服务概念，可以用多种不同的方式来提供目录服务。不同的目录所允许存储的信息是不同的，在信息如何被引用、查询、更新以及防止未经授权的访问等问题上，不同的目录服务的处理方式也有诸多的不同。
例如：一些目录服务是本地的，只提供受限的服务（比如，单机上的finger服务）。另一些服务是大范围的（global），提供广阔得多的服务（比如面向整个因特网），大范围的服务通常是分布式的，这也就意味着数据是分布在多台机器上的，这些机器一起来提供目录服务，典型的大范围服务定义一个统一的名称空间（namespace）来给出一个相同的数据视图（data view），而不管你相对于数据所在的位置。DNS是一个典型的大范围分布式目录服务的例子。
http://www.openldap.org/faq/data/cache/595.html 什么是ldap？ 目录服务有两个国际标准，分别是X.500和LDAP。X.500是ITU定义的目录标准，而LDAP是基于TCP/IP的目录访问协议，是Intemet上目录服务的通用访问协议。
LDAP是 Lightweight Directory Access Protocol（轻量级目录访问协议）的缩写。正如它的名字所表明的那样，它是一个轻量级的目录访问协议，特指基于X.500的目录访问协议的简化版本。LDAP运行在 TCP/IP 或者其他的面向连接的传输服务之上。LDAP完整的技术规范由RFC2251“The Lightweight Directory Access Protocol（v3）”和其他几个在RFC3377中定义的文档组成。</description>
    </item>
    <item>
      <title>Ceph RBD - 关于RBD的操作与管理</title>
      <link>https://www.oomkill.com/ch03-2-rbd-management/</link>
      <pubDate>Wed, 31 Jul 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch03-2-rbd-management/</guid>
      <description>上一章提到了 RBD 块设备相关的基本配置，这章主要描述 RBD 操作部分
ceph块设备接口（RDB） Ceph块设备，也称为RADOS块设备（简称RBD），是一种基于RADOS存储系统支持超配（thin-provisioned）、可伸缩的条带化数据存储系统，它通过librbd库与OSD进行交互。RBD为KVM等虑拟化技术和云OS（如OpenStack和CloudStack）提供高性能和无限可扩展性的存储后端，这些系统依赖于libvirt和QEMU实用程序与RBD进行集成。
客户端基于librbd库即可将RADOS存储集群用作块设备，不过，用于rbd的存储池需要实现启用rbd功能并进行初始化。例如，下面的命令创建rbddata的存储池，在启动rbd功能后对其进行初始化。
sh 1 2 3 4 ceph osd pool create rbdpool 64 # 创建存储池 rbd pool init -p rbdpool # rbd create rbdpool/img1 --size 2G rbd ls -p rbdpool 不过rbd存储池并不能直接用于块设备，而是需要事先在其中按需创建影响（image）
RBD是建立在librados之上的客户端，全程为Rados Block Devices，是对rados存储服务做抽象，将rados位于存储池当中所提供的存储空间，使用对象式存储数据的能力的机制。
rbd虚拟磁盘设备要想使linux内核所识别使用，要求linux在内核级支持Ceph，内核级有一个Ceph模块，专门用来驱动Ceph设备的。这个驱动就叫librbd。此模块自己是一个客户端，能够连接至RBD服务上，检索出他所管理的镜像文件。从而镜像文件完全可以被linux主机作为一块完整的硬盘来使用。
创建存储池镜像
--object-size 任何数据存储在存储池中都被切分为固定大小的对象，对象通常称之为条带，切分的对象大小，默认4M --image-feature 指定镜像文件的特性，每种特性代表镜像文件能支持哪些种功能，可被单独启用或禁用。 layering(+), 分层克隆 exclusive-lock 排它锁，是否支持分布式排它锁，已用来限制一个镜像文件同时只能被一个客户端使用。 object-map(+*) 对象映射,是否支持对象位图，主要用于加速导入、导出及已用容量统的。 fast-diff(+*), 快速比较，主要用于做快照之间的比较 deep-flatten(+-) , 深层展评 journaling 日志，用户在修改image数据时是否记录日志。 shared image --no-progress：不显示创建过程 sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 $ rbd help create usage: rbd create [--pool &amp;lt;pool&amp;gt;] [--image &amp;lt;image&amp;gt;] [--image-format &amp;lt;image-format&amp;gt;] [--new-format] [--order &amp;lt;order&amp;gt;] [--object-size &amp;lt;object-size&amp;gt;] [--image-feature &amp;lt;image-feature&amp;gt;] [--image-shared] [--stripe-unit &amp;lt;stripe-unit&amp;gt;] [--stripe-count &amp;lt;stripe-count&amp;gt;] [--data-pool &amp;lt;data-pool&amp;gt;] [--journal-splay-width &amp;lt;journal-splay-width&amp;gt;] [--journal-object-size &amp;lt;journal-object-size&amp;gt;] [--journal-pool &amp;lt;journal-pool&amp;gt;] [--thick-provision] --size &amp;lt;size&amp;gt; [--no-progress] &amp;lt;image-spec&amp;gt; Create an empty image.</description>
    </item>
    <item>
      <title>Ceph对象存储概述</title>
      <link>https://www.oomkill.com/ch05-1-rgw/</link>
      <pubDate>Wed, 31 Jul 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch05-1-rgw/</guid>
      <description>什么是对象存储 对象存储是一种以非结构化格式（称为对象），简单来说，对象存储是一种将文件存储为对象而不是数据块的存储架构。它是一种将非结构化数据存储在跨位置分布的结构化平面文件系统中的方法。在这种格式中，文件空间由元数据标签组成，支持简单的 API 来描述、读取、删除和定位对象。因此，您可以通过 API 协议直接访问任何设备上保存的数据。此类元数据标签包括有助于更好地识别和分类数据的唯一标识符。
这些元数据标签是高度可定制的，让您可以在需要时通过跟踪和索引文件来轻松组织、访问和检索所有数据。对象存储服务可以在设备级、系统级甚至接口级实现。作为对象存储的数据可确保数据可用性、可搜索性并增强数据安全性，因为它可以保护数据免遭意外删除或损坏。
什么是 CEPH 中的对象存储 在知道了对象存储不能作为文件系统磁盘由操作系统直接访问，只可以通过应用程序级别的 API 进行访问。Ceph是一个分布式对象存储系统，通过一个 “网关服务” 来提供对象存储接口，这个服务被称为 RADOS Gateway ( RGW )，RGW是构建在 Ceph RADOS 之上，通过在 librados 之构建出的一个库 librgw，实际上是一个 Civetweb 的服务，rados gateway 内嵌在里面，RGW 为应用程序提供兼容 RESTful 的 S3/Swift 的 API 接口，以在 Ceph 集群中以对象的形式存储数据。Ceph 还支持多租户对象存储，可通过 RESTful API 访问。除此之外，RGW 还支持 Ceph 管理 API，可用于使用本机 API 调用来管理 Ceph 存储集群。
librados 是一个构建在 RADOS 集群和 Ceph 集群的中间层，通过这个库，提供了允许用户应用程序通过C、C++、Java、Python 和 PHP绑定直接访问 Ceph 存储集群。Ceph 对象存储还具有多站点 (MultiSite) 能力，即提供灾难恢复的解决方案。
图：Ceph RGW StructureSource：https://docs.ceph.com/en/octopus/radosgw/
安装rgw
rgw 包 ceph-radosgw</description>
    </item>
    <item>
      <title>Ceph文件系统概述</title>
      <link>https://www.oomkill.com/ch04-1-cephfs/</link>
      <pubDate>Wed, 31 Jul 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch04-1-cephfs/</guid>
      <description>Ceph专门提供了文件系统接口CephFS。CephFS是略微不同于RBD的架构形式，在基础的RADOS Cluster存储集群的基础之上，需要额外运行一个守护进程MDS MetaDataServer 元数据服务器。
RADOS Cluster自己是一个对象存储服务，他无法管理传统文件系统上分离去管理元数据和数据的功能。（而且元数据还拥有权限、用户属组、时间戳等。）RADOS Cluster自身是无法实现这个功能的。MDS专用于模拟传统文件系统所应该具有的将数据和元数据分离存储的方式而专门提供的一个服务。MDS只用来管理元数据。
MDS需要工作一个守护进程，客户端必须通过套接字的方式，每一次访问文件时，先去联系到MDS，来获取文件的元数据信息，再到RADOS Cluster以对象方式，将对象模拟成传统文件系统的块，来加载文件数据。
如是挂在CephFS系统的客户端，需先联系到MDS，识别文件系统的各种信息。客户端向挂载目录路径下的任何一个读写操作就相当于由挂载时的内核驱动模块联系到对应的MDS，而后再由客户端之上的模块来联系到RADOS Cluster。为了能够支持CephFS文件系统，也需要内核级模块Ceph.ko模块。挂载过程机制为将内核模块作为文件系统内核的客户端，与文件系统的守护进程进行通讯，必要时将用户数据存取转为对应集群的存储操作。
对于Rados存储集群来讲，存储集群所有数据都会被放在存储池当中，而CephFS管理其数据和元数据分别放置在不同的存储池中。所有元数据都是由MDS管理的。MDS也是客户端，连入CephFS的的metadata，专门用于存储元数据的存储池。
cephfs逻辑
元数据是一类很密集的IO访问。对原数据存储池的操作是放置在存储池当中的，但在本地会使用内存（高速缓存）中完成，过断时间同步到metadata pool中。而数据直接写入data存储池中
meatdata pool只能对mds访问，其他任何客户端时不能被访问的。客户端对元数据的访问必须经由MDS来实现。
当客户端打开一个文本时，首先请求客户端的inode（传统文件系统采用inode来保存文件的元数据）。获得相应授权以后从mds中接收到inode，inode中标示文件的数据究竟放置在data pool的那些对象中。返回对象编号给客户端，客户端基于对象编号访问所有的对象，将数据加载到。
ceph mds stat
mds: 2 up:standby 当没有文件系统时，无法进行选举，故所有的都为standby
CephFS Client访问CephFS集群的方式
客户端挂载CephFS， 基于内核文件系统完成挂载ceph、libcephfs 用户空间文件系统（FUSE Filesystem in USErspace）：libcephfs与ceph集群进行交互。 ==激活CephFS步骤==
激活CephFS MDS，至少有一个节点运行ceph-mds守护进程
ceph-deploy命令完成的 创建存储池：metadata-pool、data-pool
bash 1 2 ceph osd pool create cephfs_metadata 8 8 ceph osd pool create cephfs_data 8 8 激活文件系统：
ceph fs new &amp;lt;name&amp;gt; {metadata-pool-name} {pool-name} ceph fs status {filesystem-name} ceph fs stat 获得必要授权，才能使用服务</description>
    </item>
    <item>
      <title>用于监控nginx的exporter：nginx-module-vts</title>
      <link>https://www.oomkill.com/prome-nginx-module-vts/</link>
      <pubDate>Tue, 02 Jul 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/prome-nginx-module-vts/</guid>
      <description>prometheus 监控nginx的模块 nginx-module-vts
下载后配置
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 http{ vhost_traffic_status_zone; vhost_traffic_status_zone shared:vhost_traffic_status:32m; # 设置共享内存大小 server { vhost_traffic_status_filter_by_set_key $status $server_name; # 计算详细的http状态代码的流量 location /status { vhost_traffic_status_display; # 设置了该指令，则可以访问如下： vhost_traffic_status_display_format html; vhost_traffic_status off; ## 启用或禁用模块工作 } } } 不想统计流量的server区域禁用vhost_traffic_statu off
例： 计算upstream后端响应时间 nginx_upstream_responseMsec{upstream=“group1”}
一个完整的配置文件：nginx.conf 关于GEO相关：GeoIP.dat file format #162 ngx如何配置GEO：GeoIP discontinuation; Upgrade to GeoIP2 with nginx on CentOS 删除所zone内存中的数据
bash 1 curl localhost/status/control?</description>
    </item>
    <item>
      <title>Ceph安全 - CephX</title>
      <link>https://www.oomkill.com/ch07-1-cephx/</link>
      <pubDate>Sun, 30 Jun 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch07-1-cephx/</guid>
      <description>如果需要与osd打交道，需要通过mon检索集群运行图才能够访问的客户端，通常经由mon认证后才能访问ceph存储。Ceph本身实现了数据服务的认证访问和授权控制机制，CephX协议来实现
CephX Protocol
CephX本身只负责认证和授权检测，不处理通讯过程是否加密。一般来讲需要与moniotr交互的客户端组件（OSD、RBD、RGW等）一般而言都经由CephX认证
CephX认证机制 Ceph使用cephx协议对客户端进行身份认证
每个MON都可以对客户端进行身份验正并分发密钥，不存在单点故障和性能瓶颈。（在集群模式下，任何一个monitor在实现认证时是无状态的，每个monitor都能完成身份检验的任务） MON会返回用于身份验正的数据结构，其包含获取Ceph服务时用到的session key session key通过客户端密钥进行加密，需事先有一个预共享秘钥存在 客户端使用session key向MON请求所需的服务。session key只是拿来做中间通讯使用。 MON向客户端提供一个ticket，用于向实际处理数据的OSD等验正客户端身份。 MON和OSD共享同一个secret，因此OSD会信任由MON发放的ticket ticket存在有效期限 注意：
CephX身份验正功能仅限制Ceph的各组件之间，它不能扩展到其它非Ceph组件。 它并不解决数据传输加密的问题。 为了实现Cephx认证，Ceph服务器端一定会为每一个客户端事先生成一个密码
认证与授权 无论Ceph客户端时何类型，Ceph都会在存储池中将所有的数据存储为对象
Ceph用户需要拥有存储池访问权限才能读取和写入数据
Ceph用户必须拥有执行全年才能使用Ceph管理命令
相关概念
用户
用户是指个人或系统参与者（例如应用） 通过创建用户，可以控制谁（或哪个参与者）能够访问Ceph存储集群、以及可访问的存储池及存储池中的数据。 Ceph支持多种类型的用户，单可管理的用户都属于Client类型 区分用户种类的原因在于，mon、osd、mds等系统组件也使用cephx协议，但它们非为客户端 通过点号来分隔用户类型和用户名，格式为TYPE.ID，例如：client.admin等 授权
使能（Capabilities）
Ceph基于&amp;quot;使能(caps)&amp;ldquo;来描述用户可针对MON、OSD或MDS使用的权限范围或级别。 通用语法格式：daemon-type&#39;allow caps[...] MON使能 包括r、w、x和allow profile cap 例如：mon allow rwx，以及mon allow profile osd&amp;rsquo;等。 OSD使能 包括r、w、x、class-read、class-write和profile osd 此外，OSD使能还允许进行存储池和名称空间设置。如为指定表示对所有OSD所有存储池都获得相关授权 MDS使能 只需要allow，或留空 各使能的意义
allow
需先于守护进程的访问设置指定 仅对MDS表示rw之意，其它的表示字面意义 r：读取权限，访问MON以检索CRUSH时依赖此使能
w：对象写入权限
x：调用类方法（读取和写入）的能力，以及在MON上执行auth操作的能力。
class-read：x能力的子集，授予用户调用类读取方法的能力
class-write：x的子集，授予用户调用类写入方法的能力
·*：授予用户对特定守护进程/存储池的读取、写入和执行权限，以及执行管理命令的能力。
profile osd
授予用户以某个OSD身份连接到其他OSD或监视器的权限 授予OSD权限，使OSD能够处理复制检测信号流量和状态报告 profile mds
授予用户以某个MDS身份连接到其他MDS或监视器的权限 profile bootstrap-osd</description>
    </item>
    <item>
      <title>Ceph概念 - 初识Ceph</title>
      <link>https://www.oomkill.com/ch01-1-ceph-acquaintance/</link>
      <pubDate>Sun, 30 Jun 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch01-1-ceph-acquaintance/</guid>
      <description>初识Ceph Ceph 是一个开源分布式存储系统系统，它不是一种单一的存储，而是面向云提供一种统一存储平台，包含块存储 RBD, 文件存储 CephFS, 以及对象存储 RGW，这种存储的出现允许用户拜托供应商的绑定，它可以提供块存储到 “云平台”，也可以提供对象存储到 “应用”，并支持理论上的无限扩展性，数千客户端访问 PB 甚至 EB 级别的数据
SAN VS Ceph 与传统 SAN 存储相比，Ceph 客户端会计算他们所需的数据所在的位置，这消除了存储系统中需要在“中心化查找”的瓶颈。 这使得 Ceph 集群可以在不损失性能的情况下进行扩展。
Ceph 集群架构组成 Ceph 集群核心是 RADOS，而基于 RADOS，构建出多种类型存储，块存储, 文件系统, 对象存储，而一个基础的 Ceph 集群的组件由 &amp;ldquo;Ceph monitor&amp;rdquo; 与 &amp;ldquo;Ceph OSD Daemon&amp;rdquo; 组成
Ceph Monitor（进程名称为 ceph-mon，下文中以 ceph-mon 代表 Ceph Monitor） 维护集群映射的主副本。 ceph集群中的monitor，可确保 ceph-mon 守护进程在失败时的高可用性。客户端从 ceph-mon 检索集群映射的副本。 Ceph OSD Daemon 检查”自身“及”其他“ OSD 的状态并报告给 Monitor。 Ceph 中的常见术语 Application 用于使用 Ceph 集群的任何 Ceph 外部的应用程序
Block Device 也称为 “RADOS 块设备” 或 ”RBD“ ，协调基于块的数据存储的工具，Ceph块设备拆分基于块的应用程序数据 成“块”。 RADOS 将这些块存储为对象。 Ceph 块 设备协调这些对象的存储 存储集群。</description>
    </item>
    <item>
      <title>Ceph算法 - crush</title>
      <link>https://www.oomkill.com/ch08-1-ceph-crush/</link>
      <pubDate>Sun, 30 Jun 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch08-1-ceph-crush/</guid>
      <description>关于存储池 从某种意义上来讲，RADOS所提供的存储空间的管理接口，不应该将其放置在同一个平面当中，因此将其切割成多个不同的&amp;quot;逻辑存储空间&amp;quot;，称之为存储池。
RADOS存储集群提供的基础存储服务需要由&amp;quot;存储池（pool）&amp;ldquo;分割为逻辑存储区域，此类的逻辑区域亦是对象数据的名称空间。
实践中，管理员可以为特定的应用程序存储不同类型数据的需求分别创建专用的存储池，例如rbd存储池，rgw存储池等，也可以为某个项目或某个用户创建专有的存储池。 存储池还可以再进一步细分为一至多个名称空间（namespace）。同一个存储池内，无论属于哪个、哪些名称空间，数据都是被存储池中的PG进行存放，虽然处于不同名称空间，但可能处于同一个PG之上。 客户端(包括rbd和rgw等）存取数据时，需要事先指定存储池名称、用户名和密钥等信息完成认证，而后将一直维持与其指定的存储池的连接，于是也可以吧存储池看做是客户端的IO接口。 存储池类型
副本池（replicated）：任何一个数据对象存储在此类存储池中其冗余机制是通过创建多个数据对象副本来实现的，而副本数量是用户在创建存储池时指定。如，创建存储池时没指定类型，就是副本池，默认副本数量为3个（1主两从），统称副本数量。把每个对象在集群中存储为多个副本，其中存储于主OSD的为主副本，副本数量在创建存储池时由管理员指定；副本池类型为Ceph为默认的存储池类型。但是此存储池是非常浪费存储空间的。副本池对读IO有很好的附带表现 纠删码池（erasure code）：使用校验码可计算回数据。把各对象存储为N=K+M个块，其中，K为数据块数量，M为编码块数量，因此存储池的尺寸为K+M；纠删码块的数据就 是允许冗余的级别。如4+2，即允许最多两个数据块丢失。不是所有的应有都能支持纠删码池，如rbd必须使用副本池。radosGW可以使用纠删码池。 副本池IO
将一个数据对象存储为多副本 写入操作时，Ceph客户端使用CRUSH算法来计算对象的PG ID和Primary OSD 主OSD根据设定的副本教、对象的名称、存储池名称和集群运行图（Cluster Map）计算出PG的各铺助OSD，而后由主OSD将数据同步给这些辅助OSD。 对于有着三个副本的存储池来讲，任何一个PG都会选择三个OSD，因此，副本池所关联的OSD数量通常与冗余量相同。OSD，成为一个活动集。如图所示，其中一个OSD为主OSD负责读写操作，另外两个OSD负责从主OSD同步数据。当三个副本都存完，才能的到存储完成的消息的。客户的只需与主OSD通信，同步过程是OSD内部自行实现的。
纠删码池IO
纠删码是一种前向纠错码（FEC）代码
通过将K块的数据转换为N块，假设N=K+M，则其中的M代表纠删码算法添加的额外活冗余的块数量以提供冗余机制（即编码块），而N则表示在纠删码编码之后要创建的块的总数，其可以故障的块数为M（即N-K）个。 类似于RAID5 纠删码池减少了确保数据持久性所需的磁盘空间量，但计算量上却比副本存储池要更贵一些 RGW可以使用纠删码池，但RDB不支持。
例如，把包含数据ABCDEFGHI的对象NYAN保存到存储池中，假设纠删码算法会将内容分割为三个数据块：第一个包含ABC，第二个为DEF，最后一个为GHI，并为这三个数据块额外创建两个编码块：第四个YXY和第五个GQC，此时纠删码算法会通过计算哪家出GHI、和YXY
副本池所有从OSD没有次序之分，只有主和从两类角色之分，各个从没有次序。纠删码池是有次序的，这个顺序代表数据拼凑起来的数据。因此，每个分片应指定其在整个数据文件的偏移量是多少。
归置组 归置组（PlacementGroup）是用于跨OSD将数据存储在某个存储池中的内部数据结构。
相对于存储池来说，PG是一个虚拟组件，它是对象映射到存储池时使用的虚拟的层 出于规模伸缩及性能方面的考虑，Ceph将存储池细分为归置组，吧每个单独的对象映射到归置组，并将归置组分配给一个主OSD 存储池由一系列的归置组组成，而CRUSH算法则根据集群运行图和集群状态，将各PG均匀、伪随机地分布到急群众的OSD之上。 若某OSD失败或需要对集群进行重新平衡，Ceph则移动或复制整个归置组而无需单独寻址每个对象。 归置组在OSD守护进程和Ceph客户端之间生成了一个中间层，CRUSH算法负责将每个对象动态映射到一个归置组，然后再将每个归置组动态映射到一个或多个OSD守护进程，从而能够支持在新的OSD设备上线时动态进行数据重新平衡。
归置组作用
在存储池中存放100w数据对象，而使用100个归置组，一组内存放1w对象。归置组是从新平衡和恢复时的基本单元。使得数据单元不至于以文件或对象为单位。
归置组计数 归置组的数量有管理员在创建存储池是指定，而后由crush负责创建和使用
通常，PG的数量应该是数据的合理粒度的子集 例如，一个包含256个PG的存储池意味着每个PG包含大约1/256的存储池数据 当需要将PG从一个OSD移动到另一个OSD时，PG的数量会对性能产生影响 PG数量过少，Ceph将不得不同时移动相当数量的数据，其产生的网络负载将对集群的正常性能输出产生负面影响。 而在过多的PG数量场景中在移动极少量的数据时，Ceph将会占用过多的CPU和RAM，从而对集群的计算资源产生负面影响。 PG数量在集群分发数据和重新平衡时扮演着重要作用 在所有OSD之间进行数据持久存储及完成数据分布会需要较多的归置组，但是它们的数量应该减少到最大性能所需的最小数量值，以节省CPU和内存资源 一般说来，对于有着超过50个OSD的RADOS集群，建议每个OSD大约有50-100个PG以平衡资源使用，取的更好的数据持久性和数据分布，更大规模的集群中，每个OSD大约可持有100-200个PG 至少应该使用多少个PG，可通过下面的公式计算后，将其值以类似于四舍五入到最近的2的N次幂 (Total OSDs * PGPerOSD/Replication factor =&amp;gt; Total PGs ) 可以使用的PG数量 = 总OSD数量* 每个OSD可以有多少个PG/复制因子（副本数量） 一个RADOS集群上可能会存在多个存储池，因此管理员还需要考虑所有存储池上的PG分布后每个OSD需要映射的PG数量 PG数量一定是2的N次方倍，这样进行hash计算时，速度才会更快。Ceph要求每一个OSD上最多不能超过256个PG 归置组状态 依据PG当前的工作特性活工作进程所阶段，它总是处于某个活某些个“状态中”，最常见的状态应该为active+clean
PG的常见状态
Active 主OSD和各辅助OSD均处于就绪状态，可正常服务于客户端IO请求 一般Peering操作过程完成后即会转入Active状态 Clean 主OSD和各辅助OSD均处于就绪状态，所有对象的副本数量均符合期望，并且PG的活动集和上行集为同一组OSD。 活动集(Acting Set)：由PG当前的主OSD和所有的处于活动状态的辅助OSD组成，这组OSD负责执行此PG上数据对象的存取操作I/O 上行集(Up Set)，根据CRUSH的工作方式，集群拓扑架构的变动将可能导致PG相应的OSD变动活扩展至其他的OSD之上，这个新的OSD集也成为PG的“（Up Set）”，其映射到的新OSD集可能不分地与原有OSD集重合，也可能会完全不相干；上行集OSD需要从当前的活动集OSD上复制数据对象，在所有对象同步完成后，上行集便成为新的活动集，而PG也将转为“活动（active）”状态。 Peering 如数据不一致，需将数据复制过去，这个复制数据过程就称之为对等过程。 一个PG中的所有OSD必须就它们持有的数据对象状态达成一致，而“对等（Peering）”即为其OSD从不一致转为一致的过程。 Degraded 在某OSD标记为“down”时，所有映射到此OSD的PG即转入“降级（degraded）”状态 此OSD重新启动并完成Perring操作后，PG将重新转回clean 一旦OSD标记为down的时间超过5分钟，它将被标记出集群，而后Ceph将对降级状态的PG启动回复操作，直到所有因此而降级的PG重回clean状态 在其内部OSD上某对象不可用活悄然崩溃时，PG也会被标记为降级状态，知道对象从某个权威副本上正确恢复。 Stale 过期 每个OSD都要周期性的向RADOS集群中的监视器报告其作为主OSD所持有的所有PG的最新统计数据，因任何原因导致某个主OSD无法正常向监视器发送此类报告，或者由其他OSD报告某个OSD已经down掉，则所有以此OSD的PG将立刻被标记为stale状态。 Undersized PG中的副本数少于其存储池定义的个数时即转入undersized状态，回复和回填操作在随后会启动已修复其副本为期望值 Scrubbing 一致性保障的非常重要机制，文件完整性检查 各OSD还需要周期性的检查其所持有的数据对象的完整性，以确保所有对等OSD上的数据一致；处于此类检查过程中的PG便会被标记为scrubbing状态，这也通常被称作light scrubs、shallow scrubs或者simply scrubs。 另外，PG还需偶尔需要进行deep scrubs检查以确保同一对象在相关的各OSD上能按位匹配，此时PG将处于scrubbing+deep状态。 Recovering 恢复 添加一个新的OSD至存储集群中或某OSD宕掉时，PG则由可能会被CRUSH重新映射进而将持有与此不同的OSD集，而这些处于内部数据同步过程中的PG则被标记为recovering状态； Backfilling 回填 新OSD加入存储集群后，Ceph则会进入数据重新均衡的状态，即一些数据对象会在进程后台从现有OSD移到新的OSD之上，此操作过程为backfill。 CRUSH 把对象直接映射到OSD之上会导致二者之间的紧密耦合关系，变动底层OSD就会牵一发而动全身，因此在OSD设备变动时不可避免地对整个集群产生扰动</description>
    </item>
    <item>
      <title>Cloud基础设施 - 初识Ceph</title>
      <link>https://www.oomkill.com/ch01-2-cloud-base/</link>
      <pubDate>Sun, 30 Jun 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch01-2-cloud-base/</guid>
      <description>初识Ceph Ceph 是一个开源分布式存储系统系统，它不是一种单一的存储，而是面向云提供一种统一存储平台，包含块存储 RBD, 文件存储 CephFS, 以及对象存储 RGW，这种存储的出现允许用户拜托供应商的绑定，它可以提供块存储到 “云平台”，也可以提供对象存储到 “应用”，并支持理论上的无限扩展性，数千客户端访问 PB 甚至 EB 级别的数据
SAN VS Ceph 与传统 SAN 存储相比，Ceph 客户端会计算他们所需的数据所在的位置，这消除了存储系统中需要在“中心化查找”的瓶颈。 这使得 Ceph 集群可以在不损失性能的情况下进行扩展。
Ceph 集群架构组成 Ceph 集群核心是 RADOS，而基于 RADOS，构建出多种类型存储，块存储, 文件系统, 对象存储，而一个基础的 Ceph 集群的组件由 &amp;ldquo;Ceph monitor&amp;rdquo; 与 &amp;ldquo;Ceph OSD Daemon&amp;rdquo; 组成
Ceph Monitor（进程名称为 ceph-mon，下文中以 ceph-mon 代表 Ceph Monitor） 维护集群映射的主副本。 ceph集群中的monitor，可确保 ceph-mon 守护进程在失败时的高可用性。客户端从 ceph-mon 检索集群映射的副本。 Ceph OSD Daemon 检查”自身“及”其他“ OSD 的状态并报告给 Monitor。 Ceph 中的常见术语 Application 用于使用 Ceph 集群的任何 Ceph 外部的应用程序
Block Device 也称为 “RADOS 块设备” 或 ”RBD“ ，协调基于块的数据存储的工具，Ceph块设备拆分基于块的应用程序数据 成“块”。 RADOS 将这些块存储为对象。 Ceph 块 设备协调这些对象的存储 存储集群。</description>
    </item>
    <item>
      <title>prometheus golang_client开发Exporter</title>
      <link>https://www.oomkill.com/prometheus-golang_client/</link>
      <pubDate>Sun, 02 Jun 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/prometheus-golang_client/</guid>
      <description>exporter是一个独立运行的采集程序，其中的功能需要有这三部分
自身是HTTP服务器，可以相应从外部发过来的HTTP GET请求。 自身需要运行在后台，并可以定期触发抓取本地的监控数据。 返回给prometheus_server的内容是要符合prometheus规定的metrics类型的key-Value promethes监控中对于采集过来的数据统一称为metrice数据
Metrics，为某个系统某个服务做监控、做统计，就需要用到Metrics.
metrics是一种对采样数掘的总称（metrics并不代表某一种具体的数据格式是一种对于度星计算单位的抽象）
metrics的几种主要的类型
METRIC TYPES prometheus客户端库提供4中metric类型
counter 计数器，累加指标 gauge 测量指标 summary 概略 histogram 直方图 counter Counter计数器，累加的指标数据，随时间逐步增加，如程序运行次数、运行错误发生总数。如网卡流量，代表持续增加的数据包或者传输字节的累加值
比如对用户访问量的采样数据
我们的产品被用户访问一次就是1过了10分钟后积累到100
过一天后累积到20000
一周后积累到100000-150000
go 1 2 3 4 5 6 7 8 test = prometheus.NewSummaryVec( prometheus.SummaryOpts{ Name: &amp;#34;zhangsan&amp;#34;, Help: &amp;#34;username&amp;#34;, Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, }, []string{&amp;#34;service&amp;#34;}, ) text 1 2 3 4 5 6 7 # HELP zhangsan username # TYPE zhangsan summary zhangsan{service=&amp;#34;aaa&amp;#34;,quantile=&amp;#34;0.5&amp;#34;} 0.</description>
    </item>
    <item>
      <title>ubuntu相关配置</title>
      <link>https://www.oomkill.com/ubuntu-configration/</link>
      <pubDate>Thu, 25 Apr 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ubuntu-configration/</guid>
      <description>Ubuntu屏幕分辨率无1920 1080 xrandr
没有1920X1080分辨率，所以手动添加一个1080P分辨率，先输入“cvt 1920 1080”命令，查询一下1080P分辨率的有效扫描频率
然后使用 xrandr 命令新建一种输出分辨率
bash 1 sudo xrandr --newmode &amp;#34;1920x1080_60.00&amp;#34; 173.00 1920 2048 2248 2576 10801083 1088 1120 -hsync +vsync bash 1 sudo xrandr --addmode Virtual1 &amp;#34;1920x1080_60.00&amp;#34; Ubuntu 制作图标 进入 /usr/share/applications/下 创建文件
bash 1 2 3 4 5 6 7 8 9 cylon@cylon-PC:/usr/share/applications$ cat goland.desktop [Desktop Entry] Encoding=UTF-8 Name=Goland Exec=goland.sh Icon=/home/lc/goland/bin/goland.svg Terminal=false Type=Application Categories=Development; 主题目录： /usr/share/themes/
图标主题目录： /usr/share/icons/</description>
    </item>
    <item>
      <title>deepin下安装goland中文字体显示全是方块</title>
      <link>https://www.oomkill.com/deepin-goland/</link>
      <pubDate>Fri, 19 Apr 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/deepin-goland/</guid>
      <description>下载中文字体
bash 1 apt-get install ttf-arphic-uming xfonts-intl-chinese 替换goland的汉化包，两个jar包。</description>
    </item>
    <item>
      <title>prometheus传统架构安装</title>
      <link>https://www.oomkill.com/prometheus-install/</link>
      <pubDate>Tue, 02 Apr 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/prometheus-install/</guid>
      <description>全局配置选项
text 1 2 3 4 5 6 7 scrape_interval: 采集生命周期 scrape_timeout: 采集超时时间 evaluation_interval: 告警评估周期 rule_files 监控告警规则 scrape_config: 被监控端 altering 检查配置文件语法
text 1 2 3 $ promtool check config \etc\prometheus.yml Checking \etc\prometheus.yml SUCCESS: 0 rule files found 100 - (node_memory_MemFree_bytes+node_memory_Cached_bytes+node_memory_Buffers_bytes) \ node_memory_MemTotal_bytes * 100
计算剩余空间
node_filesystem_free_bytes{mountpoint=&amp;quot;&amp;quot;,fstype=~&amp;ldquo;ext4|xfs&amp;rdquo;} \ node_filesystem_size_bytes{mountpoint=&amp;quot;&amp;quot;,fstype=~&amp;ldquo;ext4|xfs&amp;rdquo;} * 100
查看使用的百分比
100-node_filesystem_free_bytes{mountpoint=&amp;quot;&amp;quot;,fstype=~&amp;ldquo;ext4|xfs&amp;rdquo;} \ node_filesystem_size_bytes{mountpoint=&amp;quot;&amp;quot;,fstype=~&amp;ldquo;ext4|xfs&amp;rdquo;} * 100
prometheus使用influxdb [Prometheus endpoints support in InfluxDB | InfluxData Documentation](https:\docs.influxdata.com\influxdb\v1.7\supported_protocols\prometheus)
[Configuration | Prometheus](https:\prometheus.io\docs\prometheus\latest\configuration\configuration)
配置文件参考
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 global: alerting: alertmanagers: - static_configs: - targets: rule_files: scrape_configs: - job_name: &amp;#39;prometheus1&amp;#39; file_sd_configs: - files: [&amp;#39;\data\sd_config\test.</description>
    </item>
    <item>
      <title>Go每日一库 - cobra</title>
      <link>https://www.oomkill.com/go-cobra/</link>
      <pubDate>Thu, 07 Mar 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-cobra/</guid>
      <description>Cobra功能 简单子命令cli 如 kubectl verion kubectl get
自动识别-h，&amp;ndash;help 帮助
更过参考官方手册：https://github.com/spf13/cobra
kubectl get pod --all-namespaces
get 代表命令（command） pod 代表事务（args） --all-namespaces 代表标识（flag） command 代表动作， Args 代表事务， flags 代表动作的修饰符。 使用Cobra 使用cobra需要main.go或和cmd/cmd.go(非固定，根据官方手册说明操作的)，来创建需要添加的命令。
cobra不需要构造函数，只需要创建命令即可
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 rootCmd = &amp;amp;cobra.Command{ Use: &amp;#34;db &amp;#34;, Short: &amp;#34;test1&amp;#34;, Long: `this is a test123`, Run: func(cmd *cobra.Command, args []string) { log.Println(cfgFile, port) }, } func Execute() { if err := rootCmd.</description>
    </item>
    <item>
      <title>Go每日一库 - cronexpr</title>
      <link>https://www.oomkill.com/cronexpr/</link>
      <pubDate>Thu, 14 Feb 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/cronexpr/</guid>
      <description>包获取：go get -u github.com/gorhill/cronexpr
创建一个定时任务
go 1 expr, err = cron.Parse(&amp;#34;* * * * *&amp;#34;); 获得任务的下次执行时间
go 1 nextTime = expr.Next(now) 完整代码
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 package main import ( &amp;#34;fmt&amp;#34; &amp;#34;time&amp;#34; cron &amp;#34;github.</description>
    </item>
    <item>
      <title>使用二进制文件构建k8s集群</title>
      <link>https://www.oomkill.com/kubernetes-install-with-binary-files/</link>
      <pubDate>Sun, 20 Jan 2019 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-install-with-binary-files/</guid>
      <description>Kubernetes集群的构成 Master Node (Control plane) Master 是整个 Kubernetes 集群构成的基础，它负责整个集群的管理，例如处理集群的状态；组件包含 API Server, Controller manager, Scheduller, Etcd
API server API 服务器是 Master 的统一前端入口，负责集群内其他组件的 协调 与 通信。该组件用于定义集群的状态。可以通过命令行, HTTP API, 第三方托管平台（dashboard, Rancker, Kuboard等）与 Kubernetes API 进行交互。
Scheduler 调度程序 Scheduler 负责根据可用资源来决定如何去部署容器，部署到哪里？确保所有 Pod（容器组）都分配给某一组节点。
Controller Manager Controller manager，又分为Controller 和 Manager，Controller的组要作用是用于协调各种控制器(Deployment, Daemonset&amp;hellip;)，这些控制器可确保在节点发生故障时采取适当的措施。而 Manager 则管理的众多Controller；更一般地说，CM 负责随时将集群的当前状态调整到所需状态（Kubernetes设计基石）。
etcd etcd 是控制平面内的一个组件，他提供了 Kubernetes 资源的存储，并为集群内组件提供了 Watch 的功能，这将意味着，etcd 在 kubernetes 集群中作为存储与分布式协调的功能。
Worker nodes 每个集群中至少需要存在一个工作节点，但是通常会有大量的节点；而工作节点包括的组件不限于 Kubelet, Kube-proxy, CNI Plugin。
Kubelet kubelet是工作节点中管理运行时的组件，负责整个Pod （容器组）进程的生命周期
Kube-proxy Kube-proxy 为整个集群内提供了 service 的功能，如果这个组件无法正常工作，那么整个集群内的网络通信将不能正常，因为 service 是作为集群内服务的访问入口，包含 Kubernetes API service。</description>
    </item>
    <item>
      <title>Go byte与rune区别</title>
      <link>https://www.oomkill.com/golang-byte-and-rune/</link>
      <pubDate>Wed, 12 Dec 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/golang-byte-and-rune/</guid>
      <description>先看代码
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package main import ( &amp;#34;fmt&amp;#34; ) func main() { var a = &amp;#34;hello world&amp;#34; var b = &amp;#34;中&amp;#34; fmt.Println([]rune(a)) fmt.Println([]rune(b)) fmt.Println([]byte(b)) } go源码中的定义
go 1 2 3 4 5 6 7 8 // byte is an alias for uint8 and is equivalent to uint8 in all ways. It is // used, by convention, to distinguish byte values from 8-bit unsigned // integer values.</description>
    </item>
    <item>
      <title>Go每日一库 - bufio缓冲区的终端输入</title>
      <link>https://www.oomkill.com/go-bufio/</link>
      <pubDate>Tue, 27 Nov 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-bufio/</guid>
      <description>bufio包实现了有缓冲的I/O。它包装一个io.Reader或io.Writer接口对象，os.stdin就是实现了这个接口
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package main import ( &amp;#34;bufio&amp;#34; &amp;#34;fmt&amp;#34; &amp;#34;os&amp;#34; ) var buff *bufio.Reader func main() { buff = bufio.NewReader(os.Stdin) str, err := buff.ReadString(&amp;#39;\n&amp;#39;) if err == nil { fmt.Printf(&amp;#34;input was :%s&amp;#34;, str) } } ReadString(byte) 遇到byte后返回，包含已读到的和byte，如果在读到之前遇到错误，返回读取的信息及该错误
在写文件时。可以写入缓冲区来可以提升磁盘性能</description>
    </item>
    <item>
      <title>etcd二进制安装与配置</title>
      <link>https://www.oomkill.com/etcd-install-bin/</link>
      <pubDate>Tue, 20 Nov 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/etcd-install-bin/</guid>
      <description>概述 etcd 是兼具一致性和高可用性的键值数据库，为云原生架构中重要的基础组件，由CNCF 孵化托管。etcd 在微服务和 Kubernates 集群中不仅可以作为服务注册与发现，还可以作为 key-value 存储的中间件。
先决条件 运行的 etcd 集群个数成员为奇数。 etcd 是一个 leader-based 分布式系统。确保主节点定期向所有从节点发送心跳，以保持集群稳定。 保持稳定的 etcd 集群对 Kubernetes 集群的稳定性至关重要。因此，请在专用机器或隔离环境上运行 etcd 集群，以满足所需资源需求]。 确保不发生资源不足。
集群的性能和稳定性对网络和磁盘 IO 非常敏感。任何资源匮乏都会导致心跳超时，从而导致集群的不稳定。不稳定的情况表明没有选出任何主节点。在这种情况下，集群不能对其当前状态进行任何更改，这意味着不能调度新的 pod。 相关术语 Raft：etcd所采用的保证分布式系统强一致性的算法。 Node：节点 ，Raft状态机的一个实例，具有唯一标识。 Member： 成员，一个etcd实例。承载一个Node，且可为客户端请求提供服务。 Cluster：集群，由多个Member构成可以协同工作的etcd集群。 Peer：同伴，Cluster中其他成员。 Proposal ：提议，一个需要完成 raft 协议的请求(例如写请求，配置修改请求)。 Client： 向etcd集群发送HTTP请求的客户端。 WAL：预写式日志，etcd用于持久化存储的日志格式。 snapshot：etcd防止WAL文件过多而设置的快照，存储etcd数据状态。 Proxy：etcd的一种模式，为etcd集群提供反向代理服务。 Leader：Raft算法中通过竞选而产生的处理所有数据提交的节点。 Follower：竞选失败的节点作为Raft中的从属节点，为算法提供强一致性保证。 Candidate：当Follower超过一定时间接收不到Leader的心跳时转变为Candidate开始竞选。 Term：某个节点成为Leader到下一次竞选时间，称为Ubuntu一个Term。 Index：数据项编号。Raft中通过Term和Index来定位数据。 ETCD 部署 源码安装 基于master分支构建etcd
bash 1 2 3 git clone https://github.com/etcd-io/etcd.git cd etcd ./build # 如脚本格式为dos的，需要将其格式修改为unix，否则报错。 启动命令
--listen-client-urls 于 --listen-peer-urls 不能为域名</description>
    </item>
    <item>
      <title>elasticsearch安装</title>
      <link>https://www.oomkill.com/es/</link>
      <pubDate>Fri, 02 Nov 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/es/</guid>
      <description>1 elasticsearch介绍 ES是一个基于Lucene实现的开源、分布式、基于Restful风格的全文本搜索引擎；此外，它还是一个分布式实时文档存储，其中每个文档的每个field均是被索引的数据，且可被搜索：也是一个带实时分析功能的分布式搜索引擎，能够扩展至数以百计的节点实时处理PB级的数据。
1.1 elasticsearch基本组件 索引（index）：文档容器，换句话说，索引是具有类似属性的文档的集合。类似于表。索引名必须使用小写字母：
类型（type）：类型是索引内部的逻辑分区，其意义完全取决于用户需求。一个索引内部可定义一个或多个类型。一般来说，类型就是拥有相同的域的文档的预定义。
文档（document）：文档是Lucene索引和搜索的原子单位，它包含了一个或多个域。是域的容器：基于J50N格式表示。每个域的组成部分：一个名字，一个或多个值；拥有多个值的域，通常称为多值域：
映射（mapping）：原始内容存储为文档之前需要事先进行分析，例如切词、过滤掉某些词等：映射用于定义此分析机制该如何实现；除此之外，ES还为映射提供了诸如将域中的内容排序等功能。
1.2 es的集群组件 cluster: es的集群标识为集群名称：默认“elasticsearch”。节点就是靠此名字来决定加入到哪个集群中。一个节点只能属性于一个集群。
Node：运行了单个es实例的主机即为节点。用于存储数据、参与集群索引及搜索操作。节点的标识靠节点名。
Shard：将索引切割成为的物理存储组件：但每一个shard都是一个独立且完整的索引；创建索引时，ES默认将其分割为5个shard，用户也可以按需自定义，创建完成之后不可修改。
shard有两种类型：primary shard和replica。replica用于数据冗余及查询时的负载均衡。每个主shard的副本数量可自定义，且可动态修改。
1.3 es的工作过程 es节点启动时默认通过多播方式或单播方式在TCP协议的9300端口查找同一集群中的其他节点，并与之建立通讯。判断是否为同一集群的标准为集群名称，集群中的所有节点会选举出一个主节点负责管理整个集群状态，以及在集群范围内决定各shared的分布方式。站在用户使用中角度而言，每个节点都可以接收并相应各类请求，无需区分哪个为主节点。
当集群中某一节点为down状态时，主节点会读取集群状态信息，并启动修复过程。此过程中主节点会检查所有可用shared的主shared，并确定主shared是否存在。各种shared及对应副本shared是否对数。此时集群状态会转换为yellow。
es集群有三种状态：green、red（不可用）、yellow（修复状态）。
当某状态为down的节点上存在主shared，此时需要从各副本shared中找一个提升为主shared。在yellow状态时，各副本shared均处于未分配模式。此时各个副本都不可用，只能使用主shared。集群虽可基于各组shared进行查询，但此时吞吐能力有限。yellows属于残破不全状态。
接下来的过程中，主节点将会查找所有的冗余shard，并将其配置为主shared。如果某shared的副本数量少于配置参数的数量，会自动启动复制过程，并为其建立副本shared。直至所有条件都满足从yellow转换至green。
es工作过程中主节点会周期性检查各节点是否处于可用状态，任意节点不可用时，修复模式都会启动，此时集群将会进入重新均衡过程。
2 安装elasticsearch 下载地址：http://www.elastic.co/cn/downloads/elasticsearch
官方文档中写明对es每个版本对jdk的要求。
https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
2.1 常用es配置文件说明 修改配置文件：/etc/elasticsearch/elasticsearch.yml
sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 cluster.</description>
    </item>
    <item>
      <title>ELK收集java日志</title>
      <link>https://www.oomkill.com/elk-collect-java/</link>
      <pubDate>Fri, 02 Nov 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/elk-collect-java/</guid>
      <description>Java日志多由多行行组成，初始行之后的每一行以空格开头，如下例所示：在这种情况下，需要在将事件数据output之前处理多行事件。
text 1 2 3 4 5 [ERROR] - 2018-09-21 04:19:57.685 (SocketTransfer.java:73) - Socket交互遇到错误 Exception in thread &amp;#34;main&amp;#34; java.lang.NullPointerException at com.example.myproject.Book.getTitle(Book.java:16) at com.example.myproject.Author.getBookTitles(Author.java:25) at com.example.myproject.Bootstrap.main(Bootstrap.java:14) 配置multiline参数如下：Multiline codec plugin
参数 说明 pattern 指定正则表达式。与指定正则表达式匹配的行被视为前一行的延续或新多行事件的开始。 what previous或next。该previous值指定与pattern选项中的值匹配的行是上一行的一部分。该next值指定与pattern选项中的值匹配的行是以下行的一部分 negate true或false（默认为false）。如果true，与pattern模式不匹配的消息将构成多行过滤器的匹配what并将应用。 sh 1 2 3 4 5 6 7 8 9 10 11 12 input { file { path =&amp;gt; &amp;#34;/root/apache-tomcat-8.5.34/logs/catalina.out&amp;#34; type =&amp;gt; &amp;#34;sk&amp;#34; start_position =&amp;gt; &amp;#34;beginning&amp;#34; codec =&amp;gt; multiline { pattern =&amp;gt; &amp;#34;^\[&amp;#34; negate =&amp;gt; &amp;#34;true&amp;#34; what =&amp;gt; &amp;#34;previous&amp;#34; } } } 如上列日志格式为</description>
    </item>
    <item>
      <title>ELK收集syslog</title>
      <link>https://www.oomkill.com/collect-syslog/</link>
      <pubDate>Fri, 02 Nov 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/collect-syslog/</guid>
      <description>Logstash通过网络将syslog消息作为事件读取。使用用 UDPSocket, TCPServer 和
LogStash::Filters::Grok 来实现
配置示例 sh 1 2 3 4 5 input { syslog{ port =&amp;gt; &amp;#34;514&amp;#34; } } 配置客户端，在修改linux主机/etc/rsyslog.conf
sh 1 *.* @@host:port 配置说明 参数 说明 * 类型 * 级别 @ udp @@ tcp host 可为主机名或ip地址 注：收集到的数据，本身就以及是rsyslog格式了，无需再进行grok
sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 { &amp;#34;message&amp;#34; =&amp;gt; &amp;#34;(root) CMD (/bin/echo 1111 &amp;gt;&amp;gt;/root/1.txt)\n&amp;#34;, &amp;#34;@version&amp;#34; =&amp;gt; &amp;#34;1&amp;#34;, &amp;#34;@timestamp&amp;#34; =&amp;gt; &amp;#34;2018-10-05T12:13:01.000Z&amp;#34;, &amp;#34;host&amp;#34; =&amp;gt; &amp;#34;10.</description>
    </item>
    <item>
      <title>jenkins pipeline docker方式</title>
      <link>https://www.oomkill.com/jenkins-docker/</link>
      <pubDate>Fri, 02 Nov 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/jenkins-docker/</guid>
      <description>pipline def timestr() { script { return sh(script: &amp;#39;date +%Y%m%d%H%M%S&amp;#39;, returnStdout: true).trim()}}def dockerImagepipeline{agent anyenvironment {time = timestr()registry = &amp;#34;xxx.com/payapp-test&amp;#34;registryhub = &amp;#34;txhub.xxx.com&amp;#34;appName = &amp;#34;api&amp;#34;}options {timeout(time: 1, unit: &amp;#39;HOURS&amp;#39;)buildDiscarder(logRotator(numToKeepStr: &amp;#39;15&amp;#39;))disableConcurrentBuilds()}stages{stage(&amp;#34;Pull Code&amp;#34;){steps{git branch: &amp;#39;testing&amp;#39;, credentialsId: &amp;#39;422fb2c7-4d58-440a-98a4-e242b66f3800&amp;#39;, url: &amp;#39;http://gitlab.fgry45iy.com:90/pay/payGateway.git&amp;#39;}}stage(&amp;#34;Maven Package&amp;#34;){steps{withEnv([&amp;#39;PATH+EXTRA=/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/apache-maven-3.6.2/bin:/usr/local/maven/bin:/root/bin&amp;#39;]) {sh &amp;#34;mvn package&amp;#34;}}}// stage(&amp;#39;Building Image&amp;#39;) {// steps{// script {// dockerImage = docker.</description>
    </item>
    <item>
      <title>Logstash使用</title>
      <link>https://www.oomkill.com/logstash/</link>
      <pubDate>Fri, 02 Nov 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/logstash/</guid>
      <description>1 logstash概述 logstash是基于Jruby语言研发的server/agent结构的日志收集工具，可以在任何一个能产生日志的服务器上部署其agent。agent能同时监控多个产生日志的服务，并把每个服务所产生的日志信息收集并发送给logstash server端。由于收集到的日志信息是分散的，logstash有专门的节点用来将所有的节点收集到的日志信息按时间序列合并在一起形成一个序列，基于这一个序列请求写入并存储在elasticsearch集群中。
kibana是基于node.js开发的elasticsearch的图形用户接口。它可以将用户的搜索语句发送给ES，有ES完成搜索，并且将结果返回。kibana可以将返回的数据，用非常直观的方式（画图）来做趋势展示的。
logstash基于多种数据获取机制，TCP/UDP协议、文件、syslog、windows EventLogs及STDIN等。同时也支持多种数据输出机制。获取到数据后，它支持对数据执行过滤、修改等操作。
logstash基于JRuby语言研发，需要运行在JVM虚拟机之上。工作于agent/server模型。
1.1 logstash工作机制 在每一个产生日志的节点之上部署一个agent，这个agent通常称为shipper。shipper负责收集日志，并且发送给server端。但是在发送给server端时，为了避免server端可能无法应付大量节点同时发来的信息，会在server端和agent端之间放置一个消息队列，通常称之为broker。这个消息队列比较常见的使用redis。各agent将数据发送至broker，logstash服务器会从broker中依次取出日志拿来在本地做过滤、修改等操作。在完修改后将其发送至ES集群。
对于logstash而言，server端也是插件式的工作的模式，与ES的不同在于，ES的插件是可有可无的。logstash的除核心外的所有功能都是基于插件来完成的。
1.2 logstash工作流程 logstash的工作模式类似于管道，从指定位置读入数据，而后过滤数据，最后将其输出到指定位置。事实上logstash的工作流程为：input | filter | output。如无需对数据额外处理，filter可省略。
1.3 logstash插件分类 input plugin：收集数据 codec plugin：编码插件 filter plugin：过滤 output plugin：输出插件 2 logstash安装下载 官网地址：https://www.elastic.co/cn/products../../images/Logstash
3 logstash的配置使用 /etc../../images/Logstash/conf.d/路径下所有以.conf结尾的文件都被当做配置文件使用。对于logstash的配置文件定义，就是定义插件。从哪得到数据。向哪里输出数据。
3.1 logstash的基本配置框架 sh 1 2 3 4 5 6 7 8 9 10 11 input{ .... } filter{ .... } output{ .... } 简单的
sh 1 2 3 4 5 6 7 8 input{ stdin {} } output { stdout{ codec =&amp;gt;rubydebug } } 检查配置文件语法是否正确logstash -f /etc.</description>
    </item>
    <item>
      <title>Go数组排序算法</title>
      <link>https://www.oomkill.com/go-datasort/</link>
      <pubDate>Wed, 24 Oct 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/go-datasort/</guid>
      <description>冒泡排序 图 https://www.cnblogs.com/onepixel/articles/7674659.html
go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package main import ( &amp;#34;fmt&amp;#34; ) func bubbleSort(slice []int) []int { for n := 0; n &amp;lt;= len(slice); n++ { for i := 1; i &amp;lt; len(slice)-n; i++ { if slice[i] &amp;lt; slice[i-1] { slice[i], slice[i-1] = slice[i-1], slice[i] } } } return slice } func main() { var arr = [.</description>
    </item>
    <item>
      <title>Jenkins在windows平台自动化构建代码</title>
      <link>https://www.oomkill.com/jenkins-in-windows/</link>
      <pubDate>Tue, 02 Oct 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/jenkins-in-windows/</guid>
      <description>Jenkins服务端：centos6.8
客户端：windows server2012 windows10
工具：cwRsync
注：复制为jenkins工作目录到网站目录，无需服务端。
配置安装slave端 所用的插件：Copy Data To Workspace Plugin
配置windows节点 \1. 主界面-&amp;gt;【系统管理】-&amp;gt;【管理节点】-&amp;gt;【新建节点】，进行节点的添加：
\2. 输入节点名称，选择【Permanent Agent】。如果添加过slave的话会出现【复制现有节点】操作
\3. 配置节点的详细信息
此处配置需要注意的有以下几个方面
【# of executors】：建议不要超过CPU核心数，一般不要写特别大。
【远程工作目录】：master将代码库中的代码复制到slave时，存放的临时目录，如slave的daemon服务也会放在此目录。一个job一个文件夹。
【用法】：选择【只允许运行绑定到这台机器的Job】，此模式下，Jenkins只会构建哪些分配到这台机器的Job。这允许一个节点专门保留给某种类型的Job。例如，在Jenkins上连续的执行测试，你可以设置执行者数量为1，那么同一时间就只会有一个构建，一个实行者不会阻止其它构建，其它构建会在另外的节点运行。
【启动方式】：选择【Launch agent via Java Web Start】，以windows服务的方式启动，这个为最好配置的。注意：2.x版本的默认没有这个选项，需要单独开启。
\4. 配置slave端并且添加至windows服务
在点击保存后，在node列表中会存在此列表默认是未连通状态
点击进入详情页面会提示slave端的安装方法，此处讲解下载文件方式。
【Launch】：浏览器下载文件方式
【Run from agent command line】：从远端代理命令运行
注意：这是java服务，每个slave端必须安装jdk后才可运行。
xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 &amp;lt;jnlp codebase=&amp;#34;http://10.0.0.11:8080/jenkins/computer/test/&amp;#34; spec=&amp;#34;1.0+&amp;#34;&amp;gt; &amp;lt;information&amp;gt; &amp;lt;title&amp;gt;Agent for test&amp;lt;/title&amp;gt; &amp;lt;vendor&amp;gt;Jenkins project&amp;lt;/vendor&amp;gt; &amp;lt;homepage href=&amp;#34;https://jenkins-ci.</description>
    </item>
    <item>
      <title>Kubernetes存储卷</title>
      <link>https://www.oomkill.com/k8s-volumes/</link>
      <pubDate>Sun, 30 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/k8s-volumes/</guid>
      <description>在Kubernetes之上，在节点级提供一个存储卷的方式来持久存储数据的逻辑，这种只具备一定程度上的持久性。为了实现更强大的持久性，应该使用脱离节点而存在的共享存储设备。 为此Kubernetes提供了不同类型的存储卷。
大多数和数据存储服务相关的应用，和有状态应用几乎都是需要持久存储数据的。容器本身是有生命周期的，为了使容器终结后可以将其删除，或者编排至其他节点上去运行。意味着数据不能存储在容器本地。一旦Pod故障就会触发重构。如果将数据放置在Pod自有的容器内名称空间中，数据随着Pod终结而结束。为了突破Pod生命周期的限制，需要将数据放置在Pod自有文件系统之外的地方。
存储卷
对Kubernetes来讲，存储卷不属于容器，而属于Pod。因此，在Kubernetes中同一个Pod内的多个容器可共享访问同一组存储卷。
Pod底部有一个基础容器， ==pause==，但是不会启动。pause是基础架构容器。创建Pod时pause时Pod的根，所有Pod，包括网络命名空间等分配都是分配给pause的。在Pod中运行的容器是pause的网络名称空间的。容器在挂载存储卷时，实际上是复制pause的存储卷。
因此为了真的实现持久性，存储卷应为宿主机挂载的外部存储设备的存储卷。如果需要实现跨节点持久，一般而言需要使用脱离节点本地的网络存储设备（ceph、glusterfs、nfs）来实现。节点如果需要使用此种存储的话，需要可以驱动相应存储设备才可以（在节点级可以访问相应网络存储设备）。
k8s之上可使用的存储卷 Kubernetes支持的存储卷类型
empryDir：只在节点本地使用的，用于做临时目录，或当缓存使用。一旦Pod删除，存储卷一并被删除。empryDir背后关联的宿主机目录可以使宿主机的内存。 hostPath：使宿主机目录与容器建立关联关系。 网络存储 传统的SAN（iSCSI，FC）NAS（常见用法协议 NFS,cifs,http）设备所构建的网络存储设备。 分布式存储（分机系统或块级别），glusterfs，ceph(rbd ceph的块接口存储)，cephfs等。 云存储：EBS（弹性块存储）亚马逊 ,Azure Disk 微软。此模型只适用于Kubernetes集群托管在其公有云之上的场景。 使用kubectl explain pod.spec.volumes查看Kubernetes所支持的存储类型。
emptyDir 语法
emptyDir medium 媒介类型 empty string （disk 默认） or memory sizeLimit 空间上限 定义完存储卷之后，需要在container当中使用volumeMounts指明挂载哪个或哪些个存储卷
yaml 1 2 3 4 5 - container - mountPath 挂载路径 - name 挂载那个卷 - readOnly 是否只读挂载 - subPath 是否挂载子路径之下 yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 apiVersion: v1 kind: Pod metadata: name: my-nginx namespace: default spec: containers: - name: busybox image: busybox imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 command: [&amp;#34;tail&amp;#34;] volumeMounts: # 指明挂载哪一个存储卷 - name: html mountPath: /data/web/html # 指明挂载到容器的哪个路径下 volumes: - name: html emptyDir: {} # 表示空映射，都使用默认值，大小不限制，使用磁盘空间，而不是不定义 在Kubernetes中 $()是变量引用</description>
    </item>
    <item>
      <title>kubernetes概念 - configMap</title>
      <link>https://www.oomkill.com/k8s-cm/</link>
      <pubDate>Fri, 28 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/k8s-cm/</guid>
      <description>secret、configMap特殊类型的存储卷，多数情况下不是为Pod提供存储空间来用的，而是给管理员或用户提供了从集群外部向Pod内部应用注入配置信息的方式。
工作实现
configMap 在集群内部存在一个名称空间，在名称空间当中拥有一个可正常运行的Pod，当镜像启动时使用的配置文件在做镜像之前就确定了，并且做完镜像就不能修改了。除非在做镜像时使用entryPoint脚本去接受用户启动容器时传入环境变量进来，将环境变量的数据替换到配置文件中去，从而使应用程序在启动之前就能获得一个新的配置文件而后得到新的配置。当需要修改配置文件时是很麻烦的。而配置中心只需将集中的配置文件修改，并通知给相应进程，让其重载配置文件。而Kubernetes的应用也存在此类问题，当配置文件修改后就需要更新整个镜像。因此无需将配置信息写死在镜像中。而是引入一个新的资源，这个资源甚至是整个Kubernetes集群上的一等公民（标准的K8S资源）。这个资源被叫做configMap
configMap当中存放的配置信息，随后启动每一个Pod时，Pod可以共享使用同一个configMap资源，这个资源对象可以当存储卷来使用，也可以从中基于环境变量方式从中获取到一些数据传递给环境变量，注入到容器中去使用。 因此configMap扮演了Kubernetes中的配置中心的功能。但是configMap是明文存储数据的。因此和configMap拥有同样功能的标准资源secret就诞生了。与configMap所不同之处在于，secret中存放的数据是用过编码机制进行存放的。
核心作用：让配置信息从镜像中解耦，从而增强应用的可移植性与复用性。使一个镜像文件可以为应用程序运行不同配置的环境而工作。简单来讲，一个configMap就是一系列配置数据的集合。这些数据可以注入到Pod对象中的容器所使用。
在configMap中，所有的配置信息都保存为key value格式。V只是代表了一段配置信息，可能是一个配置参数，或整个配置文件信息都是没有问题的。
配置容器化应用的方式
自定义命令行参数 args [] 把配置文件直接陪进镜像； 环境变量 Cloud Native的应用程序一般可直接通过环境变量加载配置 通过entrypoint脚本来预处理变量为配置文件中的配置信息。 存储卷 配置文件注入方式：
将configMap做存储卷 使用env docker config
contioners env name 变量名 value 变量值 valueFrom 数据不是一个字符串，而是引用另外一个对象将其传递给这个变量。 configMapKeyRef configMap中的某个键 fieldRef 某个字段。此资源可以是Pod自身的字段。如metadata.labels status.hostIP status.podIP resourceFieldRef 资源需求和资源限制。 secreKeyRef 引用secre configMap无需复杂描述，因此没有spec字段
text 1 2 3 4 apiVersion kind data binaryData 一般情况下data与binaryData只使用其中一种。 创建简单的configMap还可以使用 kubectl create configMap来创建。如需要长期使用，可以定义为配置清单文件。
text 1 2 3 kubectl create configmap nginx-config \ --from-literal=nginx_port=80 \ --from-literal=servername=test.com 使用文件创建</description>
    </item>
    <item>
      <title>kubernetes概念 - Dashboard</title>
      <link>https://www.oomkill.com/k8s-dashboard/</link>
      <pubDate>Fri, 28 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/k8s-dashboard/</guid>
      <description>基于web的UI前端，认证是由Kubernetes完成的。登陆dashboard的密码是k8s的账号和密码，和dashboard自身没有关系。dashboard自身不做认证。
text 1 kubectl patch svc kubernetes-dashboard -p&amp;#39;{&amp;#34;spec&amp;#34;:{&amp;#34;type&amp;#34;:&amp;#34;NodePort&amp;#34;}}&amp;#39;-n kube-system 如使用域名访问，CN一定要与域名保持一致。
text 1 2 3 4 (umask 077; openssl genrsa -out dashboard.key 2048) openssl req -new -key dashboard.key -out dashboard.csr -subj &amp;#34;/O=test/CN=dashboard&amp;#34; openssl req -in dashboard.csr -noout -text openssl x509 -req -in dashboard.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out dashboard.crt -days 3650 Certificate Attributes
要想穿透集群边界，从集群外访问集群内部某一服务或Pod上的容器的应用，有两种方式 nodePort、NodeBlanc 或ingress
text 1 2 3 4 5 kubectl create secret generic \ dashboard-cert \ -n kube-system \ --from-file=dashboard.</description>
    </item>
    <item>
      <title>kubernetes概念 - ingress</title>
      <link>https://www.oomkill.com/k8s-ingress/</link>
      <pubDate>Fri, 28 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/k8s-ingress/</guid>
      <description>IngressController比较独特，它与DaemonSet、Deployment、Repliacaset不同，DaemonSet、Deployment等控制器是作为ControllerManager的子组件存在的。Ingress Controller是独立运行的一组Pod资源，通常是拥有七层代理、调度能力的应用程序。
通常在使用IngressController时有三种选择Nginx、Traefik、Envoy。
IngressController nginx运行在Pod中，其配置文件是在Pod中。后端代理的Pod随时会发生变动，IngressController需要watch API当中的后端Pod资源的改变。IngressController自身无法识别目前符合自己关联的（条件的）被代理的Pod资源有哪些，IngressController需借助service来实现。
因此要想定义一个对应的调度功能，还需要创建service，此service通过label selector关联至每一个upstream服务器组，通过此service资源关联至后端的Pod。此service不会被当做被代理时的中间节点，它仅仅是为Pod做分类的。此service关联的Pod，就将其写入upstream中。
在Kubernetes中有一种特殊资源叫做Ingress，当Pod发生改变时，其servcie对应的资源也会发生改变， 依赖于IngressResource将变化结果反应至配置文件中。
Ingress定义期望IngressController如何创建前段代理资源（虚拟主机、Url路由映射），同时定义后端池（upstream）。upstream中的列表数量，是通过service获得。
Ingress可以通过编辑注入到IngressController中，并保存为配置文件，且Ingress发现service选定的后端Pod资源发生改变，此改变会及时反映至Ingress中，Ingress将其注入到前端调度器Pod中，并触发Pod中的container主进程（nginx）重载配置文件。
要想使用Ingress功能，需要有service对某些后端资源进行分类，而后Ingress通过分类识别出Pod的数量和IP地址信息，并将反映结果生成配置信息注入到upstream中。
IngressController根据自身需求方式来定义前端，而后根据servcie收集到的后端Pod IP定义成upstream server，将这些信息反映在Ingress server当中，由Ingress动态注入到IngressController当中。
Ingress也是标准的Kubernetes资源，定义Ingress时同样类似于Pod方式来定义。使用kubectl explain Ingress查看帮助。
spec rules 规则，对象列表 host 主机调度 虚拟主机而非url映射 http paths 路径调度 backend path backend 定义被调度的后端主机，靠service定义，找到后端相关联的Pod资源。 serviceName 后端servcie名称，即用来关联Pod资源的service。 servicePort IngressController部署
namespace.yaml 创建名称空间 configmap.yaml 为nginx从外部注入配置的 rbac.yaml 定义集群角色、授权。必要时让IngressController拥有访问他本身到达不了的名称空间的权限
ingress.yaml
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-myapp namespace: defualt # 与deployment和要发布的service处在同一名称空间内 annotations: kubernetes.</description>
    </item>
    <item>
      <title>kubernetes概念 - Kubenetes Deployment</title>
      <link>https://www.oomkill.com/kubenetes-deployment/</link>
      <pubDate>Fri, 28 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubenetes-deployment/</guid>
      <description>Deployment当中借助于ReplicaSet进行更新的策略反映在Deployment的对象定义所需字段可使用kubectl explain deploy，Deployment属于extension群组。在1.10版本中它被移至到apps群组。他与ReplicaSet相比增加了几个字段。
stratgy 重要字段，定义更新策略，它支持两种策略 重建式更新 Recreate与滚动更新RollingUpdate，如果type为RollingUpdate，那么RollingUpdate的策略还可以使用RollingUpdate来定义，如果type为Recreate，那么RollingUpdate字段无效。 默认值为RollingUpdate
stratgy.RollingUpdate控制RollingUpdate更新力度
maxSurge 对应的更新过程当中，最多能超出目标副本数几个。有两种取值方式，为直接指定数量和百分比。在使用百分比时，在计算数据时如果不足1会补位1个。 maxUnavailable 最多有几个副本不可用。 revisionHistoryLimit 滚动更新后，在历史当中最多保留几个历史版本，默认10。
在使用Deployment创建Pod时，Deployment会自动创建ReplicaSet，而且Deployment名称是使用Pod模板的hash值，此值是固定的。
Deployment在实现更新应用时，可以通过编辑配置文件来实现，使用kubectl apply -f更改每次变化。每次的变化通过吧变化同步至apiserver中，apiserver发现其状态与etcd不同，从而改变etcd值来实现修改其期望状态，来实现现有状态去逼近期望状态。
kubectl explain deploy
yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 apiVersion: apps/v1 kind: Deployment metadata: name: app-deploy namespace: default spec: replicas: 2 selector: matchLabels: app: deploy release: canary template: metadata: labels: app: deploy release: canary spec: containers: - name: my-deploy image: node01:5000/busybox:v1 ports: - name: http containerPort: 80 command: [&amp;#34;/bin/sh&amp;#34;,&amp;#34;-c&amp;#34;,&amp;#34;/bin/httpd -f -h /tmp&amp;#34;] 使用kubectl apply 声明式更新、创建资源对象。</description>
    </item>
    <item>
      <title>kubernetes概念 - Kubernetes Pod控制器</title>
      <link>https://www.oomkill.com/kubernetes-pod-controller/</link>
      <pubDate>Fri, 28 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-pod-controller/</guid>
      <description>Kubernetes资源清单 类别 名称 工作负载型资源（workload） 运行应用程序，对外提供服务：Pod、ReplicaSet、Deployment、StatefulSet、DaemonSet、Job、Cronjob （ReplicationController在v1.11版本被废弃） 服务发现及负载均衡 service、Ingress 配置与存储 Volume、CSI（容器存储接口 特殊类型存储卷 ConfigMap（当配置中心来使用的资源类型）、Secret（保存敏感数据）、DownwardAPI（把外部环境中的信息输出给容器） 集群级资源 Namespace、Node、Role、ClusterRole、RoleBinding（角色绑定）、ClusterRoleBinding（集群角色绑定） 元数据型资源 HPA、PodTemplate（Pod模板，用于让控制器创建Pod时使用的模板）、LimitRange（用来定义硬件资源限制的） Kubernetes配置清单使用说明 在Kubernetes中创建资源时，除了命令式创建方式，还可以使用yaml格式的文件来创建符合我们预期期望的pod，这样的yaml文件我们一般称为资源清单。资源清单由很多属性或字段所组成。
以yawl格式输出pod的详细信息。
资源清单格式 yaml 1 kubectl get pod clients -o yaml Pod资源清单常用字段讲解 在创建资源时，apiserver仅接收JSON格式的资源定义。在使用kubectl run命令时，自动将给定内容转换成JSON格式。yaml格式提供配置清单，apiserver可自动将其转为JSON格式，（yaml可无损转为json），而后再提交。使用资源配置请清单可带来复用效果。
Pod资源配置清单由五个一级字段组成，通过kubectl create -f yamlfile就可以创建一个Pod
apiVersion: 说明对应的对象属于Kubernetes的哪一个API群组名称和版本。给定apiVersion时由两部分组成group/version，group如果省略表示core（核心组）之意。使用kubectl api-versions获得当前系统所支持的apiserver版本。alpha 内测版、beta 公测版、stable 稳定版
kind: 资源类别，用来指明哪种资源用来初始化成资源对象时使用。
metadata: 元数据，内部嵌套很多2级、3级字段。主要提供以下几个字段。
name，在同一类别当中name必须是唯一的。
namespace 对应的对象属于哪个名称空间，name受限于namespace，不同的namespace中name可以重名。
lables key-value数据，对于key名称及value，最多为63个字符，value，可为空。填写时只能使用字母、数字、_、-、.，只能以字母或数字开头及结尾。
annotations 资源注解。与label不同的地方在于，它不能用于挑选资源对象，仅用于为对象提供“元数据”。对键值长度没有要求。在构建大型镜像时通常会用其标记对应的资源对象的元数据
spec: specification，定义接下来创建的资源对象应该满足的规范（期望的状态 disired state）。spec是用户定义的。不同的资源类型，其所需要嵌套的字段各不相同。如果某一字段属性标记为required表示为必选字段，剩余的都为可选字段，系统会赋予其默认值。如果某一字段标记为Cannot be updated，则表示为对象一旦创建后不能改变字段值。可使用kubectl explain pods.spec查看详情。
containers [required]object list
name [string] 定义容器名称
image [string] 启动Pod内嵌容器时所使用的镜像。可是顶级、私有、第三方仓库镜像。
imagePulLPolicy [string] 镜像获取的策略，可选参数Always（总是从仓库下载，无论本地有无此镜像）、Never（从不下载，无论本地有无此镜像）、IfNotPresent（本地存在则使用，不存在则从仓库拉去镜像）。如果tag设置为latest，默认值则为Always，非latest标签，默认值都为IfNotPresent。</description>
    </item>
    <item>
      <title>kubernetes概念 - kubernetes调度</title>
      <link>https://www.oomkill.com/kubernetes-schedule/</link>
      <pubDate>Fri, 28 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-schedule/</guid>
      <description>Overview kube-scheduler 是kubernetes控制平面的核心组件，其默认行为是将 pod 分配给节点，同时平衡Pod与Node间的资源利用率。通俗来讲就是 kube-scheduler 在运行在控制平面，并将工作负载分配给 Kubernetes 集群。
本文将深入 Kubernetes 调度的使用，包含：”一般调度”，”亲和度“，“污点与容忍的调度驱逐”。最后会分析下 Scheduler Performance Tuning，即微调scheduler的参数来适应集群。
简单的调度 NodeName [1] 最简单的调度可以指定一个 NodeName 字段，使Pod可以运行在对应的节点上。如下列资源清单所示
yaml 1 2 3 4 5 6 7 8 9 apiVersion: v1 kind: Pod metadata: name: netpod spec: containers: - name: netbox image: cylonchau/netbox nodeName: node01 通过上面的资源清单Pod最终会在 node01上运行。这种情况下也会存在很多的弊端，如资源节点不足，未知的nodename都会影响到Pod的正常工作，通常情况下，这种方式是不推荐的。
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 $ kubectl describe pods netpod Name: netpod Namespace: default .</description>
    </item>
    <item>
      <title>kubernetes概念 - Service</title>
      <link>https://www.oomkill.com/kubernetes-service/</link>
      <pubDate>Fri, 28 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-service/</guid>
      <description>在Kubernetes集群中，Pod是有生命周期的，为了能够给对应的客户端提供一个固定访问端点，因此在客户端与服务端（Pod之间）添加了一个固定中间层，这个中间层被称之为Service。Service的工作严重依赖于在Kubernetes集群之上，部署的附件Kubernetes DNS服务。较新版本使用的coreDNS，1.11之前使用的KubeDNS。
service的名称解析是强依赖于DNS附件的。因此在部署完Kubernetes后，需要部署CoreDNS或KubeDNS。 Kubernetes要想向客户端提供网络功能，依赖于第三方方案，在较新版本中，可通过CNI容器网络插件标准接口，来接入任何遵循插件标准的第三方方案。 Service从一定程度上来说，在每个节点之上都工作有一个组件Kube-proxy，Kube-proxy将始终监视apiserver当中，有关service资源的变动状态。此过程是通过Kubernetes中固有的请求方法watch来实现的。一旦有service资源的内容发生变动，kube-proxy都将其转换为当前节点之上的能够实现service资源调度至特定Pod之上的规则。
service实现方式 在Kubernetes中service的实现方式有三种模型。
userspace 用户空间，可以理解为，用户的请求。 1.1之前包括1.1使用此模型。 用户的请求到达当前节点的内核空间的iptables规则（service规则），由service转发至本地监听的某个套接字上的用户空间的kube-proxy，kube-proxy在处理完再转发给service，最终代理至service相关联的各个Pod，实现调度。
iptables 1.10- 客户端IP请求时，直接请求serviceIP，IP为本地内核空间中的service规则所截取，并直接调度至相关Pod。service工作在内核空间，由iptables直接调度。
ipvs 1.11默认使用，如IPVS没有激活，默认降级为iptables 客户端请求到达内核空间后，直接由ipvs规则直接调度至Pod网络地址范围内的相关Pod资源。
使用清单创建service资源 SVC中的kubernetes service是集群中各Pod需要与Kubernetes集群apiserver联系时需要通过此svc地址联系。这个地址是集群内的apiserver服务地址。
service类型 ClusterIP 默认值，表示分配集群IP地址，仅用于集群内通信。自动分配地址，如需固定，需要指定相应地址，在创建后无法修改。当使用ClusterIP时，只有两个端口有用，port与targetPort
NodePort 接入集群外部流量，默认分配的端口是30000~32767
LoadBalancer 表示将Kubernetes部署在虚拟机上，虚拟机是工作在云环境中，云环境支持lbaas（负载均衡及服务的一键调用）。
ExternaName 表示将集群外部服务引用到集群内部中来，在集群内部直接使用。
yaml 1 2 3 4 5 6 7 8 9 10 11 12 spec: ports: # 将哪个端口与后端容器端口建立关联关系。 - port # service对外提供服务的端口 name 指明port的名称 targetPort # 容器的端口 nodePort # 只有类型为NodePort时，才有必要用节点端口，否则此选项是无用的。 protocol 协议，默认TCP seletcor 关联到哪些Pod资源上 app: redis run: redis clusterIP: # clusterIP可以动态分贝可以不配置 type: ClusterIP yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 apiVersion: v1 kind: Service metadata: name: redis namespace: default spec: selector: run: redis clusterIP: 10.</description>
    </item>
    <item>
      <title>kubernetes概念 - serviceaccount</title>
      <link>https://www.oomkill.com/kubernetes-serviceaccount/</link>
      <pubDate>Fri, 28 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-serviceaccount/</guid>
      <description>在整个Kubernetes集群来讲 apiserver是访问控制的唯一入口。如通过service或ingress暴露之后，是可以不通过apiserver接入的，只需要通过节点的nodePort或者ingress controller daemonset共享宿主机节点网络名称空间监听的宿主机网络地址（节点地址），直接接入。
当请求到达APIServer时，会经历几个阶段，如图所示
图：Kubernetes API 请求的请求处理步骤图Source：https://kubevious.io/blog/post/securing-kubernetes-using-pod-security-policy-admission-controller任何用户（sa与人类用户）在通过任何方式试图操作API资源时，必须要经历下列的操作：
Authentication，这个步骤在建立TLS连接后，验证包含，证书、密码，Token；可以指定多种认证，依次尝试每一个，直到其中一个认证成功。如果认证失败，此时客户端收到的是401。 Authorization，此步骤是在完成 Authentication 后确定了来源用户，此时用户的请求动作必须被授权。如bob用户对pod资源有 get , list 权限操作。如果 Admission Control：此步骤为图3，与 Authorization 不同的时，这里只要有任意准入控制器拒绝，则拒绝；多个准入控制器会按顺序执行 Refer to controlling access
认证 Kubernetes是高度模块化设计的，因此其认证授权与准入控制是各自都通过插件的方式，可由用户自定义选择经由什么样的插件来完成何种控制逻辑。如对称秘钥认证方式、令牌认证。由于Kubernetes提供的是resetful方式的接口，其服务都是通过HTTP协议提供的，因此认证信息只能经由HTTP协议的认证首部进行传递，此认证首部通常被称作认证令牌(token)。
ssl认证，对于Kubernetes访问来讲，ssl证书能让客户端去确认服务器的身份，（要求服务端发送服务端证书，确认证书是否为认可的CA签署的。）在Kubernetes通信过程当中，重要的是服务器还需认证客户端的身份，因此==Kubectl也应有一个证书，并且此证书为server端所认可的CA所签署的证书==。并且客户端身份也要与证书当中标识的身份保持一致。双方需互相做双向证书认证。认证之后双方基于SSL会话实现加密通讯。
注：kubernetes认证无需执行串行检查，用户经过任何一个认证插件通过后，即表示认证通过，无需再经由其他插件进行检查。
授权 kubernetes的授权也支持多种授权插件来完成用户的权限检查，kubernetes 1.6之后开始支持基于RBAC的认证。除此只外还有基于节点的认证、webhook基于http回调机制，通过web的rest服务来实现认证的检查机制。最重要的是RBAC的授权检查机制。基于角色的访问控制，通常只有许可授权，没有拒绝授权。默认都是拒绝。
在默认情况下，使用kubeadm部署Kubernetes集群是强制启用了RBAC认证的。
准入控制 一般而言，准入控制本身只是用来定义对应授权检查完成之后的后续其他安全检查操作的。
用户账号 一般而言用户账号大体上应具有以下信息
user 用户，一般而言由username与userid组成。
group 用户组
extra 用来提供额外信息
API资源 k8sapiserver是分组的，向哪个组，哪个版本的哪个api资源对象发出请求必须进行标识，所有的请求资源通过url path进行标识的。如 /apis/apps/v1/，所有名称空间级别的资源在访问时一般都需指名namespaces关键词，并给出namespaces名称来获取 /apis/apps/v1/namespaces/default/ /apis/apps/v1/namespaces/default/nginx 。
一个完整意义上的url 对象引用url格式 ==/apis/&amp;lt;GROUPS&amp;gt;/&amp;lt;VERSION&amp;gt;/namespaces/&amp;lt;NameSpace_name&amp;gt;/&amp;lt;Kind&amp;gt;/[/object_id]==
bash 1 2 3 $ kubectl api-versions admissionregistration.k8s.io/v1beta1 ... Kubernetes中，所有的api都取决于一个根 /apis
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 $ curl -k --cert /etc/k8s/pki/apiserver-kubelet-client.</description>
    </item>
    <item>
      <title>Unix归档模式cpio - 深入剖析与构建rpm包</title>
      <link>https://www.oomkill.com/rpm-package/</link>
      <pubDate>Sat, 15 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/rpm-package/</guid>
      <description>RPM概述 RPM (Red Hat Package Manager)，几乎所有的 Linux 发行版本都使用这种形式的软件包管理安装、更新和卸载软件。对于最终用户来说，使用RPM所提供的功能来维护系统是比较容易和轻松的。安装、卸载和升级RPM软件包只需一条命令就可以搞定。RPM维护了一个所有已安装的软件包和文件的数据库，可以让用户进行查询和验证工作。在软件包升级过程中，RPM会对配置文件进行特别处理，绝对不会丢失以往的定制信息。对于程序员RPM可以让我们连同软件的源代码打包成源代码和二进制软件包供最终用户使用。
一般而言制作一个RPM包包含以下几个步骤
计划你想要建立什么 收集软件包 根据需要修补软件 计划升级旧有的包 创建可重现的软件构建 概述任何依赖关系 构建rpm 测试rpm（能否安装、升级） RPM capability 能力 运行或安装需要依赖于其他的RPM包本身或所提供的文件为基础的现象被称之为依赖关系。但在制作RPM包时，依赖关系有两类编译依赖与安装依赖。
自身名字所包含的意义 它提供的文件也有可能被其他软件所依赖，文件本身也能识别成一种能力 编译依赖和安装依赖
每一个RPM包都提供一种能够完成任务的功能，此种能力很可能被其他RPM所依赖，此能力大多数情况下和RPM名字是相同的。
制作RPM包的纲要有如下四部
设定RPM包制作的目录结构（制作车间） 将原材料（源码包、配置文件、补丁包）放置规划好的目录当中。 创建spec文件，指挥如何使用原材料将其制作成rpm包。 编译源代码生成rpm包 在一个特定的目录中提供如下5个子目录 redhat上默认在/usr/src/reahat BUILD 源代码解压以后放置的位置，仅需提供目录。 RPMS 放置制作完成后的RPM包 SOURCES 原材料放置目录（配置文件、源码包、补丁包） SPECS 放置spec文件（纲领性文件）的。 SRPMS SRC rpm包存放位置 RPM优缺点 优点：
集中管理：RPM可以集中管理安装、升级和删除软件包，保证系统的干净和稳定。 精确控制：RPM提供详细的软件包信息，可以对软件包的安装路径、依赖关系、版本等进行精确控制，使得软件安装更加灵活便捷。 简单易用：RPM提供了一套完整的命令行工具和图形化管理工具，对于普通用户来说，使用起来非常方便。 更新机制：RPM可以根据用户需要进行更新，包括安全更新、功能更新和修复错误等，可以更好地保证系统安全与稳定性。 缺点：
依赖管理：RPM虽然可以管理软件包的依赖关系，但其解决依赖的方式容易出现问题，可能会出现某些软件包的依赖关系无法解决的情况。 更新速度：由于需要对软件包进行依赖检查等操作，升级软件包可能需要较长时间，特别是当软件包依赖比较复杂时。 存在问题：有时候使用RPM安装的软件包出现问题，需要手动卸载并重新安装，这会导致一些无法预测的麻烦。 兼容性：RPM采用了特定的软件包管理标准，要求安装的软件包必须符合这些标准。因此，RPM可能不太适用于其他Linux系统或自定义的软件包格式。 SPEC文件 制作RPM软件包的关键在于编写SPEC软件包描述文件。要想制作一个rpm软件包就必须写一个软件包描述文件（SPEC）。这个文件中包含了软件包的诸多信息，如软件包的名字、版本、类别、说明摘要、创建时要执行什么指令、安装时要执行什么操作、以及软件包所要包含的文件列表等等。
SPEC文件通常包括以下几个部分：
头文件：包括软件包的名称、版本、发布号、授权等信息。
%description：包括软件包的描述、依赖关系、构建环境等信息。
%prep：指定源代码的来源和如何解压缩及准备源代码。
%build：指定如何编译源代码。
%install：指定如何安装编译好的软件包。
%check：指定测试源代码的特定部分，通常是用来运行单元测试。
%clean：指定清除构建过程中产生的临时文件和目录的方法。
%files：指定哪些文件应该包括在最终的RPM文件中。
%changelog：记录软件包的变更历史。
SPEC文件中常用的宏变量 宏变量 说明 %{name} 软件包的名称，如 myapp。 %{version} 软件包的版本号，如 1.</description>
    </item>
    <item>
      <title>kubernetes概念 - RBAC</title>
      <link>https://www.oomkill.com/kubernetes-rbac/</link>
      <pubDate>Tue, 21 Aug 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/kubernetes-rbac/</guid>
      <description>Kubernetes API Object 在Kubernetes线群中，Kubernetes对象是持久化的实体（最终存入etcd 中的数据），集群中通过这些实体来表示整个集群的状态。前面通过kubectl来提交的资源清单文件，将我们的YAML文件转换成集群中的一个API对象的，然后创建的对应的资源对象。
Kubernetes API是一个以JSON为主要序列化方式的HTTP服务，除此之外支持Protocol Buffers序列化方式（主要用干集群内年件间的通信）。为了api的可扩展性，Kubemetes在不同的API路径（/api/v1或/apis/batch）下面支持了多个API版本，不同的API版本就味不同级别稳定性和支持。
Alpha ：例如v1Alpha：默认情况下是禁用的，可以随时删除对功能的支持。 Beta：例如 v2beta1 默认是启用的，表示代码已经经过了很好的测试，但是对象的语义可能会在施后的版本中以不兼咨的方式更改 Stable：例如：v1 表示已经是稳定版本，也会出现在后续的很多版本中。 在Kubernetes集群中，一个API对象在Etcd 里的完整资源路径，是由：group （API组）、 version （API版本） 和 Resource API资源类型）三个部分组成。通过这种的结构，整个Kubernetes 中所有API对象，就可以用如下的树形结构表示出来：
Kubernetes API Object的使用 API对象组成查看：kubectl get --raw /
通常，KubernetesAPI支持通过标准HTTP P0ST、PUT、DELETE 和 GET 在指定PATH路径上创建、更新、删除和检索操作，并使用JSON作为默认的数据交互格式。
如要创建一个Deployment对象，那YAML文件的声明就需：
yaml 1 2 apiVersion: apps/v1 # kind: Deployment Deployment就是这个API对象的资源类型（Resource），apps就是它的组（Group），v1就是它的版本（Version）。API Group、Version 和资源满唯一定义了一个HTTP路径，然后在kube-apiserver 对这个url进行了监听，然后把对应的请求传递给了对应的控制器进行处理。
API对象参考文档
授权插件分类 Node 由节点来认证。
ABAC 基于属性的访问控制，RBAC之前的授权控制的插件算法
RBAC Role-based Access Control。
Webhook 基于http的回调机制来实现访问控制。
RBAC 基于角色的访问控制可以理解为，角色（role）反而是授权的机制，完成了权限的授予、分配等。角色是指一个组织或者任务工作中的位置，通常代表一种权利、资格、责任等。在基于角色的访问控制中还有一种术语叫做 ==许可==（permission）。
简单来讲就如同上图描述，使用户去扮演这个角色，而角色拥有这个权限，所以用户拥有这个角色的权限。所以授权不授予用户而授予角色。
RBAC 使用 rbac.authorization.k8s.ioAPI组来驱动鉴权操作，允许管理员通过 Kubernetes API 动态配置策略。</description>
    </item>
    <item>
      <title>CentOS 6.8升级OpenSSH7.7p</title>
      <link>https://www.oomkill.com/upgrade-openssh-in-centos6/</link>
      <pubDate>Sun, 22 Jul 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/upgrade-openssh-in-centos6/</guid>
      <description>近期因 centos 6.x 默认 openssh 扫描存在大量漏洞，基于安全考虑，需要将 openssh_5.3p1 升级为最新版，网上查了很多教程，发现 openssh 存在大量依赖，不解决依赖问题很难保证其他服务政策。而 openssl 又被大量程序依赖。实在是头疼。最后发现一个不破坏各种依赖又可以完美升级的方案
注：curl wget yum 等依赖 openssl gitlab依赖 openssh 因卸载 openssh 与 openssl 编译安装导致各种依赖程序被破坏，虽然最后升级成功，但是wget curl 和代码库被破坏。
下载 openssh-7.7p 源码包 下载地址
下载之后解压看 README 和 INSTALL
text 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 1. Prerequisites ---------------- A C compiler. Any C89 or better compiler should work.</description>
    </item>
    <item>
      <title>ansible介绍</title>
      <link>https://www.oomkill.com/ansible/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ansible/</guid>
      <description>运维工具 OS Provisioning: PXE, Cobbler(repository,distritution, profile)
PXE: dhcp, tftp, (http, ftp)
dnsusq: dhcp, dns
OS Config:
puppet, saltstack, func
Task Excute:
fabric, func, saltstack
Deployment:
fabric
管理主机，要想管理被管理节点，二者必须有安全管理通道。puppet、saltstack在管理被管节点时，每一个被管节点必须运行puppet agent，管理端进程与每一个被管节点的agent进程进行通信，通信时使用的HTTP协议。此种方式必须在被管节点安装应用程序的agent，远程接收到指令，并在本地负责执行相应的任务。
根据远程管理时，是不是在每一个被管主机上安装agent端，分为两种puppet、func、saltstack；与无需agent端，ansible、fabric。依赖被管节点的ssh服务。而管理端需要知道对方主机上的账号密码。
ansible的组成 ansible核心 host invenory ：为了管控每个被管主机，每个主机在本地需要注册。用来定义由ansible远程配置管理的主机，每个主机的IP地址、掩码、SSH监听的地址、端口号、账号密码等。
core modules：ansible执行任何特定管理任务，都是不由ansible自身玩成的，而是通过模块完成的。
custom Modules：使用任何编程语言来编写模块。
playbooks：将主机要完成的多个任务，事先定义在文件中可以多次调用。
1 ansible的特性 基于Python语言实现，由Paramiko, PyYAML和jiniia2三个关键模块 部署简单，agentless 默认使用SSH协议 主从模式： master:ansible, ssh client slave: ssh server 支持自定文模块：支持各种编程语言，支持Playbook，基于“模块”完成各种“任务”。 安装依赖于epel源
配置文件：
text 1 2 /etc/ansible/ansible.cfg Invertory:/etc/ansible/hosts 2 ansible命令应用基础 语法: ansible &amp;lt;host-pattern&amp;gt; [-f forks] [-m module_name] [-a args]</description>
    </item>
    <item>
      <title>docker Registry使用</title>
      <link>https://www.oomkill.com/docker-registry/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/docker-registry/</guid>
      <description>docker registry介绍 Registry用于保存docker镜像，包括镜像的层次结构和元数据，用户可自建Registry，也可使用官方的Docker Hub
分类
Sponsor Registry：第三方的registry，供客户和Docker社区使用 Mirror Registry：第三方的registry，只让客户使用 Vendor Registry：由发布Docker镜像的供应商提供的registry Private Registry：通过设有防火墙和额外的安全层的私有实体提供的registry 一个docker Registry上拥有两种功能：
提供镜像存储的仓库。 提供用户获取镜像时的认证功能。 同时提供当前服务器上所有可用镜像的搜索索引。 一个docker镜像仓库有仓库的名称，等同于yum的repostory。通常简称为repo。为了使的镜像和应用程序版本之间有意义上的关联关系。在docker一个仓库通常只存放一个应用程序的镜像。因此，这个仓库名就是应用程序名。通过给每个镜像额外添加一个组件叫tag，来标识每一个镜像。通常镜像名称:标签repo_name:tag才能唯一标识一个镜像。
为了可以快速创建registry，docker专门提供了一个程序包 docker-distribution 。https://hub.docker.com/r/distribution/registry/ regustry自身运行在容器中，而容器的文件系统会随着容器生命周期终止而删除，因此需要给registry定义存储卷，使用网络存储。
在yum的extras仓库有一个docker-registry的程序包。docker-distribution的主配置文件在 /etc/docker-distribution/registry/config.yml，所有上传的镜像存放在/var/lib/registry 。
sh 1 2 3 4 5 6 7 8 9 10 11 12 $ yum info docker-registry Available Packages Name : docker-registry Arch : x86_64 Version : 0.9.1 Release : 7.el7 Size : 123 k Repo : extras/7/x86_64 Summary : Registry server for Docker URL : https://github.</description>
    </item>
    <item>
      <title>docker Volume</title>
      <link>https://www.oomkill.com/docker-volume/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/docker-volume/</guid>
      <description>对于docker来讲，作为容器运行的底层引擎，在组织及运行容器时每个容器内只运行一个程序及子程序。对于这个容器来讲，启动时依赖于 底层镜像联合挂载启动而成。 底层能够存储此类分层构建并联合挂载镜像的文件系统。最上层构建读写层。对于此读写层来说。所有对容器的操作都保存在最上层之上。而下层内容的操作需要使用写时复制。
Docker镜像由多个只读层叠加而成，启动容器时，Docker会加载只读镜像层并在镜像栈顶部添加一个读写层，如果运行中的容器修改了现有的一个已经存在的文件，那该文件将会从读写层下面的只读层复制到读写层，该文件的只读版本仍然存在，只是已经被读写层中该文件的副本所隐藏，此即 写时复制（COW）机制。此机制对IO较高的应用在实现持久化存储时，势必对在底层应用数据存储时性能要求较高。要想绕过使用限制，可以使用存储卷机制。
Why Data Volume？
宿主机的主机文件系统直接与容器内部的文件系统之上的某一访问路径建立绑定关系。
在宿主机上目录和容器内文件系统建立绑定关系的目录相对于容器来讲被称为volume。容器内所有有效数据都是保存在存储卷，从而脱离容器自身文件系统。当容器关闭并删除时，只要不删除与宿主机与之绑定的存储目录，就能实现数据脱离容器的生命周期而持久化。docker的存储卷默认情况下使用其所在宿主机之上的本地文件系统目录的。
关闭并重启容器，其数据不受影响；但删除Docker容器，则其更改将会全部丢失 存在的问题 存储于联合文件系统中，不易于宿主机访问； 容器间数据共享不便 删除容器其数据会丢失 解决方案：“卷（volume）” “卷”是容器上的一个或多个“目录”，此类目录可绕过联合文件系统，与宿主机上的某目录“绑定（关联）” 在docker中如果需要动刀存储卷时，不必要手动创建，Volume于容器初始化之时即会创建，由base image提供的卷中的数据会于此期间完成复制
Volume的初衷是独立于容器的生命周期实现数据持久化，因此删除容器之时既不会删除卷，也不会对哪怕未被引用的卷做垃圾回收操作；
Data volumes ·卷为docker提供了独立于容器的数据管理机制 ·可以把“镜像”想像成静态文件，例如“程序”，把卷类比为动态内容，例如“数据 &amp;ldquo;；于是，镜像可以重用，而卷可以共享； ·卷实现了“程序（镜像）”和“数据（卷）”分离，以及“程序（镜像）”和“制作镜像的主机 &amp;ldquo;分离，用户制作镜像时无须再考虑镜像运行的容器所在的主机的环境；
Docker有两种类型的卷，每种类型都在容器中存在一个挂载点，但其在宿主机上的位置有所不同；
Bind mount volume 绑定挂载卷 在宿主机指定一个特定路径，在容器内指定一个特定路径，二者已知路径建立关联关系。
a volume that points to a user-specified location on the host file system
Docker-managed volume docker管理卷 指定容器内的挂载点，与之关联的是宿主机的目录由docker daemon引擎自行创建空目录，或者使用已存在目录与存储卷路径建立关联关系。
the Docker daemon creates managed volumes in a portion of the host&amp;rsquo;s file system that&amp;rsquo;s owned by Docker
在容器中使用Volumes 为docker run命令使用一v选项即可使用Volume</description>
    </item>
    <item>
      <title>docker-compose使用</title>
      <link>https://www.oomkill.com/docker-compose/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/docker-compose/</guid>
      <description>Compose是一个定义和管理多容器的工具，使用Python语言编写。使用Compose配置文件描述多个容器应用的架构，比如使用 什么镜像、数据卷、网络、映射端口等；然后一条命令管理所有服务，比如启动、停止、重启等。
1、Linux安装Compose 参考网址：Releases · docker/compose · GitHub
下载二进制文件 bash 1 2 3 curl -L \ https://github.com/docker/compose/releases/download/1.22.0/docker-compose-\ `uname -s`-`uname -m` -o /usr/local/bin/docker-compose 对二进制文件添加可执行权限 bash 1 chmod +x /usr/local/bin/docker-compose 测试安装 docker-compose &amp;ndash;version
也可以使用pip工具安装：pip install docker-compose
2、使用compose 参考文档：Docker Compose | Docker Documentation
compose语法详解：Compose file version 3 reference | Docker Documentation Docker compose file 中文参考文档 - CSDN博客
2.1 Compose常用命令选项 参数 介绍 build 构建或修改Dockerfile后重建服务 config 验证和查看compose文件语法
-q,只验证配置，不输出。 当配置正确时，不输出任何内容，当文件配置错误，输出错误信息。
--services,打印服务名，一行一个 create down 停止和删除容器、网络、卷、镜像，这些内容是通过docker-compose up命令创建的. 默认值删除 容器 网络。 logs 打印compose service日志输出。 ps 打印compose进程，-q只打印pid 更多参数参考：Docker-compose命令详解 - CSDN博客</description>
    </item>
    <item>
      <title>docker-compose示例</title>
      <link>https://www.oomkill.com/docker-compose-example/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/docker-compose-example/</guid>
      <description>使用docker-compose构建LNMP环境 编写Dockerfile 这里采用的是先将nginx php打包为rpm包，然后做成镜像。与直接在容器里编译安装同理的。
nginx Dockerfile
bash 1 2 3 4 5 6 7 8 FROM centos MAINTAINER lc RUN yum install -y gcc gcc-c++ openssl-devel make pcre-devel ADD nginx-1.13.9-1.el7.centos.x86_64.rpm /tmp/ RUN cd /tmp/ &amp;amp;&amp;amp; rpm -ivh nginx-1.13.9-1.el7.centos.x86_64.rpm ADD nginx.conf /etc/nginx/ EXPOSE 80 CMD [&amp;#34;/usr/sbin/nginx&amp;#34;, &amp;#34;-g&amp;#34;, &amp;#34;daemon off;&amp;#34;] php Dockerfile
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 FROM centos MAINTAINER LC RUN curl -o /etc/yum.</description>
    </item>
    <item>
      <title>Dockerfile使用示例</title>
      <link>https://www.oomkill.com/dockerfile/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/dockerfile/</guid>
      <description>一、使用前提 通用镜像未必与应用程序和配置是符合我们需要的。
1.1 常见镜像制作方式 常见制作镜像方式有两种
基于容器 基于镜像制作：编辑一个Dockerfile，而后根据此文件制作； 二、Dockerfile概述 Dockerfile只是构建Docker镜像的源代码，docker可以通过读取Dockerfile中的指令自动构建图像。Dockerfile是一个文本文档，其中包含用户可以在命令行上调用以组合图像的所有命令。用户可以使用 docker build 创建连续执行多个命令行指令的自动构建。
2.1 Dockerfile的工作模式 基于Dockerfile制作镜像时，需在专用目录放置Dockerfile文件，并且文件首字母必须大写。基于Dockerfile中打包的文件必须奇基于工作目录往下走的路径。在打包镜像时，.dockeringore 文件本身与所有包含在 .dockeringore 文件中的路径，都不被打包进去。在Dockerfile制作环境为底层镜像启动容器时所能够提供的环境。
2.2 环境变量替换 制作镜像中还可以使用环境变量。环境变量（使用ENV语句声明）也可以在某些指令中使用，因为Dockerfile环境变量在 Dockerfile 中以 $variable_name 或${variable_name}标记。
语法还支持一些标准`bash修饰符
${variable:-word} 表示如果设置了变量，那么结果将是该值。如果未设置变量，那么word将是结果。 ${variable+word} 表示如果设置了变量，则word将是结果，否则结果为空字符串。 三、Dockerfile指令说明 特别说明：Dockerfile中每一条指令都会生成一个新的镜像层。
FROM FROM指令（最重要的一个），必须为Dockerfile文件开篇的第一个非注释行，用于为镜像文件构建过程指定基准镜像，后续的指令运行于此基准镜像所提供的运行环境。基准镜像可以是任何可用镜像文件，默认情况下，docker build会在docker主机上查找指定的镜像文件，在其不存在时，则会从 Docker Hub Registry 上拉取所需的镜像文件。如果找不到指定的镜像文件，docker build 会返回一个错误信息
Syntax:
sh 1 FROM repository[:tag] sh 1 FROM registry/repository[:tag] bash 1 FROM resository@[digest] #←相同名称时，可以使用resository@镜像hush码指定镜像。 参数 说明- reposotiry 某一个镜像的仓库，如redis镜像仓库。 registry docker镜像仓库，如docker hub，docker registry包含很多reposotiry，如nginx php tomcat等。不指定registry，默认从docker hub下载。 tag image的标签，为可选项，省略时默认为latest。 MAINTANIER(depreacted) MAINTANIER（depreacted）用于让Dockerfile制作者提供本人的详细信息。Dockerfile并不限制MAINTAINER指令可在出现的位置，但推荐将其放置于FROM指令之后。</description>
    </item>
    <item>
      <title>Docker跨宿主机网络通信</title>
      <link>https://www.oomkill.com/docker-cross-node-network/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/docker-cross-node-network/</guid>
      <description>Docker Overlay Network Overlay网络是指在不改变现有网络基础设施的前提下，通过某种约定通信协议，把二层报文封装在IP报文之上的新的数据格式。这样不但能够充分利用成熟的IP路由协议进程数据分发；而且在Overlay技术中采用扩展的隔离标识位数，能够突破VLAN的4000数量限制支持高达16M的用户，并在必要时可将广播流量转化为组播流量，避免广播数据泛滥。
因此，Overlay网络实际上是目前最主流的容器跨节点数据传输和路由方案。
要想使用Docker原生Overlay网络，需要满足下列任意条件
Docker 运行在Swarm 使用键值存储的Docker主机集群 使用键值存储搭建Docker主机集群 使用键值存储的Docker主机集群，需满足下列条件：
集群中主机连接到键值存储，Docker支持 Consul、Etcd和Zookeeper 集群中主机运行一个Docker守护进程 集群中主机必须具有唯一的主机名，因为键值存储使用主机名来标识集群成员 集群中linux主机内核版本在3.12+,支持VXLAN数据包处理，否则可能无法通行 部署docker内置的OverLAY网络 环境准备说明 host ip- node01 10.0.0.15 node02 10.0.0.16 安装Consul 下载地址：Download Consul
启动命令
bash 1 2 3 4 5 6 7 8 consul agent -server -bootstrap -ui -data-dir /data/docker/consul \ -client=10.0.0.16 -bind=10.0.0.16 docker run -d -p 8400:8400 -p 8500:8500 -p 8600:53/udp -h consul progrium/consul -server -bootstrap -ui-dir /ui #-ui : consul 的管理界面 #-data-dir : 数据存储 配置docker链接consul bash 1 2 3 4 5 ExecStart=/usr/bin/dockerd \ -H tcp://0.</description>
    </item>
    <item>
      <title>docker容器管理</title>
      <link>https://www.oomkill.com/docker-ma/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/docker-ma/</guid>
      <description>参数 说明 -i, &amp;ndash;interactive 即使不是交互模式也保持stdin打开 -d, &amp;ndash;detach 后台运行容器并打印容器ID -t, &amp;ndash;tty 分配一个伪TTY 添加自定义主机映射
bash 1 2 3 4 5 6 $ docker run -tid --add-host docker-node:10.0.0.1 centos 61d5824c720f1a32c743a3d0f434e17a7f6860dba1cb5559653a80c064da8073 $ docker exec 61d5824c720f1a32c cat /etc/hosts ff02::2	ip6-allrouters 10.0.0.1	docker-node 172.17.0.2	61d5824c720f 添加linux功能
linux内核特性，提供权限访问控制。如需要特殊权限，不赋权限容器将不能正常运行。
将容器pid写入一个文件内
bash 1 2 3 4 $ docker run -itd --cidfile /tmp/pid centos 458d9f4b3cc51a4f0f3abffbc78c643b98a89eef3cdfe263e762ac05d3f5f47d $ cat /tmp/pid 458d9f4b3cc51a4f0f3abffbc78c643b98a89eef3cdfe263e762ac05d3f5f47d 将主机列表添加到容器中
bash 1 --device list 设置自定义dns
bash 1 2 3 4 5 $ docker run -it centos cat /etc/resolv.</description>
    </item>
    <item>
      <title>Docker网络</title>
      <link>https://www.oomkill.com/docker-network/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/docker-network/</guid>
      <description>docker的四种网络模式 Bridge模式（默认） 当Docker进程启动时，会在宿主机上创建一个名为docker0的虚拟网桥，此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似，这样主机上的所有容器就通过交换机连在了一个二层网络中。
默认ip段172.17.0.1/16；从docker0子网中分配一个IP给容器使用，并设置docker0的IP为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备，Docker将veth pair设备的一端放在新创建的容器中，并命名为eth0（容器的网卡），另一端放在主机中，以vethxxx这样类似的名字命名，并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。
使用 docker run -p 时，docker实际是在iptables做了DNAT规则，实现端口转发功能。可以使用 iptables -t nat -nL 查看。
host模式 启动容器的时候使用host模式，那么这个容器将不会获得一个独立的Network Namespace，而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡，配置自己的IP等，而是使用宿主机的IP和端口。但是，容器的其他方面，如文件系统、进程列表等还是和宿主机隔离的。
none模式 使用none模式，Docker容器拥有自己的Network Namespace，但是，并不为Docker容器进行任何网络配置。也就是说，这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。
container模式 这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace，而不是和宿主机共享。新创建的容器不会创建自己的网卡，配置自己的 IP，而是和一个指定的容器共享 IP、端口范围等。同样，两个容器除了网络方面，其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
容器外部访问原理 bash 1 2 3 4 5 6 7 8 docker0: flags=4163&amp;lt;UP,BROADCAST,RUNNING,MULTICAST&amp;gt; mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0 inet6 fe80::42:a5ff:fe59:2034 prefixlen 64 scopeid 0x20&amp;lt;link&amp;gt; ether 02:42:a5:59:20:34 txqueuelen 0 (Ethernet) RX packets 56986 bytes 2746876 (2.6 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 64106 bytes 503304169 (479.</description>
    </item>
    <item>
      <title>macvlan实现docker跨宿主机访问</title>
      <link>https://www.oomkill.com/docker-cross-node-network-macvlan/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/docker-cross-node-network-macvlan/</guid>
      <description>关于vlan说明 Macvlan和ipvlan是Linux网络驱动程序，它们将底层或主机接口直接暴露给在主机中运行的VM或容器。
Macvlan允许单个物理接口使用macvlan子接口具有多个mac和ip地址。这与使用vlan在物理接口上创建子接口不同。使用vlan子接口，每个子接口使用vlan属于不同的L2域，所有子接口都具有相同的mac地址。使用macvlan，每个子接口将获得唯一的mac和ip地址，并将直接暴露在底层网络中。Macvlan接口通常用于虚拟化应用程序，每个macvlan接口都连接到Container或VM。每个容器或VM可以直接从公共服务器获取dhcp地址，就像主机一样。这将有助于希望Container成为传统网络的客户使用他们已有的IP寻址方案。Macvlan有4种类型(Private, VEPA, Bridge, Passthru)。常用的类型是Macvlan网桥，它允许单个主机中的端点能够在没有数据包离开主机的情况下相互通信。对于外部连接，使用底层网络。下图显示了两个使用macvlan网桥相互通信以及外部世界的容器。两个容器将使用Macvlan子接口直接暴露在底层网络中。
使用mavvlan构建docker网络 Macvlan，MACVLAN或MAC-VLAN允许您在单个物理接口上配置多个第2层（即以太网MAC）地址。 Macvlan允许您配置父物理以太网接口（也称为上层设备）的子接口（也称为从设备），每个接口都有自己唯一的（随机生成的）MAC地址，因此也有自己的IP地址。然后，应用程序、VM和容器可以绑定到特定的子接口，以使用自己的MAC和IP地址直接连接到物理网络。
Mavlan子接口不能直接与父接口通信，即VM不能直接与主机通信。如果需要VM主机通信，则应添加另一个macvlan子接口并将其分配给主机。
Macvlan子接口使用 eth0.20@eth0 表示法来清楚地识别子接口及其父接口。子接口状态绑定到其父级状态。如果eth0关闭，则 eth0.20@eth0 也会关闭。
配置macvlan先决条件 至少需要Linux内核版本3.9以上，建议使用4.0或更高版本。 环境准备 主机名 IP地址 地位 软件环境 物理机 10.0.0.1 物理机 windows10 网关 10.0.0.2 宿主机网关 vmvare网关 c1 10.0.0.3 容器01 docker c2 10.0.0.4 容器02 docker node01 10.0.0.15 宿主机01（vm虚拟机） centos 7.3/docker-ce1806 node02 10.0.0.16 宿主机02（vm虚拟机） centos 7.3/docker-ce1806 2.3 启动网卡混合模式 两台主机网卡使用桥接模式,网卡混杂模式开启全部允许。
主机上配置的eth0网卡和创建的vlan网卡,均需要开启混杂模式。如果不开启混杂模式会导致macvlan网络无法访问外界,具体在不使用vlan时,表现为无法ping通路由,无法ping通同一网络内其他主机。
sh 1 2 ip link set eth0 promisc on ip link set eth0 promisc off 开启后查看网卡状态
sh 1 2 3 4 5 6 7 $ ip addr 2: eth0: &amp;lt;BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP&amp;gt; mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:0c:29:84:f3:29 brd ff:ff:ff:ff:ff:ff inet 10.</description>
    </item>
    <item>
      <title>tomcat使用</title>
      <link>https://www.oomkill.com/tomcat/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/tomcat/</guid>
      <description>tomcat介绍 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器，Tomcat是Apache 软件基金会（Apache Software Foundation）的Jakarta 项目中的一个核心项目，它早期的名称为catalina，后来由Apache、Sun 和其他一些公司及个人共同开发而成，并更名为Tomcat。
java体系结构 java程序设计语言（编程） java类文件格式 java api java vm java 纯面向对象语言
obj：以指令为中心，围绕指令组织数据
面向对象：以数据为中心，围绕数据组织指令
Tomcat核心组件：
Catalina：servlet container在tomcat中用于实现servlet代码的被称作Catalina Coyote：一个http连接器，能够接受http请求并相应http请求的web服务器 jasper：JSP Engine jsp翻译器 Tomcat组成部分 Tomcat支持Servlet和JSP1的规范，它由一组嵌套的层次和组件组成，一般可分为以下四类：
顶级组件：位于配置层次的顶级，并且彼此间有着严格的对应关系； 连接器：连接客户端（可以是浏览器或Web服务器）请求至Servlet容器， 容器：包含一组其它组件； 被嵌套的组件：位于一个容器当中，但不能包含其它组件； tomcat常见组件 服务器(server) 服务器(server)顶级组件：Tomcat的一个实例，通常一个JVM只能包含一个Tomcat实例；因此，一台物理服务器上可以在启动多个JVM的情况下在每一个JVM中启动一个Tomcat实例，每个实例分属于一个独立的管理端口。这是一个顶级组件。
server相关属性 className：用于实现此Server容器的完全限定类的名称，默认为 org.apache.cataliana.core.StandardServer;
port：接收shutdown指令的端口，默认仅允许通过本机访问，默认为8005
shutdown：发往此Server用于实现关闭tomcat实例的命令字符串，默认为SHUTDOWN
服务(service) Service主要用于关联一个引擎和此引擎相关的连接器，每个连接器通过一个特定的端口和协议接收入站请求将其转发至关联的引擎进行处理，因此，Service要包含一个引擎（Engine）、一个或多个连接器（Connector）。 定义一个名为Catalina的Service，此名字也会产生相关的日志信息时记录在日志文件当中。
xml 1 &amp;lt;Service name=&amp;#34;Catalina&amp;#34;&amp;gt; Service相关属性 className：用于实现service的类名，一般都是 org.apache.catalina.core.StandardService
name：此服务的名称，默认为Catalina。
连接器(connectors) 分析并接收用户请求，并把它转换成本地jsp文件代码的请求。负责连接客户端（可以是浏览器或Web服务器）请求至Servlet容器内的Web应用程序，通常指的是接收客户发来请求的位置及服务器端分配的端口。 默认端口通常是HTTP协议的8080，管理员也可以根据自己的需要改变此端口。一个引擎可以配置多个连接器，但这些连接器必须使用不同的端口。默认的连接器是基于HTTP/1.1的Coyote。同时，Tomcat也支持AJP、JServ和JK2连接器。
进入Tomcat的请求可以根据Tomcat的工作模式分为如下两类：
Tomcat作为应用程序服务器：请求来自于前端的web服务器，这可能是Apache IIS Nginx。
Tomcat作为独立服务器：请求来自与web浏览器。
Tomcat应该考虑工作情形并为相应情形下的请求分别定义好需要的连接器才能正确接收来自于客户端的请求，一个引擎可以有一个或多个连接器，以适应多种请求方式。
定义连接器可以使用多种属性，有些属性也只是适用于某种特定的连接器类型，
一般来说，常见于server.xml中的连接器类型通常有4种：
HTTP连接器 SSL连接器 AJP 1.3连接器 proxy连接器 xml 1 2 3 &amp;lt;Connector port=&amp;#34;8080&amp;#34; protocol=&amp;#34;HTTP/1.</description>
    </item>
    <item>
      <title>tomcat修改日志目录</title>
      <link>https://www.oomkill.com/tomcat-log-path/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/tomcat-log-path/</guid>
      <description>修改logging.properties text 1 /usr/local/apache-tomcat-8.5.32/conf/logging.properties bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ############################################################ # Handler specific properties. # Describes specific configuration info for Handlers. ############################################################ 1catalina.org.apache.juli.AsyncFileHandler.level = FINE 1catalina.org.apache.juli.AsyncFileHandler.directory = /data/logs 1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina. 2localhost.org.apache.juli.AsyncFileHandler.level = FINE 2localhost.org.apache.juli.AsyncFileHandler.directory = /data/logs 2localhost.org.apache.juli.AsyncFileHandler.prefix = localhost. 3manager.org.apache.juli.AsyncFileHandler.level = FINE 3manager.org.apache.juli.AsyncFileHandler.directory = /data/logs 3manager.org.apache.juli.AsyncFileHandler.prefix = manager. 4host-manager.org.apache.juli.AsyncFileHandler.level = FINE 4host-manager.</description>
    </item>
    <item>
      <title>容器的资源限制</title>
      <link>https://www.oomkill.com/container-limit/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/container-limit/</guid>
      <description>默认情况下，容器没有任何资源限制，因此几乎耗尽docker主机之上，内核可分配给当前容器的所有资源。可以使用主机内核调度程序允许的尽可能多的给定资源。在此基础上Docker provides提供了控制容器可以使用多少内存，CPU或块IO的方法，设置docker run命令的运行时配置标志。
容器得以实现主要依赖于内核中的两个属性namespace cgroup。其中许多功能都要求您的内核支持Linux功能。要检查支持，可以使用docker info命令。
Memory OOME
在Linux主机上，如果内核检测到没有足够的内存来执行重要的系统功能，它会抛出OOME或Out of Memory Exception异常，并开始终止进程以释放内存资源。一旦发生OOME，任何进程都有可能被杀死，包括docker daemon自身在内。为此，Docker特地调整了docker daemon的OOM优选级，以免它被内核“正法”，但容器的优选级并未被调整。
工作逻辑为
在宿主机上跑有很多容器并包括系统级进程。系统级进程也包括docke daemon自身。当内核执行系统管理操作，如内核需要使用内存，发现可以内存已经为空，会启动评估操作，评估谁占用内存高。我们认为哪个资源占用内存高就该将其kill来释放内存空间。（需要注意的是占用内存高的进程也不一定被kill掉。A进程分配10G已使用5G，进程B分配1G已使用1G。A只使用50%内存，而B已经耗尽所有内存）。内核会提供这些进程进行评分，按照优先级逆序强制kill，直至可使用内存空间足够。此时内核就可以使用内存资源创建其他进程。
每一个进程被计算之后会有一个oom scores，得分越高就会被优先kill。得分是由内存申请分配空间等一系列复杂计算得知。当进程得分最高也不能被kill掉时，如docker daemon，此时需要调整优先级。每一个进程有一个oom.adj的参数，将优先级调整越低，计算的分数就越少。
在docker run时可以直接调整容器的OOM.adj参数。如果想限制容器能使用多少内存资源、或CPU资源，有专门的选项可以实现。非常重要的容器化应用需要在启动容器时调整其OOM.adj，还可以定义容器的策略，一旦被kill直接restart
Limit a container&amp;rsquo;s resources
限制一个容器能使用多少内存资源或CPU资源docker有专门的选项来实现
-m 限制容器可用RAM空间。选项参数可以使用KB M G等作为接受单位使用。可单独使用。
--memory-swap 设置容器可用交换分区大小。使用swap允许容器在容器耗尽可用的所有RAM时将多余的内存需求写入磁盘。--memory-swap是一个修饰符标志，只有在设置了&amp;ndash;memorys时才有意义。
--memory-swap
--memory-swap --memory 功能 正数S 正数 M 容器可用总空间为S，其中可用ram为M 0 正数 M相当于未设置swap（unset） unset（未设置） 正数 M 若主机（Docker Host）启用了swap，则容器的可用swap为 2*M -1 正数M 若主机（Docker Host）启用了swap，则容器可使用交换分区总空间大小为宿主机上的所有swap空间的swap资源 注意：在容器内使用free命令可以看到的swap空间并不具有其所展现出的空间指示意义。 &amp;ndash;memory-swappiness
用来限定容器使用交换分区的倾向性。
&amp;ndash;memory-reservation
预留的内存空间
&amp;ndash;oom-kill-disable
禁止oom被kill掉
默认情况下，每个容器对主机CPU周期的访问权限是不受限制的。可以设置各种约束来限制给定容器访问主机的CPU周期。大多数用户使用和配置默认CFS调度程序。在Docker 1.13及更高版本中，还可以配置实时调度程序。 CPU Limit a container&amp;rsquo;s resources
内核中进程管理子系统当中最重要的组件为进程角度器scheduler，非实时优先级,有效范围为100-139[-20,19]。因此每个进程的默认优先级为120。实时优先级0-99。调度100-139之间的进程有个非常重要的调度器CFS scheduler（完全公平调度器），公平调度每一个进程在需要执行时，去分配scores到这个进程上。</description>
    </item>
    <item>
      <title>使用weave实现docker跨宿主机通讯</title>
      <link>https://www.oomkill.com/weave-over-host/</link>
      <pubDate>Sat, 02 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/weave-over-host/</guid>
      <description>项目地址：https://github.com/weaveworks/weave
注：weave公司与2024年关门
weaves说明 Weave是由weaveworks公司开发的解决Docker跨主机网络的解决方案，它能够创建一个虚拟网络，用于连接部署在多台主机上的Docker容器，这样容器就像被接入了同一个网络交换机，那些使用网络的应用程序不必去配置端口映射和链接等信息。
外部设备能够访问Weave网络上的应用程序容器所提供的服务，同时已有的内部系统也能够暴露到应用程序容器上。Weave能够穿透防火墙并运行在部分连接的网络上，另外，Weave的通信支持加密，所以用户可以从一个不受信任的网络连接到主机。
weaves实现原理 weave launch初始化时会自动下载三个docker容器来辅助运行，并且创建linux网桥与docker网络
weave 运行了三个容器：
weave 是主程序，负责建立weave网络，收发数据，提供 DNS 服务等。 weavevolumes容器提供卷存储 weavedb容器提供数据存储 sh 1 2 3 4 5 6 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE weaveworks/weavedb latest 15c78a9b1895 4 weeks ago 698B weaveworks/weaveexec 2.4.0 bf0c403ea58d 4 weeks ago 151MB weaveworks/weave 2.4.0 7aa67bc6bc43 4 weeks ago 96.7MB 自动创建网桥
sh 1 2 3 4 5 $ brctl show bridge name	bridge id	STP enabled	interfaces docker0	8000.</description>
    </item>
    <item>
      <title>SSH客户端应用场景</title>
      <link>https://www.oomkill.com/ssh-client-application/</link>
      <pubDate>Fri, 18 May 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ssh-client-application/</guid>
      <description>SSH命令详解 参数 说明 -1 强制使用ssh协议版本1； -2 强制使用ssh协议版本2； -4 强制使用IPv4地址； -6 强制使用IPv6地址； -A 开启认证代理连接转发功能； -a 关闭认证代理连接转发功能； -b 使用本机指定地址作为对应连接的源ip地址； -C 请求压缩所有数据； -F 指定ssh指令的配置文件； -f 后台执行ssh指令； -g 允许远程主机连接主机的转发端口； -i 指定身份文件； -l 指定连接远程服务器登录用户名； -N 不执行远程指令； -o 指定配置选项； -p 指定远程服务器上的端口； -q 静默模式； -X 开启X11转发功能； -x 关闭X11转发功能； -y 开启信任X11转发功能。 -D 指定本地 “动态” 应用程序级端口转发。这通过分配套接字来侦听本地端口，可选地绑定到指定的bind_address。只要与此端口建立连接，就会通过安全通道转发连接，然后使用应用程序协议确定从远程计算机连接的位置。 SSH端口转发实战 概述 在通常情况下，网络防火墙会阻碍你进行某些必要的网络传输。公司的安全策略可能不允许你把SSH密钥存储在某些主机上。或者，你也可能需要在原本安全的环境中运行一些不安全的网络应用程序。
SSH提供了一个重要功能，称为转发forwarding或者称为隧道传输tunneling，它能够将其他 TCP 端口的网络数据通过 SSH 链接来转发，并且自动提供了相应的加密及解密服务。这一过程有时也被叫做tunneling，这是因为 SSH 为其他 TCP 链接提供了一个安全的通道来进行传输而得名。
SSH端口转发主要用来解决如下两方面问题：
突破防火墙的限制完成无法建立的 TCP 连接。 加密 Client 端至 Server 端之间的通讯数据。 开启ssh的端口转发功能 ssh端口转发功能默认是打开的。如需修改的话，修改后需要重启sshd服务才会生效。</description>
    </item>
    <item>
      <title>tcp.validnode_checking踩过的坑</title>
      <link>https://www.oomkill.com/oracle-tcp.validnode_checking/</link>
      <pubDate>Sun, 06 May 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/oracle-tcp.validnode_checking/</guid>
      <description>对Oracle 检查ip合法性,就必须在服务器端的sqlnet.ora文件中设置如下参数
text 1 2 TCP.INVITED_NODES=(10.0.0.36,10.0.0.1,10.0.0.35) TCP.EXCLUDED_NODES=(10.0.0.2) 启动监听出现如下错误
text 1 2 3 4 5 6 7 8 9 10 11 $ lsnrctl status LSNRCTL for Linux: Version 11.2.0.1.0 - Production on 12-MAR-2018 18:32:13 Copyright (c) 1991, 2009, Oracle. All rights reserved. Connecting to (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521)) TNS-12541: TNS:no listener TNS-12560: TNS:protocol adapter error TNS-00511: No listener Linux Error: 111: Connection refused 错误输出并没有打印详细的信息,从lisenter.ora,tnsnames.ora入手,但没有发现文件是错误的。最后检查sqlnet.ora,发现TCP.INVITED_NODES参数有如下约束是官方文档没有给出的
tcp.invited_nodes需要满足如下条件才可成功启动监听
1、需要设置参数TCP.VALIDNODE_CHECKING为YES才能激活该特性。 2、tcp.invited_nodes的值中一定要包括本机地址（127.0.0.1 / 10.0.0.36）或localhost，因为监听需要通过本机ip去访问监听，一旦禁止lsnrct将不能启动或停止监听。 3、不能设置ip段和通配符。 4、此方式只适合tcp/ip协议。 5、此方式是通过监听限制白名单的。 6、针对的是ip地址而不是其他（如用户名等）。 7、此配置适用于9i以上版本。本次踩坑是oracle11gr2。 8、修改配置后需要重启监听才可生效。 TCP.</description>
    </item>
    <item>
      <title>jenkins多个slave遇到的坑</title>
      <link>https://www.oomkill.com/jenkins-multi-slave-problem/</link>
      <pubDate>Wed, 02 May 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/jenkins-multi-slave-problem/</guid>
      <description>jenkins配置如下 在Jenkins上添加了两个节点(Slave Node)，且为这两个节点设置了一个相同的标签 &amp;ldquo;windows&amp;rdquo;。创建了一个新Job – &amp;ldquo;test-windows&amp;rdquo;，选择的是”构建一个自由风格的软件项目”。并且为了使多个slave并行构建，我选择了&amp;quot;只允许绑定到这台机器的job”，在&amp;quot;Label Expression&amp;quot;中选择了&amp;quot;windows&amp;quot;。
然而这种方式并不能实现多个slave并行操作。网上90%说的都不靠谱。
在我使用的过程中，使用了label 去管理多个 Slave，给一个项目的构建指定了这个 label，会发现这个项目的多次构建，都使用同一个 Slave，并没有使用 label 里的其它 Slave去构建。
查了很多资料才发现原来从 jenkins 的调度算法使用了一致性的哈希算法，jenkins根据添加的信息评测出优先级列表，选择优先级最高的Slave去构建，当最优slave不满足条件或者没有可用的 execut时，才会选用下一个slave。
查了很多资料发现构造多配置项目可以选择构建时的slave。这样可以实现多slave并行构建。
multi configuration project比起构建自由风格的软件项目多个Configuration Matrix，在这里可以选择多个slave。这里选择lable的话，还是会使用默认算法从lable中选择最优slave进行构建。
配置完成后再构建时，会同时在多个slave上进行并行构建
禁止在master上运行job或和业务相关的操作
将 [executors] 设置为0</description>
    </item>
    <item>
      <title>jenkins检查代码 如没更新停止构建步骤</title>
      <link>https://www.oomkill.com/jenkins-checkcode/</link>
      <pubDate>Wed, 02 May 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/jenkins-checkcode/</guid>
      <description>需求分析 在jenkins中没有找到构建前插件，每次构建时间很长，希望可以实现判断代码是否更新，如果没更细则停止构建步骤。
实现步骤 在构建时执行shell命令，而jenkins提供的的环境变量可以实现此判断 https://wiki.jenkins.io/display/JENKINS/Conditional+BuildStep+Plugin
text 1 2 3 4 5 6 GIT_COMMIT The commit hash being checked out. GIT_PREVIOUS_COMMIT The hash of the commit last built on this branch, if any. GIT_PREVIOUS_SUCCESSFUL_COMMIT The hash of the commit last successfully built on this branch, if any. GIT_COMMIT 当前拉取版本的commit id GIT_PREVIOUS_COMMIT 最后在此分支上构建的 commit id GIT_PREVIOUS_SUCCESSFUL_COMMIT 最后在此分支上成功构建的 commit id号
text 1 2 3 4 5 6 7 8 #!/bin/bash if [ $GIT_PREVIOUS_SUCCESSFUL_COMMIT == $GIT_COMMIT ];then echo &amp;#34;no change，skip build&amp;#34; exit 0 else echo &amp;#34;git pull commmit id not equals to current commit id trigger build&amp;#34; fi 注意，不能使用-eq 只能使用 “==” 提交新版本后，构建提示如下：</description>
    </item>
    <item>
      <title>windows上sqlplus客户端连接oralce数据库中文显示问题</title>
      <link>https://www.oomkill.com/sqlplus-windows/</link>
      <pubDate>Thu, 19 Apr 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/sqlplus-windows/</guid>
      <description>运行环境 服务器：centos6.8
服务器oracle版本：oracle 11g R2 64位，字符集是ZHS32utf8。
客户端：navicat 12x64 windows8.1x64
问题分析 当在windows客户端使用sqlplus或navicat时如果数据库中文显示“????”
这种情况是在客户端与服务器端字符集不一致时，从客户端输入了汉字信息。输入的这些信息即便是把客户端字符集更改正确，也无法显示汉字。
解决方法：退出sqlplus,设置相应的环境变量NLS_LANG
linux：
text 1 export NLS_LANG=&amp;#34;SIMPLIFIED CHINESE_CHINA.ZHS16GBK&amp;#34; windows：
出现问题 此时。系统cmd命令行使用sqlplus已经正常显示中文，但是navicat中依旧是？？？？
图为cmd命令行访问sqlplus客户端查询
图为navicat f6弹出的sqlplus客户端
原因是因为Navicat Premium默认自带的instant client，但是其是base lite版本的（Basic Lite： Basic 的精简版本，其中仅带有英文错误消息和 Unicode、ASCII 以及西欧字符集支持），不支持中文字符集，而本文中的服务器端oracle恰好是中文字符集。自带版本不支持。此处需要去oracle官网下载相对应的版本。
http://www.oracle.com/technetwork/database/database-technologies/instant-client/downloads/index.html
将下载的文件解压覆盖navicat中的instantclient目录里的文件。
此时连接oracle实例提示如下信息
尽管我们下载了64位的版本。却提示如图信息。这是因为Navicat仅支持32位的，因此还需下载一个32位的客户端。替换到instantclient目录中
替换完成后连接实例。f6使用sqlplus查询发现中文已经正常显示</description>
    </item>
    <item>
      <title>jenkins github tag使用方式</title>
      <link>https://www.oomkill.com/jenkins-github-tag/</link>
      <pubDate>Fri, 02 Feb 2018 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/jenkins-github-tag/</guid>
      <description>jenkins github tag
测试项目地址：GitHub - go-redis\redis: Type-safe Redis client for Golang
插件下载地址：[git-parameter](http:\updates.jenkins-ci.org\download\plugins\git-parameter)
pt-online-schema-change
Jenkins中配置gradle项目的坑 - doctorq - CSDN博客</description>
    </item>
    <item>
      <title>详解haproxy</title>
      <link>https://www.oomkill.com/haproxy/</link>
      <pubDate>Thu, 16 Nov 2017 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/haproxy/</guid>
      <description>haproxy 介绍 haproxy是一个开源的、高性能的基于TCP和HTTP应用代理的高可用的、负载均衡服务软件，它支持双机热备、高可用、负载均衡、虚拟主机、基于TCP和HTTP的应用代理、图形界面查看信息等功能。其配置简单、维护方便，而且拥有很好的对服务器节点的健康检查功能(相当于keepalived健康检查)，当其代理的后端服务器出现故障时，haproxy会自动的将该故障服务器摘除，当故障的服务器恢复后，haproxy还会自动将该服务器自动加入进来提供服务。
LVS/NGINX对比 haproxy 特别适用于那些高负载、访问量很大，但又需要会话保持及七层应用代理的业务应用。haproxy运行在今天的普通的服务器硬件上，几乎不需要进行任何的优化就可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单、轻松、安全的整合到各种己有的网站架构中，同时，haproxy的代理模式，可以使得所有应用服务器不会暴露到公共网络上，即后面的节点服务器不需要公网IP地址。
从1.3版本起，haproxy软件引入了frontend,backend的功能，frontend (ad规则匹配)可以让运维管理人员根据任意HTTP请求头内容做规则匹配，然后把请求定向到相关的backend(这个是事先定义好的多个server pools，等待前端把请求转过来的服务器组)。通过frontend和backend，我们可以很容易的买现haproxy的各种7层应用代理功能。
haproxy代理模式 haproxy支持两种主要代理模式：
1、基于4层的tcp应用代理(例如:可用于邮件服务、内部协议通信服务器、MySQL、HTTPS服务等)。
2、基于7层的http代理。在4层tcp代理模式下，haproxy仅在客户端和服务器之间进行流量转发。但是在7层http代理模式下，haproxy会分析应用层协议，并且能通过允许、拒绝、交换、增加、修改或者删除请求(request)或者回应(response)里指定内容来控制协议。
官方网站:www.haproxy.org
haproxy 解决方案拓扑图 haproxy L4负载均衡应用架构拓扑 haproxy软件的四层tcp应用代理非常优秀，且配置非常简单、方便，比LVS和Nginx的配置要简单很多，首先，配置haproxy不需要在RS端做任何特殊配置 (只要对应服务开启就OK)就可以实现应用代理，其次，haproxy的配置语法和增加虚拟主机功能等也比lvs/nginx简单。并且和商业版的NS (Netscaler)、F5, A10等负载均衡硬件的使用方法和在架构中的位置一模一样。下面是haproxy的Layer4层应用代理的拓扑结构图:
说明:由于haproxy软件采用的是类NAT模式(本质不同)的应用代理，数据包来去都会经过haproxy，因此，在流量特别大的情况下(门户级别的流量)，其效率和性能不如LVS的DR模式负载均衡。
在一般的中小型公司，建议采用haproxy做负载均衡，而不要使用LVS或Nginx。为什么强调中小型公司呢?换句话说，千万PV级别以下直接使用haproxy做负载均衡，会让我们负责维护的运维管理人员配置简单、快速、维护方便，出问题好排查。
haproxy L7负载均衡应用架构拓扑 haproxy软件的最大优势在于其7层的根据URL请求头应用过滤的功能以及sesson会话功能，在门户网站的高并发生产架构中，haproxy软件一般用在4层LVS负载均衡软件的下一层，或者像haproxy官方推荐的也可以挂在硬件负载均衡althon, NS, F5, A10下使用，其表现非常好。从2009年起taobao，京东商城的业务也大面积使用了haproxy作为7层CACHE应用代理。
安装haproxy 模拟真实环境
搭建合适的模拟环境是一个人学习能力的重要体现。例如：人类第一次上太空也没有真正的环境，但是想去太空就是要自己动手去搭建逼真的模拟环境。实验多了就是经验，自然就有解除生产环境的机会了。
名称 接口 IP 用途 MASTER eth0 10.0.0.7 外网管理IP用于WAN数据转发 eth1 172.16.1.7 内网管理IP，用于LAN数据转发 eth2 10.0.10.7 用于服务器间心跳连接（直连） VIP 10.0.0.17 用于提供应用程序A挂载服务 BACKUP eth0 10.0.0.8 外网管理IP，用于WAN数据转发 eth1 172.16.1.8 内网管理IP，用于LAN数据转发 eth2 10.0.10.8 用于服务器间心跳连接（直连） VIP 10.0.0.8 用于提供应用程序B挂载服务 下载安装haproxy 下载地址：http://www.haproxy.org/download/
文档地址：http://www.haproxy.org/download/1.7/doc/configuration.txt
编译haproxy bash 1 2 3 4 make TARGET=linux2628 ARCH=x86_64 # &amp;lt;==64位编译配置 make TARGET=linux2628 ARCH=i386 # &amp;lt;==32位编译配置 make PREFIX=/app/haproxy-1.</description>
    </item>
    <item>
      <title>ch08 - MySQL存储引擎</title>
      <link>https://www.oomkill.com/ch8-mysql-engine/</link>
      <pubDate>Tue, 23 May 2017 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch8-mysql-engine/</guid>
      <description>什么是存储引擎 在经清楚什么是存储引擎之前，我们先来个比喻，我们都知道录制一个视频文件，可以转换成不同的格式如mp4 avi wmv等，而存在我们电脑的磁盘上也会存在于不同类型的文件系统中如windows里常见的ntfs fat32，存在于linux常见的ext3 ext4 xfs，但是，给我们或者用户看到实际视频内容都是一样的。直观区别是，占用系统的空间大小与清晰程度可能不一样。
那么数据库表里的数据存储在数据库里及磁盘上和上述的视频格式及存储磁盘文件系统格式特征类似，也有很多中存储方式。
但是，对于用户和应用程序来说同样一张表的数据，无论用什么引擎来存储，用户看到的数据都是一样的。不同的引擎存储，引擎功能，占用的空间大小，读取性能等可能有区别。
MySQL最常用的存储引擎为：MyISAM和InnoDB。全文索引：目前MySQL5.5版本，myisam和inondb都已经支持。
MySQL存储引擎的架构 MySQL的存储引擎是MySQL数据库的重要组成部分，MySQL常用的表的引擎为MyISAM和InnoDB两种。MySQL的每种存储引擎在MySQL里是通过插件的方式使用的，MySQL可以同时支持多种存储引擎。下面是MySQL存储引擎体系结构简图：
MyISAM引擎 MyISAM引擎是MySQL关系数据库管理系统的默认存储引擎（MySQL 5.5.5以前）。这种MySQL表存储结构从旧的ISAM代码扩展出许多有用的功能。在新版本MySQL中，InnoDB引擎由于其对事务参照完整性，以及更高的并发性等优点开始逐步的取代MyISAM引擎，
“InnoDB is the default storage engine as of MySQL 5.5.5。MyISAM: The MySQL storage engine that is used the most in Web,data warehousing,and other application environments.MyISAM is supported in all MySQL configurations,an is the default storage engine prior to MySQL 5.5.5。”
查看MySQL5.1数据库默认引擎
bash 1 2 3 4 5 6 7 mysql&amp;gt; show create table test1\G *************************** 1.</description>
    </item>
    <item>
      <title>ch07 - 实现和MySQL非交互式对话</title>
      <link>https://www.oomkill.com/ch7-mysql-non-interact/</link>
      <pubDate>Mon, 22 May 2017 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch7-mysql-non-interact/</guid>
      <description>利用 mysql -e 参数查看 mysql 数据 bash 1 2 3 4 5 6 7 8 $ mysql -uroot -p111 -e &amp;#39;use test;show tables;&amp;#39; +------------------------------+ | Tables_in_test | +------------------------------+ | 33hao_activity | | 33hao_activity_detail | | 33hao_address | +------------------------------+ 利用 mysql -e 参数查看SQL线程执行状态
bash 1 2 $ mysql -uroot -p111 -e &amp;#39;show processlist;&amp;#39; kill 12; 查看完整的线程状态，此参数才查看慢查询语句是非常有用
解决方法：
bash 1 2 3 4 root@localhost [test]&amp;gt;show variables like &amp;#39;%_timeout%&amp;#39;; # 设置 set global wait_timeout=60; set global interactive_timeout=60; 在配置文件里修改 text 1 2 set global wait_timeout=60; set global interactive_timeout=60; # 此参数设置后wait_timeout自动生效 其他方法 (1) PHP程序中，不适用持久链接，即 mysql_connect 而不是 pconnect（java调整连接池）</description>
    </item>
    <item>
      <title>ch04 - MySQL数据库服务日志类型</title>
      <link>https://www.oomkill.com/ch04-mysql-log/</link>
      <pubDate>Sun, 21 May 2017 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch04-mysql-log/</guid>
      <description>错误日志 error log MySQL错误日志记录MySQL服务进程mysqld在启动/关闭或运行过程中遇到的错误信息
错误日志配置
在配置文件中调整方法，当然可以在启动时加入启动参数
bash 1 2 [mysqld_safe] log-error=/data/3306/mysql_3306.err 启动MySQL命令里加入
bash 1 2 3 4 5 6 7 8 9 10 /app/mysql/bin/mysqld_safe \ --defaults-file=/data/3306/my.cnf \ --log-error=/data/3306/mysql_3306.err MariaDB&amp;gt; show variables like &amp;#34;%log_error%&amp;#34;; +-------------------+---------------------------+ | Variable_name | Value	| +-------------------+---------------------------+ | log_error | /data/3306/mysql_3306.err | +-------------------+---------------------------+ 遇到数据库启动不了
先把日志文件备份并清空启动一下mysql服务后再查看日志文件，看报有什么错误
bash 1 2 3 InnoDB: The error means mysqld does not have the access rights to InnoDB: the directory 然后查看mysql3306目录下文件权限
普通查询日志 general query log 普通查询日志 (general query log)：记录客户端链接信息和执行的SQL语句信息。</description>
    </item>
    <item>
      <title>ch06 - MySQL主从复制</title>
      <link>https://www.oomkill.com/ch6-mysql-replication/</link>
      <pubDate>Sun, 21 May 2017 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch6-mysql-replication/</guid>
      <description>Linux文件数据同步方案 在讲解MySQL主从复制之前，先回忆下，前面将结果的普通文件（磁盘上的文件）的同步方法。
文件级别的异机同步方案
scp/sftp/nc命令可以实现远程数据同步。 搭建ftp/http/svn/nfs服务器，然后在客户端上也可以把数据同步到服务器。 搭建samba文件共享服务，然后在客户端上也可以把数据同步到服务器。 利用rsync/csync2/union等均可以实现数据同步。 提示：union可实现双向同步，csync2可实现多机同步。
​	以上文件同步方式如果结合定时任务或innotify sersync等功能，可以实现定时以及实时的数据同步。
扩展思想：文件级别复制也可以利用mysql,mongodb等软件作为容器实现。
扩展思想：程序向两个服务器同时写数据，双写就是一个同步机制。
​	特点：简单、方便、效率和文件系统级别要差一些，但是被同步的节点可以提供访问。
软件的自身同步机制（mysql、oracle、mongdb、ttserver、redis&amp;hellip;..），文件放到数据库，听不到从库，再把文件拿出来。 文件系统级别的异机同步方案
drbd基于文件系统同步，相当于网络RAID1，可以同步几乎任何业务数据。
mysql数据的官方推荐drbd同步数据，所有单点服务例如：NFS，MFS(DRBD)，MySQL等度可以用drbd做复制，效率很高，缺点：备机服务不可用。
数据库同步方案
自身同步机制：mysql relication，（逻辑的SQL重写）物理复制方法drbd（丛库不提供读写）。 第三方drbd MySQL主从复制概述 MySQL的主从复制方案，和上述文件及文件系统级别同步是类似的，都是数据的传输。只不过MySQL无需借助第三方工具，而是其自带的同步复制功能，另外一点，MySQL的主从复制并不是磁盘上文件直接同步，而是逻辑的binlog日志绒布到本地在应用执行的过程
MySQL主从复制是一个异步的复制过程（虽然一般情况下感觉是实时的），数据将从一个MySQL数据库（Master）复制到另一个数据库（Slave），在 mater 与 Slave之 间实现整个主从复制的过程是由三个线程参与完成的。其中有两个线程( SQL和IO )在Slave端，另外一个线程（I/O）在Master端。
要实现MySQL的主从复制，首先必须打开 Master 端的 binlog 记录功能，否则就无法实现。因为整个复制过程实际上就是Slave从Master端获取Binlog日志，然后在Slave上以相同顺序逐自获取 binlog 日志中所记录的各种SQL操作。
要打开MySQL的binlog记录功能，可能通过在MySQL的配置文件 my.cnf 中的 mysqld 模块( [mysqld] )标识后的参数部分增加 “log-bin” 参数选项来实现，具体信息如下：
bash 1 2 [mysqld] log-bin = /data/3307/mysql-bin 提示：log-bin需放置在[mysqld]标识后，否则会导致配置复制不成功。
MySQL数据可支持单向、双向、链式级联等不同场景的复制。在复制过程中，一台服务器充当主服务器（Master），而一个或多个其他的服务器充当从服务器（Slave）。
复制可以使单向：M==&amp;gt;S，也可以是双向 M&amp;lt;==&amp;gt;M，当然也可以多M环装同步等。
如果设置了链式级联复制，那么，从（slave）服务器本身除了充当从服务器外，也会同时充当其下面从服务器的主服务器。链式级联复制类似 A==&amp;gt;B==&amp;gt;C==&amp;gt;D 的复制形式。
下面是MySQL各种同步架构的逻辑图。
单向主从复制逻辑图，次架构只能在Master端进行数据写入。官方给出Slave最多9，工作中不要超过5
双向主主同步逻辑图，次架构可以再Master1端或Master2端进行数据写入
线性级联单向双主同步逻辑图，此架构只能在Master1端进行数据写入
缺陷：1 ==&amp;gt;3 之间会存在延迟
环装级联单向多主同步逻辑图，任意一个点都可以写入数据。</description>
    </item>
    <item>
      <title>ch02 - MySQL安全相关配置</title>
      <link>https://www.oomkill.com/ch2-mysql-security/</link>
      <pubDate>Tue, 16 May 2017 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch2-mysql-security/</guid>
      <description>设置MySQL管理员账号密码 在安装MySQL数据库后，MySQL管理员的账号root密码默认为空，极不安全
启动修改丢失的MySQL单实例root密码方法
停止MySQL
bash 1 /etc/init.d/mysqld stop 使用 &amp;ndash;skip-grant-tables启动mysql，忽略授权登陆验证
bash 1 2 3 4 5 6 7 8 9 10 11 # 单实例 /app/mysql/bin/mysqld_safe --skip-grant-tables --user=mysql # 多实例 /app/mysql/bin/mysqld_safe --defaults-file=/data/3306/my.cnf --user=mysql --skip-grant-tables &amp;amp; # 登录时空密码 $ mysql -S /data/3306/mysql.sock ... ... Welcome to the MySQL monitor. Commands end with ; or \g. # 在启动时加 --skip-grant-tables参数，表示忽略授权 修改root密码为新密码
bash 1 2 3 4 5 6 mysql&amp;gt; set password=password(&amp;#39;123&amp;#39;); ERROR 1290 (HY000): The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement mysql&amp;gt; update mysql.</description>
    </item>
    <item>
      <title>ch05 - MySQL字符集相关配置</title>
      <link>https://www.oomkill.com/ch5-mysql-charset/</link>
      <pubDate>Mon, 15 May 2017 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch5-mysql-charset/</guid>
      <description>MySQL数据库字符集介绍 简单来说，字符集就是一套文字符号及其编码、比较规则的集合，第一个计算机字符集ASCII！
MySQL数据库字符集包括字符集(character)和校对规则(collation)两个概念。其中，字符集是用来定义MySQL数据字符串的存储方式。而校对规则则是定义比较字符串的方式。
上面命令查看已建立的test数据库语句中 CHARACTER SET latin1即为数据库字符集，而COLLATE latin1_swedish_ci为校对规则，更多内容 见mysql手册第10章。
编译MySQL时，指定字符集了，这样以后建库的时候就直接create database test;
二进制安装MySQL，并没有指定字符集，这时字符集默认latin1，此时，需要建立UTF8字符集的库，就需要指定UTF8字符集建库。
sql 1 create database test1 default character set utf8 default collate=utf8_general_ci; MySQL常见字符集介绍 在互联网环境中，使用MySQL时常用的字符集有：
常用字符集 一个汉字长度（字节） 说明 GBK 2 不是国际标准，对中文环境支持很好。 UTF8 3 中英文混合环境，建议使用此字符集，用的比较多的。 latin1 1 MySQL的默认字符集 utf8mb4 4 UTF8 Unicode，移动互联网 MySQL如何选择合适的字符集？ 如果处理各种各样的文字，发布到不同语言的国家地区，应选Unicode字符集，对MySQL来说就是utf-8（每个汉字三个字节），如果应用需处理英文，仅有少量汉字的utf-8更好。
如果只需支持中文，并且数据两很大，性能要求也高，可选GBK（定长 每个汉字占双字节，英文也占双字节），如果需大量运算，比较排序等，定长字符集更快，性能
处理移动互联网业务，可能需要使用utf8mb4字符集。
如无特别需求，选择UTF8
查看MySQL字符集 查看当前MySQL系统支持的字符集
MySQL可支持多种字符集，同一台机器，库或表的不同字段都可以指定不同的字符集。
sql 1 2 3 4 5 6 7 8 9 mysql&amp;gt; show character set; +----------+-------------------------+---------------------+--------+ | Charset | Description | Default collation | Maxlen | +----------+-------------------------+---------------------+--------+ | latin1 | cp1252 West European | latin1_swedish_ci | 1 | | gbk | GBK Simplified Chinese | gbk_chinese_ci | 2 | | utf8 | UTF-8 Unicode | utf8_general_ci | 3 | | utf8mb4 | UTF-8 Unicode | utf8mb4_general_ci | 4 | +----------+-------------------------+---------------------+--------+ 查看MySQL当前的字符集设置情况</description>
    </item>
    <item>
      <title>ch03 - MySQL的备份与恢复</title>
      <link>https://www.oomkill.com/ch3-mysql-backup-and-restore/</link>
      <pubDate>Sun, 14 May 2017 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch3-mysql-backup-and-restore/</guid>
      <description>备份数据库的意义 运维工作到底是什么工作，到底是做什么？
运维工作简单的概括就两件事：
一是保护公司的数据；二是网站7*24小时提供服务。
那么对数据丢失一部分和网站7*24小时提供服务那个更重要呢？
都很重要，只是说相比哪个更为重要？这个具体要看业务个公司。例如：银行、金融行业，数据是最重要的，一条都不能丢，可能宕机停机影响就没那么大。百度搜索，腾讯qq聊天记录丢失了几万条数据，都不算啥。
对于数据来讲，数据最核心的就是数据库数据。
备份单个数据库练习多种参数的使用 MySQL数据库自带了一个很好用的备份命令，就是mysqldump，它的基本使用如下：
sql 1 mysqldump -u UserName -p PassWord dbName &amp;gt; backName.sql 备份库 sql 1 mysqldump -S /data/3306/mysql.sock -uroot -p test&amp;gt;mysql.sql 检查备份结果
sql 1 2 3 4 5 6 7 8 9 10 11 12 $ egrep -v &amp;#34;#|\*|--|^$&amp;#34; ./mysql.sql DROP TABLE IF EXISTS `test1`; CREATE TABLE `test1` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `num1` varchar(20) NOT NULL, `num2` varchar(20) NOT NULL, `num3` varchar(20) NOT NULL, `num4` int(11) NOT NULL DEFAULT &amp;#39;0&amp;#39; COMMENT &amp;#39;test1&amp;#39;, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2000001 DEFAULT CHARSET=utf8; LOCK TABLES `test1` WRITE; INSERT INTO `test1` VALUES (1,&amp;#39;1455577&amp;#39;,&amp;#39;9779520&amp;#39;,&amp;#39;4530868&amp;#39;,0), 注：因为导出时的格式没有加字符集，一般恢复到数据库里会正常，只是系统外查看不正常而已。另外，insert是批量插入的方式，这样在恢复时效率很高。</description>
    </item>
    <item>
      <title>ch01 - Linux下安装Mysql</title>
      <link>https://www.oomkill.com/ch1-mysql-deployment/</link>
      <pubDate>Fri, 12 May 2017 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch1-mysql-deployment/</guid>
      <description>MySQL数据库简介 编程语言排名：http://www.tiobe.com/tiobe-index
数据库排名：http://db-engines.com/en/ranking
MySQL数据库分类与版本升级 MySQL数据库官网为http://www.mysql.com，其发布的MySQL版本采用双授权政策，和大多数开源产品的路线一样，分别为社区版和商业版，而这两个版本又各自分四个版本依次发布，这四个版本为Alpha版、Beta版、RC版和GA版（GA正式发布版）
MySQL数据库商业版和社区版的区别 在前面的内容已经阐述过了，MySQL的版本发布采用双授权政策，即分为社区版和商业版，而这两个版本又各自分四个版本依次发布：Alpha版、Beta版、RC版和GA版（GA正式发布版）
Alpha版 Alpha版一般只在开发的公司内部运行，不对外公开。主要死开发者自己对产品进行测试，检查产品是否存在缺陷、错误，验证产品功能与说明书、用户手册是否一致。MySQL是属于开放源代码的开源产品，因此需要世界各地开发者、爱好者和用户参与软件的开发测试和手册编写等工作。所以会对外公布此版本的源码和产品，方便任何人可以参与开发测试工作，甚至编写与修改用户手册。
Beta版 Beta版一般是完成功能的开发和所有的测试工作时候的产品，不会存在较大的功能或性能BUG，并且邀请或提供给公户体验与测试，以便更全面地测试软件的不足之处或存在的问题。
RC版 RC版属于生产环境发布之前的一个小版本或称候选版，是根据Beta测试结果，收集到的BUG或缺陷之处等收集到信息，进行修复和完善之后的新一版本
GA版 GA版是软件产品正式发布的版本，也称生产版本的产品。一般情况下，企业生产环境都会选择GA版本的MySQL软件，用于真实的生产环境中。偶尔有个别的大型企业会追求新功能驱动而牺牲稳定性使用其他版本，但这个是个例。
MySQL四中发布版本选择说明 MySQL AB官方网站会把五种数据库版本都提供下载，主要是MySQL数据库属于开发源代码的数据库产品，鼓励全球的技术爱好者参与研发、测试、文档编写和经验分享，甚至包过产品发展规划，对于Development版本、Alpha版本和Beta版本是绝对不允许使用在任何生产环境，毕竟这是一个GA版本之前，也即生产版本发布之前的一个小版本。另外，对MySQL数据库GA版本，也是需要慎重选择，开源社区产品毕竟不是经过严格的测试工序完成的产品，是全球开源技术人员的资源完成的，会存在比商业产品稳定性弱的缺陷。更严格的选择见后文。
MySQL产品路线 MySQL产品路线变更历史背景 早起MySQL也是遵循版本号逐渐增加的方式发展的，格式例如：mysql-x.xx.xx.tar.gz，例如DBA都非常熟悉的生产场景版本：4.1.7、5.0.56等。
近几年，为了提高MySQL产品的竞争优势、以及提高性能、降低开发维护成本等原因，同时，更方便企业用户更精准的选择适合的版本产品用于自己的企业生产环境中。 MySQL在发展到5.1系列版本之后，重新规划为3条产品线
5.0.xx到5.1.xx产品线介绍 第一条产品线：5.0.xx及升级到5.1.xx的产品系列，这条产品线继续完善与改进其用户体验和性能，同时增加新功能，这条路线可以说是MySQL早起产品的延续系列，这一系列的产品发布情况及历史版本如下： MySQL 5.1是当前稳定（产品质量）发布系列。只针对漏洞修复重新发布；没有增加会影响稳定性的新功能。
MySQL 5.1:Previous stable(production-quality) release MySQL 5.0是前一稳定（产品质量）发布系列。只针对严重漏洞修复和安全修复重新发布；没有增加会影响该系列的重要功能。 MySQL 5.0:Old stable release nearing the end of the product lifecycle MySQL 4.0和3.23是旧的稳定(产品质量)发布系列。该版本不再使用，新的发布只用来修复特别严重的漏洞(以前的安全问题)。 5.4.xx开始到5.7.xx产品线系列介绍 为了更好的整合MySQL AB公司社区和第三方公司开发的新存储引擎，以及吸收新的实现算法等，从而更好的支持SMP架构，提高性能而做了大量的代码重构。版本号为从5.4.xx开始，目前发展到了5.6.x 主流：互联网公司用mysql5.5，逐步过渡到5.6。
6.0.xx-7.1.xx产品线系列介绍 第三条产品线：为了更好的推广MySQL Cluster版本，以及提高MySQL Cluster的性能和稳定性，以及功能改进和增加，以及改动mysql基础功能，使其对Cluster存储引擎提供更有效地支持与优化。版本号为6.0.xx开发，目前发展到7.1.xx
MySQL数据库软件命名介绍 MySQL数据库软件的名字是由3个数字和一个后缀组成的版本号。例如，像 mysql-5.0.56.tar.gz 的版本号这样解释：
第一个数字（5）为主版本号，描述了文件格式。所有版本5发行都有相同文件格式。 第二个数字（0）为发行级别，主版本号和发行级别组合到一起便构成了发行序列号。 第三个数字（56 为在此发行系列的版本号，随每个新分发版本递增。通常你需要已经选择的发行(release)的最新版本。 每次更新后，版本字符串的最后一个数字递增。如果相对于前一个版本增加了新功能或有微小的不兼容性，字符串的第二个数字递增。如果文件格式改变，第一个数字递增。 后缀显示发现的稳定性级别。通过一系列后缀显示如何改进稳定性。可能的后缀有：
alpha 表明发行包含大量未被彻底测试的新代码。已知的缺陷应该在新闻小节被记录。请参见附录D：MySQL变更史。在大多数alpha版本中也有新的命令和扩展。alpha版本也可能有主要代码更改等开发。但我们在发布前一定对其进行测试。
beta 意味着该版本功能是完整的，并且所有的新代码被测试了，没有增加重要的新特征，应该没有已知的缺陷。当alpha版本至少一个月没有出现报导的致命漏洞，并且没有计划增加导致已经实施的功能不稳定的新功能时，版本则从alpha版变为beta版。在以后的beta版、发布版或产品发布中，所有API、外部可视结构和SQL命令列均不再更改。
rc 是发布代表；是一个发行了一段时间的beta版本，看起来应该运行正常。只增加了很小的修复。(发布代表即以前所称的gamma 版) 如果没有后缀，这意味着该版本已经在很多地方运行一段时间了，而且没有非平台特定的缺陷报告。只增加了关键漏洞修复修复。这就是我们称为一个产品（稳定）或“通用”版本的东西。</description>
    </item>
    <item>
      <title>同步工具rsync使用指南</title>
      <link>https://www.oomkill.com/rsync/</link>
      <pubDate>Sun, 07 May 2017 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/rsync/</guid>
      <description>Overview 官方网站：https://www.samba.org/ftp/rsync/rsync.html
rsync特性
rsync类似于scp的功能
rsync还可以在本地的不同分区和目录之间进行全量及增量的复制数据，类似cp又优于cp
rsync可以实现文件的删除
一个rsync相当于 scp cp rm，但是还优于他们每一个
支持拷贝特殊文件如链接文件，设备等 可以有排除指定文件或目录的权限、时间、软硬链接、属主、组所有属性均不改变-p 可以有排除指定文件或目录的功能，相当于打包命令tar的排除功能 可以实现增量同步，即只同步发生变化的数据，因此数据传输效率很高tar。 可以使用rcp rsh ssh等方式来配合传输文件（rsync本身不对数据加密） 可以通过socket（进程方式）传输文件和数据 支持匿名的或认证（无须系统用户）的进程模式传输，可实现方便安全的进行数据备份及镜像 安装rsync linux上安装rsync Platform Command Debian/Ubuntu &amp;amp; Mint sudo apt-get install rsync Arch Linux pacman -S rsync Gentoo emerge sys-apps/rsync Fedora/CentOS/RHEL and Rocky Linux/AlmaLinux sudo yum install rsync openSUSE sudo zypper install rsync windows安装rsync 官网下载cwRsync的服务端和客户端软件，cwRsync官网为：www.itefix.net/cwrsync
Notes：由于伟大的 people‘s leader president xi 网站已经无法中国地区访问（点击测试），伟大的俄罗斯因为俄乌战争，也不对俄罗斯访问了（俄乌战争开始后，西方大量学术网站禁止了俄罗斯地区的访问）
所以目前只能下载到一些镜像站上4.x版本，截止到2022年11月的6.2.7相差很多，windows客户端版本可以通过chocolate 安装
rsync使用说明 rsync命令语法
选项 注释说明 rsync rsync同步命令 option 为同步时的选项参数 src 为源，及待拷贝的分区、文件或目录等 dest 为目标分区、文件或目录等 rsync参数说明</description>
    </item>
    <item>
      <title>firewalld</title>
      <link>https://www.oomkill.com/firewalld/</link>
      <pubDate>Thu, 02 Mar 2017 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/firewalld/</guid>
      <description>1 firewalld的配置文件 以xml格式为主
bash 1 2 /etc/firewalld/ /usr/lib/firewalld/ 使用时的规则是这样的：当需要一个文件时firewalld会首先到第一个目录中查找，如果找到直接使用，否则会继续到第二个目录中查找。
1.1 配置文件结构 firewalld的配置文件主要有两个文件和三个目录
文件：firewalld.conf、lockdown-whitelist.xml
目录：zone services icmptypes
1.2 firewalld.conf firewalld的主配置文件，不过非常简单，只有五个配置项
defaultzone：默认使用的zone默认public
minimalmark：标记最小值
cleanUpOnExit：退出当前firewalld后是否清除防火墙规则，默认值为yes;
zones
保存zone配置文件
services
保存service配置文件
icmptypes
保存和icmp类型相关的配置文件
2 firewall操作 2.1 查看firewalld状态 bash 1 2 3 4 5 6 7 $ firewall-cmd --state not running $ systemctl start firewalld $ firewall-cmd --state running 2.2 不改变状态的条件下重新加载防火墙 bash 1 firewall-cmd --reload 获取支持的区域列表
bash 1 firewall-cmd --get-zone 获得所有支持的服务
bash 1 2 $ firewall-cmd --get-services RH-Satellite-6 amanda-client bacula bacula-client dhcp dhcpv6 dhcpv6-client dns ftp high-availability http https imaps ipp ipp-client ipsec kerberos kpasswd ldap ldaps libvirt libvirt-tls mdns mountd ms-wbt mysql nfs ntp openvpn pmcd pmproxypmwebapi pmwebapis pop3s postgresql proxy-dhcp radius redis rpc-bind samba samba-client smtp ssh telnet tftp tftp-clienttransmission-client vnc-server wbem-https 获取所有支持的ICMP类型</description>
    </item>
    <item>
      <title>Keepalived 高可用集群应用实践</title>
      <link>https://www.oomkill.com/keepalived/</link>
      <pubDate>Wed, 15 Feb 2017 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/keepalived/</guid>
      <description>Keepalived介绍 Keepalived软件起初是专为LVS负载均衡软件设计的，用来管理并监控LVS集群系统中各个服务节点的状态，后来又加入了可以实现高可用的VRRP功能。因此，Keepalived除了能够管理LVS软件外，还可以作为其他服务（例如：Nginx、Haproxy、MySQL等）的高可用解决方案软件。
Keepalived软件主要是通过VRRP协议实现高可用功能的。VRRP是Virtual Router Redundancy Protocol（虚拟路由器冗余协议）的缩写，VRRP出现的目的就是为了解决静态路由单点故障问题的，它能够保证当个别节点宕机时，整个网络可以不间断地运行。所以，Keepalived一方面具有配置管理LVS的功能，同时还具有对LVS下面节点进行健康检查的功能，另一方面也可实现系统网络服务的高可用功能。
Keepalived服务的三个重要功能 管理LVS负载均衡软件 早期的LVS软件，需要通过命令行或脚本实现管理，并且没有针对LVS节点的健康检查功能。为了解决LVS的这些使用不便的问题，Keepalived就诞生了，可以说，Keepalived软件起初是专为解决LVS的问题而诞生的。因此，Keepalived和LVS的感情很深，它们的关系如同夫妻一样，可以紧密地结合，愉快地工作。Keepalived可以通过读取自身的配置文件，实现通过更底层的接口直接管理LVS的配置以及控制服务的启动、停止等功能，这使得LVS的应用更加简单方便了。LVS和Keepalived的组合应用不是本章的内容范围。
实现对LVS集群节点健康检查功能（healthcheck） 前文已讲过，Keepalived可以通过在自身的keepalived.conf文件里配置LVS的节点IP和相关参数实现对LVS的直接管理；除此之外，当LVS集群中的某一个甚至是几个节点服务器同时发生故障无法提供服务时，Keepalived服务会自动将失效的节点服务器从LVS的正常转发队列中清除出去，并将请求调度到别的正常节点服务器上，从而保证最终用户的访问不受影响；当故障的节点服务器被修复以后，Keepalived服务又会自动地把它们加入到正常转发队列中，对客户提供服务。
作为系统网络服务的高可用功能（failover） Keepalived可以实现任意两台主机之间，例如Master和Backup主机之间的故障转移和自动切换，这个主机可以是普通的不能停机的业务服务器，也可以是LVS负载均衡、Nginx反向代理这样的服务器。
Keepalived高可用功能实现的简单原理为，两台主机同时安装好Keepalived软件并启动服务，开始正常工作时，由角色为Master的主机获得所有资源并对用户提供服务，角色为Backup的主机作为Master主机的热备；当角色为Master的主机失效或出现故障时，角色为Backup的主机将自动接管Master主机的所有工作，包括接管VIP资源及相应资源服务；而当角色为Master的主机故障修复后，又会自动接管回它原来处理的工作，角色为Backup的主机则同时释放Master主机失效时它接管的工作，此时，两台主机将恢复到最初启动时各自的原始角色及工作状态。
说明：Keepalived的高可用功能是本章的重点，后面除了讲解Keepalived高可用的功能外，还会讲解Keepalived配合Nginx反向代理负载均衡的高可用的实战案例。 Keepalived高可用故障切换转移原理 Keepalived高可用服务对之间的故障切换转移，是通过VRRP（Virtual Router Redundancy Protocol，虚拟路由器冗余协议）来实现的。
在Keepalived服务正常工作时，主Master节点会不断地向备节点发送（多播的方式）心跳消息，用以告诉备Backup节点自己还活着，当主Master节点发生故障时，就无法发送心跳消息，备节点也就因此无法继续检测到来自主Master节点的心跳了，于是调用自身的接管程序，接管主Master节点的IP资源及服务。而当主Master节点恢复时，备Backup节点又会释放主节点故障时自身接管的IP资源及服务，恢复到原来的备用角色。
什么是VRRP VRRP，全称Virtual Router Redundancy Protocol，中文名为虚拟路由冗余协议，VRRP的出现就是为了解决静态路由的单点故障问题，VRRP是通过一种竞选机制来将路由的任务交给某台VRRP路由器的。
VRRP早期是用来解决交换机、路由器等设备单点故障的，下面是交换、路由的Master和Backup切换原理描述，同样适用于Keepalived的工作原理。
在一组VRRP路由器集群中，有多台物理VRRP路由器，但是这多台物理的机器并不是同时工作的，而是由一台称为Master的机器负责路由工作，其他的机器都是Backup。Master角色并非一成不变的，VRRP会让每个VRRP路由参与竞选，最终获胜的就是Master。获胜的Master有一些特权，比如拥有虚拟路由器的IP地址等，拥有系统资源的Master负责转发发送给网关地址的包和响应ARP请求。
VRRP通过竞选机制来实现虚拟路由器的功能，所有的协议报文都是通过IP多播（Multicast）包（默认的多播地址224.0.0.18）形式发送的。虚拟路由器由VRID（范围0-255）和一组IP地址组成，对外表现为一个周知的MAC地址：00-00-5E-00-01-{VRID}。所以，在一个虚拟路由器中，不管谁是Master，对外都是相同的MAC和IP（称之为VIP）。客户端主机并不需要因Master的改变而修改自己的路由配置。对它们来说，这种切换是透明的。
在一组虚拟路由器中，只有作为Master的VRRP路由器会一直发送VRRP广播包（VRRP Advertisement messages），此时Backup不会抢占Master。当Master不可用时，Backup就收不到来自Master的广播包了，此时多台Backup中优先级最高的路由器会抢占为Master。这种抢占是非常快速的（可能只有1秒甚至更少），以保证服务的连续性。出于安全性考虑，VRRP数据包使用了加密协议进行了加密。
如果你在面试时，要你解答Keepalived的工作原理，建议用自己的话回答如下内容，以下为对面试官的表述：
Keepalived高可用对之间是通过VRRP通信的：
VRRP，全称Virtual Router Redundancy Protocol，中文名为虚拟路由冗余协议，VRRP的出现是为了解决静态路由的单点故障。 VRRP是通过一种竞选协议机制来将路由任务交给某台VRRP路由器的。 VRRP用IP多播的方式（默认多播地址（224.0.0.18））实现高可用对之间通信。 工作时主节点发包，备节点接包，当备节点接收不到主节点发的数据包的时候，就启动接管程序接管主节点的资源。备节点可以有多个，通过优先级竞选，但一般Keepalived系统运维工作中都是一对。 VRRP使用了加密协议加密数据，但Keepalived官方目前还是推荐用明文的方式配置认证类型和密码。 Keepalived服务的工作原理 介绍完了VRRP，接下来我再介绍一下Keepalived服务的工作原理：
Keepalived高可用对之间是通过VRRP进行通信的，VRRP是通过竞选机制来确定主备的，主的优先级高于备，因此，工作时主会优先获得所有的资源，备节点处于等待状态，当主挂了的时候，备节点就会接管主节点的资源，然后顶替主节点对外提供服务。 在Keepalived服务对之间，只有作为主的服务器会一直发送VRRP广播包，告诉备它还活着，此时备不会抢占主，当主不可用时，即备监听不到主发送的广播包时，就会启动相关服务接管资源，保证业务的连续性。接管速度最快可以小于1秒。
Keepalived高可用服务搭建 安装Keepalived 通过官方地址获取Keepalived源码软件包编译安装
sh 1 2 3 4 ./configure \ --prefix=/app/keepalived-\ --mandir=/usr/local/share/man make &amp;amp;&amp;amp; make install 复制命令到/usr/sbin下
sh 1 ln -s /app/keepalived-1.3.5/sbin/keepalived /usr/sbin/ keepalived默认会读取/etc/keepalived/keepalived.conf配置文件</description>
    </item>
    <item>
      <title>LVS &amp; keepalived 集群架构</title>
      <link>https://www.oomkill.com/lvs-and-keepalived/</link>
      <pubDate>Sat, 07 Jan 2017 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/lvs-and-keepalived/</guid>
      <description>LVS概述 负载均衡(Load Balance)集群提供了一种廉价、有效、透明的方法，来扩展网络设备和服务器的负载、带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。
搭建负载均衡服务的需求
把单台计算机无法承受的大规模的并发访问或数据流量分担到多台节点设备上分别处理，减少用户等待响应的时间，提升用户体验. 单个重负载的运算分担到多台节点设备上做并发处理，每个节点设备处理结束后，将结果汇总，返回给用户，系统处理能力得到大幅度提高。 7*24小时服务保证，任意一个或多个有限后面节点设备宕机，要求不能影响业务。 在负载均衡集群中，所有计算机节点都应该提供相同的服务。集群负载均衡器所截获所有对该服务的入站请求。然后将这些请求尽可能的平均分配在所有集群节点上。
LVS (Linux Virtual Server)介绍 LVS是Linux Virtual Server的简写，意即Linux虚拟服务器，是一个虚拟的服务器集群系统，可在UNIX、Linux平台下实现负载均衡集群功能。该项目在1998年5月由章文嵩博士组织成立，是中国国内最早出现的自由软件项目之一
LVS项目介绍 http://www.linuxvirtualserver.org/zh/lvs1.html
LVS集群的体系结构 http://www.linuxvirtualserver.org/zh/lvs2.html
LVS集群中的IP负载均衡技术 http://www.linuxvirtualserver.org/zh/lvs3.html
LVS集群的负载调度 http://www.linuxvirtualserver.org/zh/lvs4.html
IPVS（LVS）发展史 早在2.2内核时，IPVS就已经以内核补丁的形式出现。
从2.4.23版本开始，IPVS软件就是合并到Linux内核的常用版本的内核补丁的集合。
从2.4.24以后IPVS已经成为Linux官方标准内核的一部分。
IPVS软件工作层次图 从上图可以看出，LVS负载均衡调度技术是在Linux内核中实现的，因此，被称之为Linux虚拟服务器（Linux virtual Server）。我们使用该软件配置LVS时候，不能直接配置内核中的ipvs，而需要使用ipvs的管理工具ipsadm进行管理.
LVS技术点小结：
真正实现调度的工具是IPVS， 工作在Linux内核层面 LVS自导IPVS管理工具是ipvsadm keepalived实现管理IPVS及负载均衡器的高可用。 RedHat工具Piranha WEB管理实现调度的工具IPVS。 LVS体系结构与工作原理简单描述 LVS集群负载均衡器接受服务的所有入站客户端计算机请求，并根据调度算法决定那个集群几点应该处理回复请求。负载均衡器简称(LB)有时也被成为LVS Director简称Director
LVS虚拟服务器的体系结构如下图所示，一组服务器通过告诉的局域网或者地理分布的广域网互相连接，在他们的前端有一个负载调度器（Load Balancer）。负载调度器能无缝地将网络请求调度到真实服务器上，从而使得服务器集群的结构对客户是透明的，客户访问集群系统提供的网络服务就像访问一台高性能、高可用的服务器一样。客户程序不收服务器集群的影响不需作任何修改。胸的伸缩性通过在服务集群中透明的加入和删除一各节点来达到，通过检测节点或服务进程故障和正确地重置系统达到高可用性。由于我们的负载调度技术是在Linux内核中实现的，我们称之为Linux虚拟服务器（Linux Virtual Server）。
LVS基本工作过程图 **LVS基本工作过程图1：带颜色的小方块代表不同的客户端请求
LVS基本工作过程图2：
不同的客户端请求小方块经过负载均衡器，通过指定的分配策略被分发到后面的机器上
LVS基本工作过程图3：
LVS基本工作过程图4：
LVS相关术语命名约定 名称 缩写 说明 虚拟IP地址(Virtual IP Address) VIP VIP为Direcort用于向客户端计算机提供IP地址.如www.baidu.com域名就要解析到VIP上提供服务 真实IP地址(Real Server IP Address) RIP 在集群下面节点上使用的IP地址，物理IP地址 Director的IP地址(Director IP Address) DIP Director用于连接内外网络的IP地址，物理网卡上的IP地址，是负载均衡器上的IP 客户端主机IP地址(Client IP Address) CIP 客户端用户计算机请求集群服务器的IP地址，该地址用作发送给集群的请求的源IP地址 LVS集群内部的节点称为真实服务器(Real Server)，也叫做集群节点。请求集群服务的计算机称为客户端计算机。</description>
    </item>
    <item>
      <title>使用fpm制作rpm包与搭建本地yum源</title>
      <link>https://www.oomkill.com/fpm/</link>
      <pubDate>Fri, 16 Dec 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/fpm/</guid>
      <description>rpm 与 fpm 软件的安装方式 编译安装：优点是可以定制化安装目录、按需开启功能等，缺点是需要查找并实验出适合的编译参数，诸如MySQL之类的软件编译耗时过长 yum安装：优点是全自动化安装，不需要为依赖问题发愁，缺点是自主性太差，软件的功能、存放位置都已经固定好了，不易变更。 编译源码：根据自己的需求做成 RMP包 ==&amp;gt; 搭建yum仓库 ==&amp;gt; yum安装。结合前两者的优点，暂未发现什么缺点。可能的缺点就是RPM包的通用性差，一般人不会定制RPM包。 RPM概述 RPM全称是Red Hat Package Manager(RedHat包管理器)。几乎所有的Linux发型版本都使用这种形式的软件包管理安装、更新和卸载软件。
rpm命令有5种基本功能（不包括创建软件包）：安装、卸载、升级、查询和验证。
关于rpm命令的使用可以用rpm &amp;ndash;help来获得
rpmbuild rpmbuild是reahat系的原声打包命令，这个命令的使用难点主要在于spec文件编写，一个类似于kickstart的ks.cfg文件。
作为一个使用工具，种种繁琐，在没有替代品时还能存活。当有了其他简易工具时，他就到了完蛋的时候
fpm fpm 是将一种类型的包转换成另一种类型
支持的源类型包
类型 说明 dir 将目录打包成所需要的类型，可以用于源码编译安装的软件包 rpm 对rpm进行转换 gem 对rubygem包进行转换 python 将python模块打包成相对应的类型 支持目标类型包 rpm 转换为rpm包 deb 转换为deb包 solaris 装环卫solaris包 puppet 转换为puppet模块 fpm安装 fpm是ruby写的，因此系统环境需要ruby，而且ruby版本号大于bshards运行的版本。
yum安装ruby模块 bash 1 yum install ruby rubygems ruby-devel -y 查看ruby的版本
bash 1 2 3 4 5 6 7 $ rpm -qa|grep ruby ruby-libs-1.</description>
    </item>
    <item>
      <title>heartbeat权威指南</title>
      <link>https://www.oomkill.com/heartbeat/</link>
      <pubDate>Fri, 25 Nov 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/heartbeat/</guid>
      <description>heartbeat介绍 Heartbeat一款开源提供高可用(Highly-Available)服务的软件，通过heartbeat，可以将资源（IP及程序服务等资源）从一台已经故障的计算机快速转移到另一台正常运转的机器上继续提供服务，一般称之为高可用服务。在实际生产应用场景中，heartbeat的功能和另一个高可用开源软件keepalived有很多相同之处，但在生产中，对应实际的业务应用也是有区别的，例如:keepalived主要是控制IP的漂移，配置、应用简单，而heartbeat则不但可以控制IP漂移，更搜长对资源服务的控制，配置、应用比较复杂
heartbeat工作原理 通过修改heartbeat软件的配置文件，可以指定哪一台Heartbeat服务器作为主服务器，则另一台将自动成为热备服务器.然后在热备服务器上配里Heartbeat守护程序来监听来自主服务器的心跳消息。如果热备服务器在指定时间内未监听到来自主服务器的心跳，就会启动故障转移程序，并取得主服务器上的相关资源服务的所有权，接替主服务器继续不间断的提供服务，从而达到资源及服务高可用性的目的。
以上描述的是heartbeat主备的模式，heartbeat还支持主主棋式，即两台服务器互为主备，这时它们之间会相互发送报文来告诉对方自己当前的状态，如果在指定的时间内未受到对方发送的心跳报文，那么，一方就会认为对方失效或者宕机了，这时每个运行正常的主机就会启动自身的资源接管模块来接管运行在对方主机上的资源或者服务，继续为用户提供服务。一般情况下，可以较好的实现一台主机故障后，企业业务仍能够不间断的持续运行。
注意：所谓的业务不间断，再故障转移期间也是需要切换时间的(例如:停止数据库及存储服务等)，heartbeat的主备高可用的切换时间一般是在5-20秒左右(服务器宕机的切换比人工切换要快)。
另外，和keepalived高可用软件一样，heartbeat高可用是操作系统级别的，不是服务(软件)级别的，可以通过简单的脚本控制.实现软件级别的高可用。
高可用服务器切换的常见条件场景：
主服务器物理宕机(硬件损坏，操作系统故障)。 Heartbeat服务软件本身故障。 两台主备服务器之间心跳连接故障。 服务故障不会导致切换.可以通过服务宕机把heartbeat服务停掉。
3 heartbeat心跳连接 经过前面的叙述，要部署heartbeat服务，至少需要两台主机来完成。那么，要实现高可用服务，这两台主机之间是如何做到互相通信和互相监侧的呢？
下面是两台heartbeat主机之间通信的一些常用的可行方法：
利用串行电缆，即所谓的串口线连接两台服务器(可选)。 一根以太网电缆两网卡直连(可选)。 以太网电缆，通过交换机等网络设备连接(次选)。 如何为高可用服务器端选择心跳通信方案？ 串口线信号不会和以太网网络交集，也不需要单独配置丐地址等信息，因此传输稳定不容易出现问题，使用串口线的缺点是两个服务器对之间的距离距离不能太远，串口线对应服务端的设备为/dev/ttys0。串口线形状如下图所示：
使用以太网网线(无需特殊交叉线了)直连网卡的方式，配置也比较简单，只需对这两块直连网线的网卡配好独立的IP段地址能够互相通信即可，普通的网线就可以了（推荐）
使用联网以太网网线和网卡作为心跳线是次选的方案，因为这个链路里增加了交换机设备这样的故障点，且这个线路不是专用心跳线路，容易受以太网其他数据传输的影响，导致心跳报文发送延迟或者无法送达问题。
选择方案小结：
和数据相关的业务，要求较高，可以串口和网线直连的方式并用。 Web业务，可以网线直连的方式或局域网通信方式也可。 Heartbeat软件未来发展说明 有关heartbeat分3个分支的说明
自2.1.4版本后，Linux-HA将Heartbeat分包成三个不同的子项目，并且提供了一个cluster-glue的组件，专用于Local ResourceManager 的管理。即heartbeat + cluster-glue + resouce-agent 三部分。
Heartbeat hearbeat本身是整个集群的基础（cluster messaging layer），负责维护集群各节点的信息以及它们之前通信。
Cluster Glue 相当于一个中间层，负责调度，可以将heartbeat和crm（pacemaker）联系起来，包括两个摸块:本地资漂管理(Local Resource Manager)LRM和STONITH。
Resource Agents 资源代理层，各种的资源的ocf脚本，这些脚本将被LRM调用从而实现各种资源启动、停止、监控等等。
Pacfrmaker资料
pacemaker介绍：http://baike.baidu.com/view/8635511.htm
从头开始搭建其群在Fedora上面创建主/主和主/备集群 http://www.clusterlabs.org/doc/zh-CN/Pacemaker/1.1/html-single/Clusters_from_Scratch/index.html
参考文档：http://www.2cto.com/os/201511/448872.html
裂脑 什么是裂脑 由于某些原因，导致两台高可用服务器对之间在指定时间内，无法互相检侧到对方心跳而各自启动故障转移功能，取得了资源及服务的所有权，而此时的两台高可用服务器对都还活着并在正常运行，这样就会导致同一个IP或服务在两端同时启动而发生冲突的严重问题，最严重的是两台主机占用同一个VIP地址，当用户写入数据时可能会分别写入到两端，这样可能会导致服务器两端的数据不一致或造成数据丢失，这种情况就被称为裂脑，也有人称其为分区集群或大脑垂直分割，英文为split brain。
导致裂脑发生的多种原因 一般来说，裂脑的发生，有以下几个原因。 高可用服务器对之间心跳线链路故障。导致无法正常通信。
心跳线坏了(包括断了，老化)。 网卡及相关驱动坏了，IP配置及冲突问题(网卡直连)。 心跳线间连接的设备故障(网卡及交换机)。 仲裁的机器出问题(仲裁的方案)。 高可用服务器对上开启了如iptables防火墙阻挡了心跳的传输。 高可用服务器对上心跳网卡地址等信息配置不正确，导致发送心跳失败。 其它服务配置不当等原因，如心跳方式不同，心跳广播冲突、软件BUG等。 提示:另外的高可用软件keepalived配置里如果virtual router_id参数，两端配置不一致，也会导致裂脑问题发生。
防止裂脑发生的8种秘籍 发生裂脑时，对业务的影响是极其严重的，有时甚至是致命的。如:两台高可用服务器对之间发生裂脑，导致互相争用同一IP资源，就如同我们在局域网内常见的IP地址冲突一样，两个机器就会有一个或者两个都不正常，影响用户正常访问服务器。如果是应用在数据库或者存储服务这种极重要的高可用上，那就可能会导致用户发布的数据间断的写在两台不同服务器上，最终数据恢复极困难或难以恢复(当然，有NAS等公共存储的硬件也许会好一些）。</description>
    </item>
    <item>
      <title>redis安全相关配置</title>
      <link>https://www.oomkill.com/redis-security/</link>
      <pubDate>Wed, 23 Nov 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/redis-security/</guid>
      <description>为Redis客户端外部设置连接密码 因为redis速度相当快，所以在一台比较好的服务器下，一个外部的用户可在一秒钟进行上万次的密码尝试，这意味着你需要指定非常非常强大的密码来防止暴力破解。
修改配置文件 bash 1 requirepass 123@1 重启服务后登录客户端提示没有验证
bash 1 2 3 $ redis-cli 127.0.0.1:6379&amp;gt; keys * (error) NOAUTH Authentication required. 验证成功后，可以正常操作
bash 1 2 3 4 5 127.0.0.1:6379&amp;gt; auth 123@1 OK 127.0.0.1:6379&amp;gt; keys * 1) &amp;#34;test-durable-1&amp;#34; 2) &amp;#34;test-durable&amp;#34; 命令行临时生效 在命令行设置后，redis在下次重启前，每次登录都需要验证密码
bash 1 2 3 4 5 6 127.0.0.1:6379&amp;gt; CONFIG set requirepass 123@1 OK 127.0.0.1:6379&amp;gt; quit $ redis-cli 127.0.0.1:6379&amp;gt; keys * (error) NOAUTH Authentication required. 注意：配置Redis复制的时候如果主数据库设置了密码，需要在从数据库的配置文件中通过masterauth参数设置主数据库的密码，以使从数据库连接主数据库时自动使用AUTH命令认证。
通过mysql命令行指定密码方式登录Redis客户端
bash 1 2 3 4 $ redis-cli -a 123@1 127.</description>
    </item>
    <item>
      <title>Redis安装</title>
      <link>https://www.oomkill.com/redis-install/</link>
      <pubDate>Wed, 23 Nov 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/redis-install/</guid>
      <description>Remote Dictonary Server(Redis)是一个基于key-value键值对的持久化数据库存储系统。redis和大名鼎鼎的Memcached缓存服务很像,但是redis支持的数据存储类型更丰富,包括string(字符串)、list(链表)、set(集合)和zset(有序集合)、Hash等。
这些数据类型都支持push/pop,add/remove及取交集、并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上，redis支持各种不同方式的排序。与memcached缓存服务一样，为了保证效率数据都是缓存在内存中提供服务。和memcached不同的是，redis持久化缓存服务还会周期性的把更新的数据写入到磁盘以及把修改的操作记录追加到文件里记录下来，比memcached更有优势的是，redis还支持master-slave(主从)同步,这点很类似关系型数据库MySQL。
Redis是一个开源的、使用C语言编写、３万多行代码、支持网络、可基于内存亦可久化的日志型、Key-Value数据库，并提供多种语言的API从2010年3月15日起，Redis开发工作由VMware主持。
Redis的出现，再一定程度上弥补了memcached这类key-value内存缓存服务的不足,在部分场合可以对关系数据库起到很好的补充作用.redis提供了Python, Ruby, Erlang, PHP客户端，使用很方便。redis官方文档如下：http://www.redis.io/documentation
Redis的优点 与memcached不用，redis可以持久化存储数据。 性能很高：Redis能支持超过10w/秒的读写频率。 丰富的数据类型：redis支持二进制的Strings, Lists, Hashes, Sets及sorted sets等数据类型操作。 原子：Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。 丰富的特性：Redis还支持publish/subscribe(发布/订阅)，通知，key过期等等特性。 redis支持异步主从复制。 Redis的应用场景 传统的MySQL+Memcached的网站架构遇到的问题：
MySQL数据库实际上是适合进行海量数据存储的,加上通过Memcached将热点数据 存放到到内存cache里,达到加速数据访问的目的,绝大部分公司都曾经使用过这样的架构,但随着业务数据量的不断增加,和访问量的增长,很多问题就会暴漏出来：
需要不断的对MySQL进行拆库拆表Memcached也需不断跟着扩容,扩容和维护工作占据大量开发运维时间。 Memcached与MySQL数据库数据一致性问题是个老大难。 Memcached数据命中率低或down机,会导致大量访问直接穿透到数据库,导致MySQL无法支撑访问。 跨机房cache同步一致性问题。 redis在微博中的应用 计数器：微博（评论、转发、阅读、赞等） 用户（粉丝、关注、收藏、双向关注等） redis在短信中的应用 发送短信后存入redis中60秒过期。
redis的最佳应用场景 Redis最佳试用场景是全部数据in-memory。 Redis更多场景是作为Memcached的替代品来使用。 当需要除key/value之外的更多数据类型支持时,使用Redis更合适。 数据比较重要，对数据一致性有一定要求的业务。 当存储的数据不能被剔除时,使用Redis更合适。 更多 Redis作者谈Redis应用场景 http://blog.nosglfan.com/html/2235.html 使用redis bitmap进行活跃用户统计 http://blog.nosqlfun.com/html/3501.html 计数、cache服务、展示最近、最热、点击率最高、活跃度最高等等条件的top list、用户最近访问记录表、relation list/Message Queue、粉丝列表
Key-Value Store更加注重对海量数据存取的性能、分布式、扩展性支持上，并不需要传统关系数据库的一些特征。例如：Schema事务、完整SQL查询支持等等，因此在布式环境下的性能相对于传统的关系数据库有较大的提升。
redis的生产经验教训 要进行Master-slave主从同步配置，在出现服务故障时可以切换。 在master禁用数据据持久化只需在slave上配置数据持久化。 物理内存+虚拟内存不足，这个时候dump一直死着，时间久了机器挂掉。这个情就是灾难。 当Redis物理内存使用超过内存总容量的3/5时就会开始比较危险了，就开始做swap，内存碎片大！ 当达到最大内存时，会清空带有过期时间的如 redis与DB同步写的问题，先写DB，后写redis，因为写内存基本上没有问题。 业务场景 提高了DB的可扩展性,只需要将新加的数据放到新加的服务器上就可以了。 提高了DB的可用性,只影响到需要访问的shard服务器上的数据的用户。 提高了DB的可维护性,对系统的升级和配里可以按shard一个个来搞,对服务产生的影响小。 小的数据库存的查询压力小,查询更快,性能更好。 使用过程中的一些经验与教训,做个小结：
要进行Master-slave配置,出现服务故障时可以支持切换。 在master侧禁用数据持久化,只需在slave上配置数据持久化。 物理内存+虚拟内存不足时,这个时候dump已知死着,时间久了机器挂掉。这个情况就是灾难。 当Redis物理内存使用超过内存总容量的3/5时就会开始比较危险了,就开始做swap,内存碎片大。 当达到最大内存时,会清空带有过期时间的key,即使key未到过期时间。 redis与DB同步写的问题,先写DB,后写redis,因为写内存基本上没有问题。 安装配置Redis 下载安装Redis redis官方网站：www.</description>
    </item>
    <item>
      <title>redis事务与发布订阅</title>
      <link>https://www.oomkill.com/redis-subscribe-and-transaction/</link>
      <pubDate>Wed, 23 Nov 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/redis-subscribe-and-transaction/</guid>
      <description>发布与订阅 Publish/Subscribe 发布订阅(pub/sub)是一种消息通信模式，主要的目的是解耦消息发布者和消息订阅者之间的藕合，这点和设计模式中的观察者模式比较相似。pub/sub不仅仅解决发布者和订阅者直接代码级别耦合也解决两者在物理部署上的耦合。Redis作为一个pub/sub的server,在订阅者和发布者之间起到了消息路由的功能。订阅者可以通过subscribe和psubscribe命令向Redis server订阅自己感兴趣的消息类型，Redis将消息类型称为通道(channel)。当发布者通过publish命令向Redis server发送特定类型的消息时。订阅该消息类型的全部client
都会收到此消息。这里消息的传递是多对多的。一个client可以订阅多个channel,也可以向多个channel发送消息。
Redis支持这样一种特性，你可以将数据推到某个信息管道中，然后其它人可以通过订阅这些管道来获取推送过来的信息。
用一个客户端订阅频道 bash 1 2 3 4 5 6 psubscribe new #### 1.批量订阅 127.0.0.1:6379&amp;gt; publish news news-test (integer) 1 127.0.0.1:6379&amp;gt; publish video video-test (integer) 1 此时可以见到接受的信息
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 127.0.0.1:6379&amp;gt; psubscribe news video Reading messages... (press Ctrl-C to quit) 1) &amp;#34;psubscribe&amp;#34; 2) &amp;#34;news&amp;#34; 3) (integer) 1 1) &amp;#34;psubscribe&amp;#34; 2) &amp;#34;video&amp;#34; 3) (integer) 2 1) &amp;#34;pmessage&amp;#34; 2) &amp;#34;news&amp;#34; 3) &amp;#34;news&amp;#34; 4) &amp;#34;news-test&amp;#34; 1) &amp;#34;pmessage&amp;#34; 2) &amp;#34;video&amp;#34; 3) &amp;#34;video&amp;#34; 4) &amp;#34;video-test&amp;#34; 数据过期设置及机制 Redis key的过期机制 Redis对过期键采用了lazy expiration：在访间key的时候判定key是否过期，如果过期，则进行过期处理（过期的key没有被访间可能不会被删除）。其次，每秒对volatile keys进行抽样测试，如果有过期键，那么对所有过期key进行处理。</description>
    </item>
    <item>
      <title>redis数据持久化</title>
      <link>https://www.oomkill.com/redis-persist/</link>
      <pubDate>Wed, 23 Nov 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/redis-persist/</guid>
      <description>Redis的所有数据都存储在内存中，但是他也提供对这些数据的持久化。
Redis是一个支持持久化的内存数据库，Redis需要经常将内存中的数据同步到磁盘来保证持久化。Redis支持四种持久化方式，一种是 Snapshotting(快照)也是默认方式 ，另一种是 Append-only file(aof)的方式 。
RDB持久化方式 Snapshotting方式是将内存中数据以快照的方式写入到二进制文件中，默认的文件名为dump.rdb。可以通过配置设置自动做快照持久化。例如可以配置redis在n秒内如果超过m个key被修改就自动做快照。
实现机制 Redis调用fork子进程。
父进程继续处理client请求，子进程负责将内存内容写入到临时文件。由于os的实时复制机制(copy on write)父子进程会共享相同的物理页面，当父进程处理写请求时os会为父进程要修改的页面创建副本，而不是写共享的页面。所以子进程地址空间内的数据是fork时刻整个数据库的一个快照。
当子进程将快照写入临时文件完毕后，用临时文件替换原来的快照文件，然后子进程退出。client也可以使用save或者bgsave命令通知redis做一次快照持久化。save操作是在主线程中保存快照的，由于redis是用一个主线程来处理所有client的请求，这种方式会阻塞所有clien:请求。所以不推荐使用。另一点需要注意的是，每次快照持久化都是完整写入到磁盘一次并不是增量的只同步变更数据。如果数据量大的话，而且写操作比较多，必然会引起大量的磁盘IO操作，可能会严重影响性能。
缺点：
快照方式是在一定间隔时间做一次的，所以如果redis意外down掉的话，就会丢失最后一次快照后的所有修改。如果应用要求不能丢失任何修改的话，可以采用aof持久化方式。
相关配置 bash 1 2 3 4 5 6 7 8 save 900 1 #←900秒内至少有1个key被改变 save 300 10 #←300秒内至少有10个key被改变 save 60 10000 #←60秒内至少有10000个key被改变 stop-writes-on-bgsave-error yes #←后台存储错误后停止写。如：磁盘空间不足 rdbcompression yes #←使用LZF压缩rdb文件 rdbchecksum yes #←存储和加载rdb文件时校验 dbfilename dump.rdb #←存储rdb文件名 dir /app/redis/db/ #←rdb文件路径 持久化测试 bash 1 2 3 4 5 11512:M 22 Apr 01:04:47.028 * 5 changes in 60 seconds.</description>
    </item>
    <item>
      <title>redis数据类型</title>
      <link>https://www.oomkill.com/redis-datatype/</link>
      <pubDate>Wed, 23 Nov 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/redis-datatype/</guid>
      <description>key/value介绍 Redis key值是二进制安全的，这意味着可以用任何二进制序列作为key值，从形如“0foo”的简单字符串到一个JPG文件的内容都可以。空字符串也是有效key值。
关于key的几条规则：
太长的键值，例如1024字节的键值，不仅因为消耗内存，而且在数据中查找这类键值的计算成本很高。
太短的键值，如果你要用 u:1000:pwd来代替user:1000:password，这没有什么问题，但后者更易阅读，并且由此增加的空间消耗相对于key object和value object本身来说很小.当然，没人阻止您一定要用更短的键值节省一丁点空间。
最好坚持一种模式;。例如：object-type:id:field就是个不错的注意，像这样user:1000:password。我喜欢对多单词的字段名中加上一个点，就像这样：comment.1234.renlv_to
key建议：object-type:id:field 长度10-20
value建议：string不要超过2K set sortedset元素不要超过5000
bash 1 2 3 4 $ redis-cli set user_list:user_id:5 zhangsan OK $ redis-cli get user_list:user_id:5 &amp;#34;zhangsan&amp;#34; 通用操作 找到全部给定模式的匹配到的key bash 1 2 3 4 5 6 7 127.0.0.1:6379&amp;gt; keys * #&amp;lt;==打印全部key 1) &amp;#34;name&amp;#34; 2) &amp;#34;site&amp;#34; 127.0.0.1:6379&amp;gt; keys na[ma]e #&amp;lt;==返回正则匹配到的key 1) &amp;#34;name&amp;#34; 127.0.0.1:6379&amp;gt; keys nam? 1) &amp;#34;name&amp;#34; randomkey返回随机key bash 1 2 3 4 127.0.0.1:6379&amp;gt; randomkey &amp;#34;name&amp;#34; 127.0.0.1:6379&amp;gt; randomkey &amp;#34;site&amp;#34; exists检查key是否存在 bash 1 2 3 4 127.</description>
    </item>
    <item>
      <title>redis主从复制工作原理</title>
      <link>https://www.oomkill.com/redis-replication/</link>
      <pubDate>Wed, 23 Nov 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/redis-replication/</guid>
      <description>Replication的工作原理 设置一个Slave，无论是第一次还是重连到Master，它都会发出一个sync命令。当Master收到sync命令之后，会做两件事：
Master执行BGSAVE，即在后台保存数据到磁盘（rdb快照文件）。 Master同时将新收到的写入和修改数据集的命令存入缓冲区（非查询类）。 当Master在后台把数据保存到快照文件完成之后，把这个快照传送给Slave，而Slave则把内存清空后，加载该文件到内存中。而Master也会把此前收集到缓冲区中的命令，通过Reids命令协议形式转发给Slave，Slave执行这些命令，实现和Master的同步。Master/Slave此后会不断通过异步方式进行命令的同步。
注：在redis2.8之前，主从之间一旦发生重连都会引发全量同步操作。但在2.8之后版本，也可能是部分同步操作。
部分复制 2.8后，当主从之间的连接断开之后，他们之间可以采用持续复制处理方式代替采用全量同步。Master端为复制流维护一个内存缓冲区（in-memory backlog），记录最近发送的复制流命令；同时，Master和Slave之间都维护一个复制偏移量(replication offset)和当前Master服务器ID（Master run id）。当网络断开，Slave尝试重连时：
如果MasterID相同（即仍是断网前的Master服务器），并且从断开时到当前时刻的历史命令依然在Master的内存缓冲区中存在，则Master会将缺失的这段时间的所有命令发送给Slave执行，然后复制工作就可以继续执行了
否则，依然需要全量复制操作。
Redis 2.8 的这个部分重同步特性会用到一个新增的PSYNC内部命令， 而 Redis 2.8以前的旧版本只有SYNC命令，不过，只要从服务器是Redis 2.8或以上的版本，它就会根据主服务器的版本来决定到底是使用 PSYNC还是SYNC。 如果主服务器是 Redis 2.8 或以上版本，那么从服务器使用 PSYNC 命令来进行同步。 如果主服务器是 Redis 2.8 之前的版本，那么从服务器使用 SYNC 命令来进行同步。
redis主从同步特点 一个Master可以有多个Slave。 Redis使用异步复制。从2.8开始，Slave会周期性（每秒一次）发起一个ack确认复制流（replication stream）被处理进度； 不仅主服务器可以有从服务器， 从服务器也可以有自己的从服务器， 多个从服务器之间可以构成一个图状结构； 复制在Master端是非阻塞模式的，这意味着即便是多个Slave执行首次同步时，Master依然可以提供查询服务； 复制在Slave端也是非阻塞模式的：如果你在redis.conf做了设置，Slave在执行首次同步的时候仍可以使用旧数据集提供查询；你也可以配置为当Master与Slave失去联系时，让Slave返回客户端一个错误提示； 当Slave要删掉旧的数据集，并重新加载新版数据时，Slave会阻塞连接请求（一般发生在与Master断开重连后的恢复阶段）； 复制功能可以单纯地用于数据冗余（data redundancy），也可以通过让多个从服务器处理只读命令请求来提升扩展性（scalability）： 比如说， 繁重的 SORT 命令可以交给附属节点去运行。 可以通过修改Master端的redis.config来避免在Master端执行持久化操作（Save），由Slave端来执行持久化。 redis replication配置文件详解 bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 slaveof [masterip] [masterport] #←该redis为slave ip和port是master的ip和port masterauth &amp;lt;master-password&amp;gt; #←如果master设置了安全密码，此处为master的安全密码 slave-serve-stale-data yes#←当slave丢失master或同步正在进行时，如果发生对slave的服务请求： slave-serve-stale-data no #←slave返回client错误:&amp;#34;SYNC with master in progress&amp;#34; slave-serve-stale-data yes #←slave依然正常提供服务 slave-read-only yes #←设置slave不可以写数据，只能用于同步 repl-ping-slave-period 10 #←发送ping到master的时间间隔 repl-timeout 60 #←IO超时时间 repl-backlog-size 1mb #←backlog的大小，当从库连接不到主库时，backlog的队列能放多少 repl-backlog-ttl 3600 #←backlog的生命周期 min-slaves-max-lag 10 #←延迟小于min-slaves-max-lag秒的slave才认为是健康的slave # 当master不可用,Sentinel会根据slave的优先级选举一个master。 # 最低的优先级的slave,当选master.</description>
    </item>
    <item>
      <title>ch1 iptables介绍</title>
      <link>https://www.oomkill.com/ch1-iptables-introduction/</link>
      <pubDate>Sat, 22 Oct 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch1-iptables-introduction/</guid>
      <description>1 防火墙实战 关闭两项功能：
selinux（生产中也是关闭的），ids入侵检测，MD5指纹将。系统所有核心文件全部做指纹识别，将指纹留下，将来出问题，一看就知道那个文件被改过。 iptables（生产中看情况，内网关闭，外网打开），大并发的情况，不能开iptables，影响性能。 使用防火墙就不如不使用防火墙，不使用防火墙的前提是不给外网ip，工作中要少给外网服务器ip，这样防火墙使用率较低，防火墙使用也很消耗资源 安全优化：
尽可能不给服务器配置外网IP。可以通过代理转发或者通过防火墙映射。 并发不是特别大情况再外网IP的环境，要开启iptables防火墙 http://edu.51cto.com/course/course_id-772.html
学好iptables基础：
OSI7层模型以及不同层对应那些协议？ TCP/IP三次握手，四次断开的过程，TCP HEADER。 常用的服务端口要了如指掌。 1.1 iptables防火墙简介 Netfilter/iptables(以下简称iptables)是unix/linux自带的一款优秀且开放源代码的完全自由的基于包过滤的防火墙工具，它的功能十分强大，使用非常灵活，可以对流入和流出的服务器数据包进行很精细的控制。特别是他可以在一台非常低的硬件配置下跑的非常好（赛扬500MHZ 64M内存的情况部署网关防火墙）提供400人的上网服务四号==不逊色企业级专业路由器防火墙==。iptables+zebra+squid
iptables是linux2.4及2.6内核中集成的服务。其功能与安全性比其老一辈ipwadin ipchains强大的多（长江水后浪推前浪），iptables主要工作在OSI七层的二、三、四层，如果重新编译内核，iptables也可以支持7层控制（squid代理+iptables）。
1.2 iptables名词和术语 容器：包含或者说属于关系
什么是容器？
​	在iptables里，就是用老描述这种包含或者说属于的关系
什么是Netfilter/iptables?
​	Netfilter是表（tables）的容器
什么是表（tables）？
​	表是链的容器，所有的链（chains）都属于其对应的表。
什么是链（chains）？
​	链（chains）是规则的容器
什么是规则（policy）
​	iptables一系列过滤信息的规范和具体方法条款
iptables抽象和实际比喻对比表| Netfilter | tables | chains | policy || --------- | ---------- | ------------ | -------------------- || 一栋楼 | 楼里的房子 | 房子里的柜子 | 柜子里衣服的摆放规则 |1.3 iptables工作流程 iptables是采用数据包过滤机制工作的，所以他会对请求的数据包包头数据进行分析，并根据我们预先设定的规则进行匹配来决定是否可以进入主机。</description>
    </item>
    <item>
      <title>ch2 iptables命令帮助信息</title>
      <link>https://www.oomkill.com/ch2-iptables-command/</link>
      <pubDate>Sat, 22 Oct 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch2-iptables-command/</guid>
      <description>2 iptables命令帮助信息 有问题查帮助，下面是很全的帮助信息（必须拿下它）
bash 1 $ iptables -h bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ iptables -nL # INPUT链 ACCEPT默认允许决策 Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22 REJECT all -- 0.0.0.0/0 0.</description>
    </item>
    <item>
      <title>ch3 iptables配置防火墙</title>
      <link>https://www.oomkill.com/ch3-iptables-configuration/</link>
      <pubDate>Sat, 22 Oct 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch3-iptables-configuration/</guid>
      <description>生产环境配置主机防火墙有两种模式：
逛公园及看电影两种模式：
逛公园：默认随便出进，对非法的分子进行拒绝。企业应用：企业配置上网网关路由。
看电影：默认没有票进不去。花钱买票才能看电影。企业应用：服务器主机防火墙。
很显然：第二种更严格，更安全。
逛公园及看电影两种模式本事就是防火墙的默认规则是允许还是拒绝。
1.清理当前所有规则和计数器
bash 1 2 3 iptables -F iptables -Z iptables -X 2.配置允许SSH登陆端口进入
bash 1 2 iptables -A INPUT -p tcp --dport 52113 -j ACCEPT iptables -A INPUT -p tcp -s 192.168.1.0/30 -j ACCEPT 提示：此步骤是为了防止执行下面的步骤，把自己关在外面，除非你在本地处理，这部可以不做。
3.设置允许本机lo通讯规则
bash 1 2 iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # output加不加都行，在工作环境上是加的 4.设置默认的防火墙禁止和允许规则
bash 1 2 3 iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT ACCEPT 一般情况下OUTPUT我们不要drop，像电影院一样，电影已经看完了，中间不想看就回家了，你不可能说不行不能走，所以一般出去没人管，进来才收票，OUTPUT一般不设置，但是不设置也有风险，企业流量暴涨，由于服务器中病毒外发流量。</description>
    </item>
    <item>
      <title>ch4 生产环境如何维护iptables</title>
      <link>https://www.oomkill.com/ch4-iptables-p/</link>
      <pubDate>Sat, 22 Oct 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch4-iptables-p/</guid>
      <description>生产中，一般第一次添加规则命令行或者脚本加入然后一次性保存成文件，然后可以改配置文件管理：
bash 1 2 3 4 5 6 7 8 9 $ cat /etc/sysconfig/iptables # Generated by iptables-save v1.4.7 on Wed Nov 23 09:18:12 2016 *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [115:13341] -A INPUT -p tcp -m tcp --dport 52113 -j ACCEPT COMMIT # Completed on Wed Nov 23 09:18:12 2016 生产维护：
⑴ 确定规则
sh 1 2 3 4 5 vim /etc/sysconfig/iptables # 加入想要的规则：例如： -A INPUT -p tcp -m tcp --dport 873 -j ACCEPT /etc/init.</description>
    </item>
    <item>
      <title>ch5 配置网关及服务器地址映射</title>
      <link>https://www.oomkill.com/ch5-iptables-nat/</link>
      <pubDate>Sat, 22 Oct 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch5-iptables-nat/</guid>
      <description>1 办公室路由网关架构图 对应实际企业办公上网场景逻辑图
2.实验环境配置需求前期准备 2.1 服务器网关B需要准备如下条件 物理条件是具备上网卡，建议eth0外网地址（这里是192.168.1.5,gw 192.168.1.2），ech1内网地址（这里是172.168.1.10，内网卡不配GW。 确保服务器网关B要可以上网（B上网才能代理别的机器上网）。可以通过ping baidu.com或外网IP测试。 内核文件/etc/sysctl.conf里开启转发功能。在服务器网关B192.168.1.5机器上开启路由转发功能。编辑/etc/sysctl.conf修改内容为net.ipv4.ip_forward = 1，然后执行sysctl -p使修改生效 iptables的filter表的FORWARD链允许转发 不要filter防火墙功能，共享上网，因此最好暂停防火墙测试/etc/init.d/tables stop 2.2 加载iptables内核模块 配置网关需要iptables的nat表，PREROUTING，POSTROUTING。
(1)载入iptables内核模块，执行并放入rc.local
bash 1 2 3 4 5 6 7 modprobe ip_tables \ modprobe iptable_filter \ modprobe iptable_nat \ modprobe ip_conntrack \ modprobe ip_conntrack_ftp \ modprobe ip_nat_ftp \ modprobe ipt_state bash 1 2 3 $ lsmod|egrep ^ip iptable_nat 6051 0 iptable_filter 2793 0 2.3 局域网的机器： 局域网的机器有一块网卡即可，确保局域网的机器C，默认网关这只了网关服务器B的eth1内网卡IP（172.168l.1.10）。把主机C的gateway设置为B的内网卡192的网卡ip即172.168l.1.10。 检查手段： 分别ping网关服务器B的内外网卡IP，都应该是通的就对了. 出公网检查除了PING网站域名外，也要ping下外网ip，排除DNS故障。不通 ping 10.0.0.254网关也是不通的。 如上，请准备两台虚拟机B和C，其中B要有双网卡。B的内网卡的网段和C的网段一样。</description>
    </item>
    <item>
      <title>ch6 iptables生产应用场景</title>
      <link>https://www.oomkill.com/ch6-iptables-application/</link>
      <pubDate>Sat, 22 Oct 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch6-iptables-application/</guid>
      <description>1、局域网共享上网（适合做企业内部局域网上网网关，以及IDC机房内网的上网网关 nat POSTROUTING）
2、服务器防火墙功能（适合IDC机房具有外网IP服务器，主要是filter INPUT的控制）
3、把外部IP及端口映射到局域网内部（可以一对一IP映射，也可针对某一个端口映射。）
也可能是IDC把网站的外网VIP级网站端口映射到负载均衡器上（硬件防火墙）（NAT PREROUTING）
4、办公路由器+网关功能（zebra路由+iptables过滤及NAT+squid正向透明代理80+ntop/iftop/iptaf流量查看+tc/cbq流量控制限速）。
5、邮件的网关。
问题2：的生产环境应用：用于没有外网地址的内网服务器，映射为公网IP后对外提供服务，也包括端口的映射
问题3：IP一对一映射 用于没有外网地址的内网服务器，映射为公网IP后对外提供服务，例如：ftp服务要一对一IP映射。
共享上网封IP的方法：
bash 1 2 /sbin/iptables -I FROWAED -s 10.0.0.26 -j　DROP /sbin/iptables ${deal} FROWARD -m mac --mac -source ${strIpMac} -j DROP 映射多个外网IP上网 bash 1 2 iptables -t nat -A POSTROUTING -s 10.0.1.0/255.255.240.0 -o eth0 -j SNAT --to-source 124.42.60.11-124.42.60.16 iptables -t nat -A POSTROUTING -s 172.168.1.0/255.255.255.0 -o eth0 -j SNAT --to=source 124.42.60.60-124.42.60.63 问题：公司内网主机多的时候，访问网站容易被封。</description>
    </item>
    <item>
      <title>ch7 关于iptables的内核参数</title>
      <link>https://www.oomkill.com/ch7-iptables-kernel-parameter/</link>
      <pubDate>Sat, 22 Oct 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ch7-iptables-kernel-parameter/</guid>
      <description>调整内核参数文件/etc/sysctl.conf，以下是我们生产环境的某个服务器的配置：
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 # 表示如果套接字由本端要求关闭，这个檀树决定了他保持在FIN-WAIT-2状态的时间。 net.ipv4.tcp_fin_timeout = 2 # 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接，默认为0，表示关闭。 net.ipv4.tcp_tw_reuse = 1 # 表示开启TCP连接中TIME-WAIT socket的快速收回，默认为0，表示关闭 net.ipv4.tcp_tw_recycle = 1 提示：以上两个参数为了防止生产环境下 time_wait过多设置的。 ############################################################ # 表示开启SYN Cookie。当出现SYN等带队列溢出时，启动cookie来处理，可防范少量SYN攻击，默认为0表示关闭 net.ipv4.tcp_syncookies = 1 # 表示当keepalive起用的时候，TCP发送keepalive消息的频度。缺省是两小时，改为20分钟 单位秒 net.ipv4.tcp_keepalive_time = 1200 # 表示对用向外连接的端口范围。缺省情况下很小。 net.ipv4.ip_local_port_range = 4000 65000 # 表示SYN队列的长度，默认为1024，加大队列长度为8192，可容纳更过等待连接的网络连接数。 net.</description>
    </item>
    <item>
      <title>Apache httpd配置集锦</title>
      <link>https://www.oomkill.com/apache-httpd/</link>
      <pubDate>Sun, 16 Oct 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/apache-httpd/</guid>
      <description>httpd下载地址：Historical releases
安装httpd bash 1 2 3 4 5 6 7 $ ls ABOUT_APACHE buildconf	emacs-style INSTALL	LICENSE	os	srclib acinclude.m4 CHANGES	httpd.dep InstallBin.dsp Makefile.in README support Apache.dsw config.layout httpd.dsp LAYOUT Makefile.win README.platforms test build configure httpd.mak libhttpd.dep modules README-win32.txt VERSIONING BuildAll.dsp configure.in httpd.spec libhttpd.dsp NOTICE ROADMAP BuildBin.dsp docs include libhttpd.mak NWGNUmakefile server httpd 编译参数 参数选项 注释说明 ./configure 配置源代码树 –prefix=/usr/local/apache2 体系无关文件的顶级安装目录PREFIX，也就Apache的安装目录。 –enable-module=so [-enable-deflate] 打开so模块，so模块是用来提DSO支持的apache核心模块 –enable-deflate=shared [-enable-expires] 支持网页压缩 –enable-expires=shared [-enable-rewrite] 支持缓存过期控制 –enable-rewrite=shared 支持URL重写 –enable-cache 支持缓存 –enable-file-cache 支持文件缓存 –enable-mem-cache 支持记忆缓存 –enable-disk-cache 支持磁盘缓存 –enable-static-support 支持静态连接(默认为动态连接) –enable-static-htpasswd 使用静态连接编译htpasswd–管理用于基本认证的用户文件 –enable-static-htdigest 使用静态连接编译htdigest–管理用于摘要认证的用户文件 –enable-static-rotatelogs 使用静态连接编译rotatelogs–滚动Apache日志的管道日志程序 –enable-static-logresolve 使用静态连接编译logresolve–解析Apache日志中的IP地址为主机名 –enable-static-htdbm 使用静态连接编译htdbm–操作DBM密码数据库 –enable-static-ab 使用静态连接编译ab–Apache服务器性能测试工具 –enable-static-checkgid 使用静态连接编译checkgid –disable-cgid 禁止用一个外部CGI守护进程执行CGI脚本 –disable-cgi 禁止编译CGI版本的PHP –disable-userdir 禁止用户从自己的主目录中提供页面 –with-mpm=worker 让apache以worker方式运行 –enable-authn-dbm=shared 对动态数据库进行操作。Rewrite时需要。 以下是分门别类的更多参数注解，与上面的会有重复 用于apr的configure脚本的选项： 可选特性 &amp;ndash;enable-experimental-libtool 启用试验性质的自定义libtool &amp;ndash;disable-libtool-lock 取消锁定(可能导致并行编译崩溃) &amp;ndash;enable-debug 启用调试编译，仅供开发人员使用。 &amp;ndash;enable-maintainer-mode 打开调试和编译时警告，仅供开发人员使用。 &amp;ndash;enable-profile 打开编译profiling(GCC) &amp;ndash;enable-pool-debug[=yes|no|verbose|verbose-alloc|lifetime|owner|all] 打开pools调试 &amp;ndash;enable-malloc-debug 打开BeOS平台上的malloc_debug &amp;ndash;disable-lfs 在32-bit平台上禁用大文件支持(large file support) &amp;ndash;enable-nonportable-atomics 若只打算在486以上的CPU上运行Apache，那么使用该选项可以启用更加高效的基于互斥执行 的原子操作。 &amp;ndash;enable-threads 启用线程支持在线程型的MPM上必须打开它 &amp;ndash;disable-threads 禁用线程支持，如果不使用线程化的MPM，可以关闭它以减少系统开销。 &amp;ndash;disable-dso 禁用DSO支持 &amp;ndash;enable-other-child 启用可靠子进程支持 &amp;ndash;disable-ipv6 禁用IPv6支持 **可选的额外程序包** &amp;ndash;with-gnu-ld 指定C编译器使用GNU ld &amp;ndash;with-pic 只使PIC/non-PIC对象[默认为两者都使用] &amp;ndash;with-tags[=TAGS] 包含额外的配置 &amp;ndash;with-installbuilddir=DIR 指定APR编译文件的存放位置(默认值为：’${datadir}/build’) &amp;ndash;without-libtool 禁止使用libtool连接库文件 &amp;ndash;with-efence[=DIR] 指定Electric Fence的安装目录 &amp;ndash;with-sendfile 强制使用sendfile(译者注：Linux2.</description>
    </item>
    <item>
      <title>php.ini优化</title>
      <link>https://www.oomkill.com/php-ini/</link>
      <pubDate>Mon, 03 Oct 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/php-ini/</guid>
      <description>PHP引擎缓存优化加速 eaccelerator zend opcode xcache 使用tmpfs作为缓存加速缓存的文件目录 bash 1 2 mount -t tmpfs tmpfs /dev/shm -o size=256m mount -t tmpfs /dev/shm/ /tmp/eaccelerator/ 利用好tmpfs
1.上传目录缩略图临时处理目录/tmp.
2.其他加速器临时目录/tmp/eaccelerator/
php.ini参数优化 无论是 apache 还是 nginx，php.ini都是适合的。而 php-fpm.conf 适合nginx。而php-fpm.conf更适合 nginx+fcgi 的配置。首选选择产品环境的 php.ini
开发场景：development 生产环境：production 打开php的安全模式 php的安全模式是个非常重要的php内嵌的安全机制，能够控制一些php中的函数执行，比如system() ,同时把很多文件操作的函数进行了权限控制。php5.4后弃用
该参数配置如下：
text 1 2 3 336 ; Safe Mode 337 ; http://php.net/safe-mode 338 safe_mode = Off 用户和安全组 当safe_mode打开时，safe_mode_gid被关闭，那么php脚本能够对文件进行访问，而且相同组的用户也能够对文件进行访问。建议设置为safe_mode_gid=off;
如果不进行设置，可能我们无法对我们服务器网站目录下的文件进行操作了，比如我们需要对文件进行操作的时候。php5.3默认为 safe_mode_gid=off; （新版弃用）
关闭危险函数 如果打开了安全模式，那么函数禁止是可以不需要的，但是我们为了安全还是考虑进去。比如，我们觉得不希望执行包括 system() 等在那的能够执行命令的php函数，或者能够查看php信息的 phpinfo() 等函数，那么我们就可以禁止他们，方法如下：
text 1 disable_functions = system,passthru,exec,shell_exec,popen,phpinfo 如果你要禁止任何文件和目录的操作，那么可以关闭很多文件操作。</description>
    </item>
    <item>
      <title>PHP安装错误记录</title>
      <link>https://www.oomkill.com/install-troubleshooting/</link>
      <pubDate>Sun, 02 Oct 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/install-troubleshooting/</guid>
      <description>编译错误 错误：同时指定了fpm与aspxs2方式错误 bash 1 2 You&amp;#39;ve configured multiple SAPIs to be build.You can build only one SAPI module and CLI binary at the same time 原因：导致的原因是我的配置参数中同时使用了&amp;ndash;enable-fpm 与&amp;ndash;with-apxs2，因此编译的时候出错了，去掉其中的任意一个参数编译成功。
系统缺少libtool bash 1 make ***[libphp5.la] Error 1 解决方法：在编译PHP版本时，产生错误 make ***[libphp5.la] Error 1
错误原因：系统缺少libtool
解决办法：yum install libtool-ltdl-devel
make过程错误 make: *** [sapi/cli/php] Error 1 原因：在 「./configure 」 沒抓好一些环境变数值。错误发生点在建立「-o sapi/cli/php」是出错，没給到要 link 的 iconv 库参数。
报错提示：
bash 1 2 3 4 5 6 7 8 9 libiconv.so.2: cannot open shared object file: No such file or directory mak /root/tools/php-7.</description>
    </item>
    <item>
      <title>memcached从入门到精通</title>
      <link>https://www.oomkill.com/memcached/</link>
      <pubDate>Wed, 28 Sep 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/memcached/</guid>
      <description>1 Memcached介绍及常见同类软件对比 1.1 Memcached是什么？ Memcached是一个开源的、支持高性能、高并发的分布式缓存系统，由C语言编写，总共2000多行代码。从软件名称上看，前3个字符的单词Mem就是内存的意思，接下来的后面5个字符的单词Cache就是缓存的意思，最后一个字符d是daemon的意思，代表是服务端守护进程模式服务。
Memcached服务分为服务端和客户端两部分，其中，服务端软件的名字形如 Memcached-1.4.24.tat.gz，客户端软件的名字形如 Memcache-2.25.tar.gz
Memcached软件诞生于2003年，最初由LiveJournal的BradFitzpatrick开发完成。Memcached是整个项目的名称，而Memcached是服务器端的主程序名，因其协议简单，使用部署方便、且支持高并发而被互联网企业广泛使用，知道现在仍然被广泛应用。官方网址：http://memcached.org
1.2 Memcached的作用 传统场景，多数Web应用都将数据保存到关系型数据库中（例如MySQL），Web服务器从中读取数据并在浏览器中显示。但随着数据量的增大、访问的集中，关系型数据库的负担就会加重、响应缓慢、导致网站打开延迟等问题，影响用户体验。
这时就需要Memcached软件出马了。使用Memcached的主要目的是，通过在自身内存中缓存关系型数据库的查询结果，减少数据库自身被访问的次数，以提高动态web应用的速度、提高网站架构的并发能力和可扩展性。
Memcached服务的运行原理是通过在实现规划好的系统内存空间中临时缓存数据库的各类数据，以达到减少前端业务服务对数据库的直接高并发访问，从而达到提升大规模网站急群众动态服务的并发访问能力。
生产场景的Memcached服务一般被用来保存网站中经常被读取的对象或数据，就像我们的客户端浏览器也会把经常访问的网页缓存起来一样，通过内存缓存来存取对象或数据要比磁盘存取快很多，因为磁盘是机械的，因此，在当今的IT企业中，Memcached的应用范围很广泛
1.3 互联网常见内存服务软件 下表为互联网企业场景常见内存缓存服务软件相关对比信息：
软件 类型 主要作用 缓存的数据 Memcached 纯内存型 常用于缓存网站后端的各类数据，例如数据库中的数据 主要缓存用户重复请求的动态内容，blog的博文BBS的帖子等内容用户的Session会话信息 Redis/Mongodb/memcachedb 可持久化存储，即使用内存也会使用磁盘存储 1. 缓存后端数据库的查询数据
2.作为关系数据库的重要补充 1.作为缓存：主要缓存用户重复请求的动态内容：例如BLOG的博文、BBS的帖子等内容。2.作为数据库的有效补充：例如：好友关注、粉丝统计、业务统计等功能可以用持久化存储。 Squid/Nginx 内存或内存加磁盘缓存 主要用于缓存web前端的服务内容 主要用于静态数据缓存，例如：图片，附件（压缩包），js,css,html等，此部分功能大多数企业会选择专业的CDN公司如：蓝讯、网宿。 2 Memcached常见用途工作流程 Memcached是一种内存缓存软件，在工作中经常用来缓存数据库的查询数据，数据被缓存在事先预分配的Memcached管理的内存中，可以通过API或命令的方式存取内存中缓存的这些数据，Memcached服务内存中缓存的数据就像一张巨大的HASH表，每条数据都是以key-value对的形式存在。
2.1 网站读取Memcached数据时的工作流程 Memcached用来缓存查询到的数据库中的数据，逻辑上，当程序访问后端数据库获取数据时会先优先访问Memcached缓存，如果缓存中有数据就直接返回给客户端用户，如果没有数据（没有命中）程序再去读取后端的数据库的数据，读取到需要的数据后，把数据返回给客户端，同时还会把读取到的数据库缓存到Memcached内存中，这样客户端用户再请求相同数据就会直接读取Memcached缓存的数据，这样就大大减轻了后端数据库的压力，并提高了整个网站的响应速断，提升了用户体验。
图2-1展示了Memcached缓存系统和后端数据库系统的协作流程上图，使用Memcached缓存查询数据来减少数据库压力的具体工作流程如下：
web程序首先检查客户端请求的数据是否在Memcached缓存中存在，如果存在，直接把请求的数据返回给客户端，此时不在请求后端数据库。
如果请求的数据在Memcached缓存中不存在，则程序会请求数据库服务，把数据库中取到的数据返回给客户端，此时不再请求后端数据库。
2.2 网站更新Memcached数据时工作流程 当程序更新或者删除数据时，会首先处理后端数据库中的数据。 程序处理后端数据库中的数据的同时，也会通知Memcached中的对应旧数据失效，从而保证Memcached中缓存的数据始终和数据库中的户数一直，这个数据一致性非常重要，也是大型网站分布式缓存集群的最头痛的问题所在。 如果是在高并发读写场合，除了要程序通知Memcached过期的缓存失效外，还可能会通过相关机制，例如在数据库上部署相关程序（例如：在数据库中设置触发器使用UDFs），实现当数据库有更新就会把数据更新到Memcached服务中，使得客户端在访问新数据前，预先把更新过的数据库数据复制到Memcached中缓存起来，这样可以减少第一次查询数据库带来的访问压力，提升Memcached中缓存的命中率，甚至sina门户还会把持久化存储redis做成MySQL数据库的从库，实现真正的主从复制。 Memcached网站作为缓存应用更新数据流程图见下图1-2Memcached服务作为缓存应用通过相关软件更新数据见图2-23 Memcached在企业中的应用场景 3.1 作为数据库查询数据缓存 3.1.1 完整数据缓存 例如电商的商品分类功能不会经常变动，就可以实现放到Memcached里，然后再对外提供数据访问。这个过程被称之为“数据预热”。
此时秩序读取缓存无需读取数据库就能读到Memcached缓存里的所有商品分类数据了，所以数据库的访问压力就会大大降低了。
为什么商品分类数据可以实现放在缓存里呢？
因为，商品分类几乎都是由内部人员管理的，如果需要更新数据，更新数据库后，就可以把数据同时更新到Memcached里。
如果把商品分类数据做成静态化文件，然后通过在前段WEB缓存或者使用CDN加速效果更好。
3.1.2 热点数据缓存 热点数据缓存一般是用于由用户更新的商品，例如淘宝的卖家，当卖家新增商品后，网站程序就会把商品写入后端数据库，同时把这部分数据，放入Memcached内存中，下一次访问这个商品的请求就直接从Memcached内存中取走了。这种方法用来缓存网站热点的数据，即利用Memcached缓存经常被访问的数据。
特别提示：这个过程可以通过程序实现，也可以在数据库上安装软件进行设置，直接由数据库把内容更新到Memcached中，相当于Memcached是MySQL的丛库一样。
淘宝、京东、小米等电商双11秒杀抢购场景：
如果碰到电商双11秒杀高并发的业务场景，必须要实现预热各种缓存，包括前端的web缓存和后端的数据缓存。</description>
    </item>
    <item>
      <title>网络共享 - centos7安装vsftpd</title>
      <link>https://www.oomkill.com/vsftp-network-filesystem/</link>
      <pubDate>Wed, 28 Sep 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/vsftp-network-filesystem/</guid>
      <description>配置防火墙，开启FTP服务器需要的端口 CentOS 7.0默认使用的是firewall作为防火墙，这里改为iptables防火墙。
关闭firewall： bash 1 2 systemctl stop firewalld.service #停止firewall systemctl disable firewalld.service #禁止firewall开机启动 安装iptables防火墙 bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 yum install iptables-services # 安装 vi /etc/sysconfig/iptables # 编辑防火墙配置文件 # Firewall configuration written by system-config-firewall # Manual customization of this file is not recommended. *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 21 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 10060:10090 -j ACCEPT -A INPUT -j REJECT --reject-with icmp-host-prohibited -A FORWARD -j REJECT --reject-with icmp-host-prohibited COMMIT :wq!</description>
    </item>
    <item>
      <title>一致性hash在memcache中的应用</title>
      <link>https://www.oomkill.com/consistent-hash/</link>
      <pubDate>Wed, 28 Sep 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/consistent-hash/</guid>
      <description>Memcache应用场景 基本场景 比如有 N 台 cache 服务器（后面简称 cache），那么如何将一个对象 object 映射到 N 个 cache 上呢，你很可能会采用类似下面的通用方法计算 object 的 hash 值，然后均匀的映射到到N个cache; hash(object)%N
如下图：
这时，一切都运行正常，再考虑如下的两种情况：
一个 cache服务器m down掉了（在实际应用中必须要考虑这种情况），这样所有映射到cache m的对象都会失效，怎么办，需要把cache m从cache 中移除，这时候 cache 是 $N-1$ 台，映射公式变成了 hash(object)%(N-1) 。此时数据 $3%3-1=3%2=1$ 此时，3应该在S3上，但是由于S3down机导致到S1去取，这时会未命中。如下图
由于访问加重，需要添加 cache ，这时候 cache 是 $N+1$ 台，映射公式变成了 hash(object)%(N+1) 。1和2意味着突然之间几乎所有的 cache 都失效了。对于服务器而言，这是一场灾难，洪水般的访问都会直接冲向后台服务器。$\frac{N-1} { N\times (N-1)}$
即：
有N台服务器，变为 $N-1$ 台，即每 $N \times (N-1)$个数中，求余相同的只有 N-1 个。命中率为：$\frac{1}{3}$
再来考虑第三个问题，由于硬件能力越来越强，你可能想让后面添加的节点多做点活，显然上面的 hash 算法也做不到。
有什么方法可以改变这个状况呢，这就是 consistent hashing&amp;hellip;
但现在一致性hash算法在分布式系统中也得到了广泛应用，研究过memcached缓存数据库的人都知道，memcached服务器端本身不提供分布式cache的一致性，而是由客户端来提供，具体在计算一致性hash时采用如下步骤：
首先求出memcached服务器（节点）的哈希值，并将其配置到 0～232 的圆（continuum）上。
然后采用同样的方法求出存储数据的键的哈希值，并映射到相同的圆上。
然后从数据映射到的位置开始顺时针查找，将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器，就会保存到第一台memcached服务器上。</description>
    </item>
    <item>
      <title>网络共享 - centos7安装samba</title>
      <link>https://www.oomkill.com/samba-network-filesystem/</link>
      <pubDate>Thu, 22 Sep 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/samba-network-filesystem/</guid>
      <description>安装samba服务 text 1 yum install samba -y 配置samba服务 text 1 2 cp /etc/samba/smb.cnf{,.`date +%F`} #&amp;lt;== 修改前备份 vim /etc/samba/smb.cnf smb配置文件 bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #=================== Global Settings[全局选项] ============================== [global] workgroup = WORKGROUP #&amp;lt;==设定Samba Server所要加入的工作组或域 server string = Samba Server Version %v #&amp;lt;==设定注释，宏%v表示显示Samba的版本号 netbios name = zhi #&amp;lt;==设置Samba Server的NetBIOS名称 map to guest = bad user #&amp;lt;==开启匿名访问 # ----------------- Logging Options [日志选项]----------------------------- #设置日志文件存储位置及名称，宏%m(主机名),表示对每台访问Samba Server的机器都单独记录一个日志文件 log file = /var/log/samba/log.</description>
    </item>
    <item>
      <title>长期总结 - Linux日志查询命令</title>
      <link>https://www.oomkill.com/awesome-linux-log-command/</link>
      <pubDate>Fri, 12 Aug 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/awesome-linux-log-command/</guid>
      <description>工具命令集合 长期总结 - Linux日志查询命令 长期总结 - Linux网络命令合集 长期总结 - Linux性能分析命令 awk常用案例 bash shell常用示例 探索kubectl - 巧用jsonpath提取有用数据 探索kubectl - kubectl诊断命令集合 理解ldap - OpenLDAP客户端命令行使用 sed 语法
bash 1 sed &amp;#39;/过滤的内容/处理的命令&amp;#39; 文件 参数 注释说明 n 取消sed默认的输出 i 替换文件内容 r 如果有特殊字符不用转义（正则） g 全局替换 d 删除 p print打印 # 为分隔符可以用其他符号替换（最好用$ @ /）替换内容中如果有分隔符，需要将分隔符替换为别的分隔符，如果不换可将内容转义 s 为search g为globla全局替换，不加的话只替换一列
打印
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 $ sed -n &amp;#39;2p&amp;#39; 3.</description>
    </item>
    <item>
      <title>SSH服务详解</title>
      <link>https://www.oomkill.com/ssh-service/</link>
      <pubDate>Fri, 05 Aug 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/ssh-service/</guid>
      <description>什么是 SSH ？ SSH全称(SecureSHell)是一种网络协议，顾名思义就是非常安全的shell，主要用于计算机间加密传输。早期，互联网通信都是基于明文通信，一旦被截获，内容就暴露无遗。1995年，芬兰学者Tatu Ylonen设计了SSH协议，将登录信息全部加密，成为互联网安全的一个基本解决方案，迅速在全世界获得推广，目前已经成为Linux系统的标准配置。
SSH服务是由OpenSSH服务端软件OpenSSH和客户端（常见的由SSH，SecureCRT，Xshell，putty）组成，默认使用22端口提供服务，有两个不兼容的ssh协议版本，分别为1.x和2.x。
SSH协议目前有SSH1和SSH2两个主流版本，SSH2协议兼容SSH1，强烈建议使用SSH2版本。目前实现SSH1和SSH2协议的主要软件有OpenSSH 和SSH Communications Security Corporation　公司的SSH Communications 软件。前者是OpenBSD组织开发的一款免费的SSH软件，后者是商业软件，因此在linux、FreeBSD、OpenBSD 、NetBSD等免费类UNIX系统种，通常都使用OpenSSH作为SSH协议的实现软件。
sh 1 2 3 $ rpm -qa openssh openssl openssl-1.0.1e-30.el6.x86_64 openssh-5.3p1-104.el6.x86_64 SSH1.x
每台ssh服务器主机都可以使用rsa加密方式来产生一个1024bit的RSAKey，这个RSA的加密方式就是用来产生公钥与私钥的算法之一，SSH1.x的整个联机加密步骤如下： 当SSH服务启动时，会产生一个768-bit的临时公钥（sshd_config配置文件中ServerKeyBits 768）存放在server中
sh 1 2 3 # centos5为768 centos6为1024 $ grep ServerKey /etc/ssh/sshd_config #ServerKeyBits 1024 当客户端联机请求传送过来时，服务器就会将这个768-bit的公钥传给客户端，此时客户端会将此公钥与先前存储的公钥进行对比，看是否一致。判断标准是服务器端联机用户目录下~/.ssh/know_hosts文件的内容（linux客户端）
sh 1 2 3 $ ssh -p22 lamp@192.168.65.62 $ ll .ssh/known_hosts -rw-r--r--. 1 root root 395 Jun 16 13:15 .ssh/known_hosts windows SecureCRT图示 在客户端接收到这个768-bit的Server Key后，客户端本地也会产生一个256bit的私钥（private key或host key），并且以加密的方式（具体的加密算法由客户端在服务器提供的所有可用算法中选择，默认为3DES算法），将Server key与host</description>
    </item>
    <item>
      <title>使用SSH协议来传输文件</title>
      <link>https://www.oomkill.com/scp/</link>
      <pubDate>Sun, 24 Jul 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/scp/</guid>
      <description>SSH客户端附带的远程拷贝scp命令 scp是加密 的远程拷贝，可以把数据从一台机器推送到另一台机器，也可以从其他服务器把数据拉回到本地执行命令的服务器，但是，每次都是全量拷贝（rsync增量拷贝），因此效率不高。 scp的基本语法使用 secure copy （remote file copy ）
参数选项 注释说明 -p 拷贝前后保持文件或目录属性 -P （大写）	接端口，默认22端口时可省略 -r 拷贝目录 -l 限制速度 推：scp -Pport 源 目标(user@host_ip):/path
sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ touch {a..f}.txt $ ls a.txt b.txt c.txt d.txt e.txt f.txt $ scp -P22 a.txt root@192.168.65.62:/ root@192.168.65.62&amp;#39;s password: a.txt 100% 0 0.0KB/s 00:00 $ ls / app a.txt 拉：scp -Pport 源(user@host_ip):/path 目标</description>
    </item>
    <item>
      <title>expect使用案例</title>
      <link>https://www.oomkill.com/expect/</link>
      <pubDate>Sat, 23 Jul 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/expect/</guid>
      <description>什么是Expect Expent是基于tcl的相对简单的一个免费的脚本编程工具语言，用来实现自动和交互任务程序进行通信，无需人的手工干预。比如SSH、FTP等，这些程序正常情况都需要手工与它们进行交互，而使用Expect就可以模拟人手工交互的过程，实现自动的和远程的程序交互，从而达到自动化运维的目的。
Expect程序工作流程 Expect的工作流程可以理解为，spawn启动进程 ==&amp;gt; expect期待关键字 ==&amp;gt; send向进程发送字符 ==&amp;gt; 退出结束。
安装Expect软件 首先，配置好yum安装源，并且确保机器可以上网，然后执行yum install expect -y即可安装Expect软件。
安装完后查看结果：
sh 1 2 $ rpm -qa|grep expect expect-5.44.1.15-5.el6_4.x86_64 先看一个Expect小实例 首先准备3台虚拟机：
sh 1 2 3 4 192.168.252.60 client 192.168.252.62 client 192.168.252.63 client 192.168.252.64 server 再执行下面例子前，我们先手工执行如下命令
sh 1 ssh -p52113 root@192.168.252.64 ifconfig 执行结果：
sh 1 2 $ ssh -p52113 root@192.168.252.64 ifconfig root@192.168.252.64&amp;#39;s password: Expect 例子脚本内容：
sh 1 2 3 4 5 6 7 #!/usr/bin/expect spawn ssh -p52113 root@192.</description>
    </item>
    <item>
      <title>编译安装PHP</title>
      <link>https://www.oomkill.com/php-installtation/</link>
      <pubDate>Thu, 09 Jun 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/php-installtation/</guid>
      <description>下载PHP 台湾镜像站：http://ftp.ntu.edu.tw/php/distributions/ 搜狐镜像站：http://mirrors.sohu.com/php/ 阿里镜像：http://mirrors.aliyun.com/ 官网：http://php.net/downloads.php 检查PHP所需的lib库 bash 1 2 3 4 5 6 7 8 9 10 11 rpm -qa \ zlib-devel \ libxml2-devel \ libjpeg-devel \ libjpeg-turbo-devel \ libiconv-devel \ freetype-devel \ libpng-devel \ gd-devel \ libcurl-devel \ libxslt-devel 提示：libjpeg-turbo-devel是早期libjpeg-devel的新名字，libcurl-devel是早期curl的新名字。
每个lib一般都会存在对应的以“-devel”命名的包，安装lib对应的-devel包后，对应的lib包就会自动安装好，例如安装gd-devel时就会安装gd。
这些lib库不是必须安装的，但是目前的企业环境下一般都需要安装。否则，PHP程序运行时会出现问题，例如验证码无法显示等。
执行下面命令安装相关的lib软件包：
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 yum install -y \ zlib-devel \ libxml2-devel \ libjpeg-devel \ libjpeg-turbo-devel \ freetype-devel \ libpng-devel \ gd-devel \ curl-devel \ libxslt-devel \ bzip2-devel \ gmp-devel \ readline-devel 提示：从安装上看，仅有libiconv-devel这个包没有安装，因为默认的yum源没有此包。可以一个一个地yum安装或通过源文件手工编译安装（这样效率慢）</description>
    </item>
    <item>
      <title>配置PHP插件</title>
      <link>https://www.oomkill.com/php-install-cache-accelerator/</link>
      <pubDate>Mon, 06 Jun 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/php-install-cache-accelerator/</guid>
      <description>PHP缓存加速器介绍 操作码介绍及缓存原理 当客户端请求一个PHP程序时，服务器的PHP引擎会解析该PHP程序，并将其编译为特定的操作码（Operate Code，简称opcode）文件，该文件是执行PHP代码后的一种二进制表示形式。默认情况下，这个编译好的操作码文件由PHP引擎执行后丢弃。而操作码缓存（Opcode Cache）的原理就是将编译后的操作码保存下来，并放到共享内存里，以便在下一次调用该PHP页面时重用它，避免了相同代码的重复编译，节省了PHP引擎重复编译的时间，降低了服务器负载，同时减少了CPU和内存开销。
PHP缓存加速软件介绍 为了提高PHP引擎的高并发访问及执行速度，产生了一系列PHP缓存加速软件。这些软件设计的目的就是缓存前文提到的PHP引擎解析过的操作码文件，以便在指定时间内有相同的PHP程序请求访问时，不再需要重复解析编译，而是直接调用缓存中的PHP操作码文件，这样就提高了动态Web服务的处理速度，从而提升了用户访问企业网站的整体体验。
LAMP环境PHP缓存加速器的原理 下面简单介绍Apache环境的PHP缓存加速器原理。
在LAMP环境中，Apache服务是使用libphp5.so响应处理PHP程序请求的，整个流程大概如下：
Apache接收客户的PHP程序请求，并根据规则过滤之。
Apache将PHP程序请求传递给PHP处理模块libphp5.so。
PHP引擎定位磁盘上的PHP文件，并将其加载到内存中解析。
PHP处理模块libphp5.so将PHP源代码编译成为opcode。
PHP处理模块libphp5.so执行opcode，然后把opcode缓存起来。
Apache接收客户端新的PHP程序请求，PHP引擎直接读取缓存执行opcode文件，并将结果返回。在这一次任务中，就无第4步的编译解 析了，从而提升了PHP编译解析效率。
PHP缓存加速器解决的是上述第5步的问题，默认情况下PHP会将opcode内容执行后丢弃，这里却通过PHP缓存加速软件，将opcode内容缓存了下来，目的是当有重复请求时，不需要再重复编译解析PHP程序代码，因为在高并发高访问量的网站上，大量的重复编译会消耗很多的系统资源和时间，而这也就会成为瓶颈，既影响了处理速度，又加重了服务器的负载，为了解决此问题，PHP缓存加速器就这样诞生了。
图4-1是LAMP环境下PHP请求及操作码缓存过程的原理示意图LNMP环境PHP缓存加速器的原理详解 在LNMP环境中，PHP引擎不再使用libphp5.so模块了，而是启动了独立的FCGI即php-fpm进程，由它监听来自Nginx的PHP程序请求，并交给PHP引擎解析处理，整个执行流程大概如下：
PHP缓存加速器软件种类及选择建议 PHP缓存加速器软件常见的种类有XCache、eAccelerator、APC（Alternative PHP Cache），ZendOpcache等，那么，在企业环境我们要如何选择PHP缓存加速器软件呢？
事实上，任选其一即可，没必要都安装上，都安装也可能会发生冲突。总的建议就是根据企业的业务需求及选择前的压力测试结果，或者根据个人的经验偏好选择。不过，老男孩建议首选XCache，其次是eAccelerator，如果想尝新，可以选择ZendOpcache。
首选XCache的原因如下：
经过测试，XCache效率更高、速度更快。 XCache软件开发社区更活跃，最新版2014年底发布。 支持更高版本的PHP，例如PHP 5.5、PHP 5.6。 次选eAccelerator的原因如下：
安装及配置参数更简单，加速效果也不错。 文档资料较多，但官方对软件的更新很慢，社区不活跃。 仅适合PHP版本5.4以下的程序。 选择ZendOpcache的原因如下：
是PHP官方研发的新一代缓存加速软件，以后的发展潜力可能会很好，PHP 5.5以前的版本可以通过ZendOpcache软件以插件扩展的方式安装，从PHP 5.5版本开始已经整合到PHP软件里了，编译时只需指定一个参数即可，例如：&amp;ndash;enable-opcache。 ZendOpcache可能是未来的缓存加速首选，现在的稳定性还有待检验，小规模环境下PHP 5以前的版本可以通过插件式安装使用，PHP 5以上的版本可以直接指定参数编译使用。若可以忍受ZendOpcache的各种未知问题的话，也可以尝试使用。 安装PHP缓存加速器扩展 安装PHP eAccelerator缓存加速模块 eAccelerator缓存加速插件说明
eAccelerator是一个免费的、开放源代码的PHP加速、优化及缓存的扩展插件软件，它可以缓存PHP程序编译后的中间代码文件（opcode）、session数据等，降低PHP程序在编译解析时对服务器的性能开销。eAccelerator还可以加快PHP程序的执行速度，降低服务器负载压力，使PHP程序代码执行效率提高1~10倍。
eAccelerator会把编译好的PHP程序存放在共享内存里，然后每次从内存里调用执行，可以设定把一些不适合放在内存里缓存的编译结果存储到磁盘上，默认情况下，磁盘和内存缓存都会被eAccelerator使用。
eAccelerator的最新版为0.9.6.1，支持的PHP最新版本为PHP 5.3及以前5系列的版本。 早期的0.9.5版本支持PHP 4和PHP 5.2以前的版本。
eAccelerator下载地址为：https://github.com/eaccelerator/eaccelerator/downloads。
eAccelerator插件安装过程
具体的安装命令集如下：
bash 1 2 /app/php/bin/phpize ./configure --enable-eaccelerator=shared --with-php-config=/app/php/bin/php-config 安装PHP XCache缓存加速模块 XCache缓存加速插件说明
XCache是一个开源的、又快又稳定的PHP opcode缓存器/优化器，其项目leader曾经是Lighttpd（和Nginx类似的高速Web服务软件）的开发成员之一。XCache把PHP程序编译后的数据（opcode）缓存到共享内存里，避免相同的程序重复编译。用户请求相同的PHP程序时，可以直接使用缓存中已编译好的数据，从而提高PHP的访问速度，通常可以提升2~5倍，并大幅降低服务器负载开销。
很多公司使用XCache，它已经能在大流量/高负载的生产环境中稳定运行，与同类型的opcode缓存器相比在各个方面都更胜一筹，例如：社区活跃、快速开发、能够快速跟进PHP的版本更新等。 当前稳定版本为3.</description>
    </item>
    <item>
      <title>配置apache httpd支持php</title>
      <link>https://www.oomkill.com/apache-php/</link>
      <pubDate>Thu, 02 Jun 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/apache-php/</guid>
      <description>默认生成
bash 1 2 3 4 5 6 7 $ grep libphp5 /app/apache/conf/httpd.conf LoadModule php5_module modules/libphp5.so $ ll /app/apache/modules/ 总用量 29620 -rw-r--r--. 1 root root 9115 4月 8 03:02 httpd.exp -rwxr-xr-x. 1 root root 30316906 4月 21 01:46 libphp5.so 修改httpd配置文件311行
text 1 2 AddType application/x-httpd-php .php .phtml AddType application/x-httpd-php-source .phps 更改daemon，更改用户是为了安全考虑
常用的httpd支持php的编译参数
text 1 2 3 4 ./configure --enable-xcache=shared --with-php-config=/app/php/bin/php-config ./configure --enable-eaccelerator=shared --with-php-config=/app/php/bin/php-config ./configure --with-php-config=/app/php/bin/php-config --with-pdo-mysql=/app/mysql ./configure --with-php-config=/app/php/bin/php-config --with-imagick=/app/imagemag/ sysconfdir 指定php配置文件路径</description>
    </item>
    <item>
      <title>Linux服务管理 - systemd</title>
      <link>https://www.oomkill.com/systemd/</link>
      <pubDate>Thu, 21 Apr 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/systemd/</guid>
      <description>关于Linux服务管理 Linux系统从启动到提供服务的过程是这样，先是机器加电，然后通过MBR或者UEFI加载GRUB，再启动内核，内核启动服务，然后开始对外服务。 SysV init UpStart systemd主要是解决服务引导管理的问题。
CentOS 5：SysV init CentOS 6：Upstart CentOS 7：Systemd http://www.linuxidc.com/Linux/2015-04/115937.htm 1.1 SysV init的优缺点 SysV init是最早的解决方案，依靠划分不同的运行级别，启动不同的服务集，服务依靠脚本控制，并且是顺序执行的。
SysV init方案的优点：
1.原理简单，易于理解； 2.依靠shell脚本控制，编写服务脚本门槛比较低。 缺点是：
1.服务顺序启动，启动过程比较慢。 2.不能做到根据需要来启动服务，比如通常希望插入U盘的时候，再启动USB控制的服务，这样可以更好的节省系统资源。 1.2 UpStart的改进 为了解决系统服务的即插即用，UpStart应运而生，在CentOS6系统中，SysV init和UpStart是并存的，UpStart主要解决了服务的即插即用。服务顺序启动慢的问题，UpStart的解决办法是把相关的服务分组，组内的服务是顺序启动，组之间是并行启动。
1.3 systemd的诞生 SysV init服务启动慢，在以前并不是一个问题，尤其是Linux系统以前主要是在服务器系统上，常年也难得重启一次。有的服务器光硬件检测都需要5分钟以上，相对来说系统启动已经很快了。
但是随着移动互联网的到来，SysV init服务启动慢的问题显得越来越突出，许多移动设备都是基于Linux内核，比如安卓。移动设备启动比较频繁，每次启动都要等待服务顺序启动，显然难以接受，systemd就是为了解决这个问题诞生的。
systemd的设计思路是：
尽可能的快速启动服务。 尽可能的减少系统资源占用。 1.4 为什么systemd能做到启动很快 systemd使用并行的方法启动服务，不像SysV init是顺序执行的，所以大大节省了系统启动时间。
使用并行启动，最大的难点是要解决服务之间的依赖性，systemd的解决办法是使用类似缓冲池的办法。比如对TCP有依赖的服务，在启动的时候会检查依赖服务的TCP端口，systemd会把对TCP端口的请求先缓存起来，当依赖的服务器启动之后，在将请求传递给服务，使两个服务通讯。同样的进程间通讯的D-BUS也是这样的原理，目录挂载则是先让服务以为目录被挂载了，到真正访问目录的时候，才去真正操作。
systemd的特性 systemd解决了那些问题？
按需启动服务，减少系统资源消耗； 尽可能并行启动进程，减少系统启动等待时间； 提供一个一致的配置环境，不光是服务配置； 提供服务状态快照，可以恢复特定点的服务状态。 CentOS 7的systemd特性 3.1 套接字服务保持激活功能 在系统启动的时候，systemd为所有支持套接字激活功能的服务创建监听端口，当服务启动后，就将套接字传给这些服务。这种方式不仅可以允许服务在启动的时候平行启动，也可以保证在服务重启期间，试图连接服务的请求，不会丢失。对服务端口的请求被保留，并且存放到队列中。
3.2 进程间通讯保持激活功能 当有客户端应用第一次通过D-Bus方式请求进程间通讯时，systemd会立即启动对应的服务。systemd依据D-Bus的配置文件使用进程间通讯保持激活功能。
3.3 设备保持激活功能 当特定的硬件插入时，systemd启动对应的硬件服务支持。systemd依据硬件服务单元配置文件保持硬件随时被激活。
3.4 文件路径保持激活功能 当特定的文件或者路径状态发生改变的时候，systemd会激活对应的服务。systemd依据路径服务单元配置文件保证服务被激活。
3.5 系统状态快照 systemd可以临时保存当前所有的单元配置文件，或者从前一个快照中恢复单元配置文件。为了保存当前系统服务状态，systemd可以动态的生成单元文件快照。
3.6 挂载和自动挂载点管理 systemd监控和管理挂载和自动挂载点，并根据挂载点的单元配置文件进行挂载。</description>
    </item>
    <item>
      <title>Linux日志管理 - syslog</title>
      <link>https://www.oomkill.com/syslog/</link>
      <pubDate>Thu, 21 Apr 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/syslog/</guid>
      <description>rsyslog介绍 syslog守护进程，内部有两个进程，syslogd主要负责用户空间的用户进程记录日志；klog负责内核所发生的各种时间记录日志。两者合并后形成syslog。
rsyslog是syslog下一代升级产品，依然有syslogd klogd提供服务。
rsyslog可以开通远程机制监听在某个套接字上，其他任何主机所产生的日志信息由本机的rsyslog收集起来，收集完后不负责记录，而是建立一个tcp或udp连接发送给专门的日志服务器，由专门的日志服务器负责记录。默认情况下是明文的。
rsyslog特性 多线程。 支持UDP,TCP协议，基于ssl tls加密完成远程日志传输。支持RELP协议 实现将日志存储到MySQL PGSQL等关系型数据库中。 强大的过滤器，可实现过滤日志信息中任何部分，支持自定义输出格式。 日志格式 事件产生的事件 主机 进程pid 事件
bash 1 2 3 Jun 6 23:36:58 Lamp-02 NET[1838]: /etc/sysconfig/network-scripts/ifup-post: updated /etc/resolv.conf Jun 6 23:46:15 Lamp-02 yum[1963]: Updated: mysql-libs-5.1.73-8.el6_8.x86_64 Jun 6 23:46:16 Lamp-02 yum[1963]: Installed: mysql-5.1.73-8.el6_8.x86_64 有些日志记录二进制日志 /var/log/wtmp /var/log/btmp
last：/var/log/wtmp 当前系统中成功登陆的日志
lastb：/var/log/btmp 当前系统中失败的登陆尝试
lastlog：显示当前系统每一个用户最近一次登陆时间
日志等级 日志级别：事件的关键性程度
lev	|说明
lev 说明 none 不记录 debug 调试信息 info 正常信息，仅是一些基本信息说明 notice 比info还需要注意的一些信息内容 warning,warn 警告信息，可能有些问题，但是还不至于影响到某个服务运作的信息 err,error 一些重大的错误信息 crit 临界状态，比error还要严重的错误信息，橙色警报 alert 红色警报，已经很有问题的等级，比crit还要严重 emerg,panic 疼痛等级，意指系统已经要宕机的状态！很严重的错误信息 设施类型 facility：把某一类具有相同特性的由各个应用程序所产生的日志数据流归类到用一个数据收集管道中，这个收集管道称之为facility。</description>
    </item>
    <item>
      <title>网络文件系统 - NFS</title>
      <link>https://www.oomkill.com/nfs-network-filesystem/</link>
      <pubDate>Wed, 13 Apr 2016 00:00:00 +0000</pubDate>
      <guid>https://www.oomkill.com/nfs-network-filesystem/</guid>
      <description>NFS介绍 什么是NFS NFS是 Network File System 网络文件系统。它的主要功能是通过网络（一般是局域网）让不同的主机系统之间可以共享文件或目录。NFS客户端（一般为应用服务器，例如Web）可以通过挂载（mount）的方式将NFS服务器端共享的数据目录挂载到NFS客户端本地系统中（就是某一个挂载点下）。从客户端本地看，NFS服务器端共享的目录就好像是客户端自己的磁盘分区或者目录一样，而实际上却是远端的NFS服务器的目录。
一般情况下，Windows网络共享服务或samba服务用于办公局域网共享，而互联网中小型网站集群架构后端常用NFS进行数据共享，如果是大型网站，那么有可能还会用到更复杂的分布式文件系统，例如：Moosefs（mfs）、GlusterFS、FastDFS。
NFS的历史介绍 第一个网络文件系统被称为File Access Listener，由Digital Equipment Corporation（DEC）在1976年开发。
NFS是第一个构建于IP协议之上的现代网络文件系统。在20世纪80年代，它首先作为实验的文件系统，由Sun Microsystems在内部完成开发。NFS协议归属于Request for Comments（RFC）标准，并且随后演化为NFSv2。作为一个标准，由于NFS与其他客户端和服务器的互操作能力很好而发展快速。
之后，标准继续演化，成为NFSv3，在RFC1813中有定义。这一新的协议比以前的版本具有更好的可扩展性，支持大文件（超过2GB），异步写入，并且将TCP作为传输协议，为文件系统在更广泛的网络中使用铺平了道路。在2000年，RFC 3010（由RFC 3530修订）将NFS带入企业级应用。此时，Sun引入了具有较高安全性、带有状态协议的NFSv4（NFS之前的版本都是无状态的）。今天，NFS版本的4.1（由RFC 5661定义）增加了对跨越分布式服务器并行访问的支持（称为PNFS extension）。
NFS系统已经历了近30年的发展。它代表了一个非常稳定的（及可移植）网络文件系统，具备可扩展、高性能等特性，并达到了企业级应用质量标准。由于网络速度的增加和延迟的降低，NFS系统一直是通过网络提供文件系统服务的有竞争力的选择，特别是在中小型互联网企业中，应用十分广泛。
NFS在企业中的应用场景 在企业集群架构的工作场景中，NFS网络文件系统一般被用来存储共享视频、图片、附件等静态资源文件，通常网站用户上传的文件都会放到NFS共享里，例如：BBS产品的图片、附件、头像（注意网站BBS程序不要放在NFS共享里），然后前端所有的节点访问这些静态资源时都可读取NFS存储上的资源。NFS是当前互联网系统架构中最常用的数据存储服务之一，前面说过，中小型网站公司应用频率更高，大公司或门户除了使用NFS外，还可能会使用更为复杂的分布式文件系统，比如Moosefs（mfs）、GlusterFS、FastDFS等。
企业生产集群为什么需要共享存储角色 例如：A用户传图片到Web1服务器，然后让B用户访问这张图片，结果B用户访问的请求分发到了Web2，因为Web2上没有这张图片，这就导致它无法看到A用户上传的图片，如果此时有一个共享存储，A用户上传图片的请求无论是分发到Web1还是Web2上，最终都会存储到共享存储上，而在B用户访问图片时，无论请求分发到Web1还是Web2上，最终也都会去共享存储上找，这样就可以访问到需要的资源了。这个共享存储的位置可以通过开源软件和商业硬件实现，互联网中小型集群架构会用普通PC服务器配置NFS网络文件系统实现。
当集群中没有NFS共享存储时，用户访问图片的情况如图所示。
如果集群中有NFS共享存储，用户访问图片的情况如图所示。
中小型互联网企业一般不会买硬件存储，因为太贵，大公司如果业务发展很快的话，可能会临时买硬件存储顶一下网站的压力，当网站并发继续加大时，硬件存储的扩展相对就会很费劲，且价格成几何级数增加。例如：淘宝网就曾替换掉了很多硬件设备，比如，用LVS+Haproxy替换了netscaler负载均衡设备，用FastDFS、TFS配合PC服务器替换了netapp、emc等商业存储设备，去IOE正在成为互联网公司的主流。
NFS系统原理介绍 NFS系统挂载结构图解与介绍 在NFS服务器端设置好一个共享目录/video后，其他有权限访问NFS服务器端的客户端都可以将这个共享目录/video挂载到客户端本地的某个挂载点（其实就是一个目录，这个挂载点目录可以自己随意指定），不同客户端的挂载点可以不相同。
客户端正确挂载完毕后，就可以通过NFS客户端的挂载点所在的/v/video或/video目录查看到NFS服务器端/video共享出来的目录下的所有数据。在客户端上查看时，NFS服务器端的/video目录就相当于客户端本地的磁盘分区或目录，几乎感觉不到使用上的区别，根据NFS服务器端授予的NFS共享权限以及共享目录的本地系统权限，只要在指定的NFS客户端操作挂载/v/video或/video的目录，就可以将数据轻松地存取到NFS服务器端上的/video目录中了。
什么是RPC 因为NFS支持的功能相当多，而不同的功能都会使用不同的程序来启动，每启动一个功能就会启用一些端口来传输数据，因此，NFS的功能所对应的端口无法固定，它会随机取用一些未被使用的端口来作为传输之用，其中CentOS 5.x的随机端口都小于1024，而CentOS 6.x的随机端口都是较大的。
因为端口不固定，这样一来就会造成NFS客户端与NFS服务器端的通信障碍，因为NFS客户端必须要知道NFS服务器端的数据传输端口才能进行通信，才能交互数据。
要解决上面的困扰，就需要通过远程过程调用RPC（Remote Proce-dure Call）服务来帮忙了，NFS的RPC服务最主要的功能就是记录每个NFS功能所对应的端口号，并且在NFS客户端请求时将该端口和功能对应的信息传递给请求数据的NFS客户端，从而确保客户端可以连接到正确的NFS端口上去，达到实现数据传输交互数据目的。这个RPC服务类似NFS服务器端和NFS客户端之间的一个中介，流程如图10-7所示。
拿房屋中介打个比喻吧：假设我们要找房子，这里的我们就相当于NFS客户端，中介介绍房子，就相当于RPC服务，房子所有者房东就相当于NFS服务，租房的人找房子，就要找中介，中介要预先存有房子主人的信息，才能将房源信息告诉租房的人。
那么RPC服务如何知道每个NFS的端口呢？
当NFS服务器端启动服务时会随机取用若干端口，并主动向RPC服务注册取用的相关端口及功能信息，如此一来，RPC服务就知道NFS每个端口对应的NFS功能了，然后RPC服务使用固定的111端口来监听NFS客户端提交的请求，并将正确的NFS端口信息回复给请求的NFS客户端，这样一来，NFS客户端就可以与NFS服务器端进行数据传输了。
在启动NFS Server之前，首先要启动RPC服务（CentOS 5.8下为portmap服务，CentOS 6.6下为rpcbind服务，下同），否则NFS Server就无法向RPC服务注册了。另外，如果RPC服务重新启动，原来已经注册好的NFS端口数据就会丢失，因此，此时RPC服务管理的NFS程序也需要重新启动以重新向RPC注册。要特别注意的是，一般修改NFS配置文件后，是不需要重启NFS的，直接在命令行执行/etc/init.d/nfs reload或exportfs-rv即可使修改的/etc/exports生效。
NFS的工作流程原理 当访问程序通过NFS客户端向NFS服务器端存取文件时，其请求数据流程大致如下：
1）首先用户访问网站程序，由程序在NFS客户端上发出存取NFS文件的请求，这时NFS客户端（即执行程序的服务器）的RPC服务（rpcbind服务）就会通过网络向NFS服务器端的RPC服务（rpcbind服务）的111端口发出NFS文件存取功能的询问请求。 2）NFS服务器端的RPC服务（rpcbind服务）找到对应的已注册的NFS端口后，通知NFS客户端的RPC服务（rpcbind服务）。 3）此时NFS客户端获取到正确的端口，并与NFS daemon联机存取数据。 4）NFS客户端把数据存取成功后，返回给前端访问程序，告知用户存取结果，作为网站用户，就完成了一次存取操作。 因为NFS的各项功能都需要向RPC服务（rpcbind服务）注册，所以只有RPC服务才能获取到NFS服务的各项功能对应的端口号（port number）、PID、NFS在主机所监听的IP等信息，而NFS客户端也只能通过向RPC服务询问才能找到正确的端口。也就是说，NFS需要有RPC服务的协助才能成功对外提供服务。从上面的描述，我们不难推断，无论是NFS客户端还是NFS服务器端，当要使用NFS时，都需要首先启动RPC服务，NFS服务必须在RPC服务启动之后启动，客户端无需启动NFS服务，但需要启动RPC服务。
注意： NFS的RPC服务，在CentOS 5.X下名称为portmap，在CentOS 6.X下名称为rpcbind。
安装NFS服务 搭建NFS环境准备 克隆虚拟机 克隆的虚拟机存在的网络问题 原因分析：</description>
    </item>
  </channel>
</rss>
