分类目录归档:linux

openldap

综述

使用openldap的目录功能实现一套账号关联登录多个应用,避免每个系统单独管理各自账号。测试已可实现的应用有grafana(10.2.3有bug,不要用20140116) .openvpn

基本概念

dc 域, uid 用户ID , cn 通用名称(通常 cn或uid可作为第三方系统的登录账号), sn 姓(一般可设置与cn相同) , ou 组织单元(可配置为部门),dn (全路径名称,如 cn=wjy,ou=users,dc=example,dc.org)

对象属性: 最终用户可以是 objectclass: inetOrgPerson , objectclass: posixAccount objectclass: top ,然后加上 cn ,sn , uid(非必须) ,uidnumber, gidnumber, userpassword , homedirectory ,homephone,mail
组用户 :objectclass: posixGroup , objectclass: top , 加上必须的cn , gidnumber , 组成员 memberuid:

搭建

用docker-compose 最简单,少了编译、配置,可以快速部署用于测试使用。当然生产还是要详细了解相关配置项
https://github.com/osixia/docker-openldap/blob/master/example/docker-compose.yml
此模板使用了openldap + phpadmin .可以快速建立web管理界面的ldap

我这里的搭建架构示例如上图。根目录是公司层,cn=java-dev 是组(也是部门),下面uid是用户,readonly是第三方应用接入的只读查询账号,这样可以最小化权限给到第三方

grafana 接入

首先在 grafana.ini 配置文件的

[auth.ldap]
enabled = true

再在ldap.toml中配置

[[servers]]
host = "192.168.0.14"
port = 389
bind_dn = "cn=readonly,dc=ywsco,dc=cn"
bind_password = '***'
search_filter = "(uid=%s)"   #这里也可以用cn
search_base_dns = ["dc=ywsco,dc=cn"]
group_search_filter = "(&(objectClass=posixGroup)(memberUid=%s))"
group_search_base_dns = ["dc=ywsco,dc=cn"]
group_search_filter_user_attribute = "uid"
[servers.attributes]
name = "givenName"
surname = "sn"
username = "uid"
member_of = "memberOf"
email = "mail"
[[servers.group_mappings]]
group_dn = "cn=tech-support,dc=ywsco,dc=cn"
org_role = "Admin"
grafana_admin = true
org_id = 1 
[[servers.group_mappings]]
group_dn = "cn=java-dev,dc=ywsco,dc=cn"
org_role = "Editor"
[[servers.group_mappings]]
group_dn = "*"
org_role = "Viewer"

zabbix监控

zabbix大版本6.4 ,agent直接装agent2,功能更强大。

1、redis监控

用官方template “Redis by Zabbix agent 2″即可监控

无密码redis无需其他配置,主机链接官方模板即可

redis 带密码的情况,需要在被监控redis的agent2配置文件增加如下两行,然后主机添加macros : {$REDIS.CONN.URI} Redis1即可监控

Plugins.Redis.Sessions.Redis1.Uri=tcp://127.0.0.1:6379
Plugins.Redis.Sessions.Redis1.Password=123456

odps表格创建操作

一个语句,创建和源表格式相同并且带字段注释的表格方法:create table [if not exists] <table_name> like <existing_table_name> [lifecycle <days>];

而这个语句create table [if not exists] <table_name> as <select_statement>; 会创建一个新表,但是不会将源表的元数据复制到新表中.元数据包括列名、列类型、列注释、分区等信息。因此,使用这种方式创建的新表只会继承源表的列名和列类型,而不会继承源表的列注释。但是他会把源表所有数据插入新的表格

示例:

CREATE TABLE IF NOT EXISTS table_name LIKE a.table_name;  

create table if not exists table_name as select * from a.table_name;

K8S部署文件的模板化

提前编写通用模板,和初始化python脚本,不同的部署包只需定义相应的变量文件就可以生成部署yaml文件,示例如下:

# 模板文件,保存为deployment.yml.j2
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ name }}
  namespace: {{ namespace }}
spec:
  replicas: {{ replicas }}
  selector:
    matchLabels:
      app: {{ name }}
  template:
    metadata:
      labels:
        app: {{ name }}
    spec:
      containers:
      - name: {{ name }}
        image: {{ image }}
        ports:
        - containerPort: {{ port }}
---
apiVersion: v1
kind: Service
metadata:
  name: {{ name }}-svc
  namespace: {{ namespace }}
spec:
  selector:
    app: {{ name }}
  type: NodePort
  ports:
  - protocol: TCP
    port: {{ port }}


# 配置文件,保存为variables.yml
name: myapp
namespace: default
replicas: 1
image: myapp:latest
port: 8080


# python 脚本createDep.py,最终生成部署文件 deployment_{appname}.yaml
# python2.7 安装yaml包 pip install pyyaml
from jinja2 import Environment, FileSystemLoader
import yaml

env = Environment(loader=FileSystemLoader('.'))
template = env.get_template('deployment.yml.j2')
variables = yaml.safe_load(open('variables.yml'))

output = template.render(variables)
output_file = "deployment_" + variables["name"] + ".yaml"
with open(output_file, 'w') as f:
    f.write(output)

K8S踩坑集锦

1 节点arp缓存满

现象:通过coreDns解析域名,时而解析成功,时而解析超时;系统日志报错如下

arp_cache: neighbor table overflow!

解决办法

调整内核参数,将阈值调高

$ sysctl -a | grep net.ipv4.neigh.default.gc_thresh
net.ipv4.neigh.default.gc_thresh1 = 80000
net.ipv4.neigh.default.gc_thresh2 = 90000
net.ipv4.neigh.default.gc_thresh3 = 100000

注意:如果coreDns没有通过nodeSelector指定coreDns的pod调度到指定标签的节点上,就需要全部节点都要修改上文的内核参数;由于coreDns是非常重要的组件,还是建议通过nodeSelector将coreDns的pod调度到特定机器,并修改特定机器的内核参数,防止其他服务影响。

linux的iptables nat利用

场景说明:

A: 172.45.255.14:3389 要访问的目标windows主机
B: 172.45.255.11 linux代理
C: 172.45.211.22 客户机
B对C的访问没有限制,A和B在同一个网段可以互访,C无法直接访问A的远程桌面

决方案:

##在B上面操作
iptables -t nat -A PREROUTING -p tcp --dport 53388 -j DNAT --to 172.45.255.14:3389
iptables -t nat -A POSTROUTING -p tcp -d 172.45.255.14 --dport 3389 -j SNAT --to 172.45.255.11
sysctl -w net.ipv4.ip_forward=1

结果:

C可以通过B的53388端口访问A的远程桌面

其他扩展:

命令加错删除:

iptables -t nat -L PREROUTING num   #查看nat表中PREROUTING第几条num
iptables -t nat -D PREROUTING num   #删除第几条num

iptables -t nat -L POSTROUTING num   #查看nat表中POSTROUTING第几条num
iptables -t nat -D POSTROUTING num   #删除第几条num

Snat配置:

## X服务器有内外和公网两张网卡,两个IP,以下配置在X机器上面操作
iptables -t nat -I POSTROUTING -s 192.68.10.1/24 -j SNAT --to-source 211.136.11.11
#其中 192.168.10.0/24为内外IP段,211.136.11.11为X的公网IP,
#内网段的服务器需要配置默认路由指向X服务器的内外IP

Nginx的location匹配规则解析

情况1:

proxy_pass  http://IPaddr/    #删除匹配段,一般配置接口使用

访问 http://域名/abc/test.map 分下面两种情况
1)location /abc/
会转发到 http://IPaddr/test.map
2) location /abc
会转发成 http://IPaddr//test.map —————-linux //路径=/路径
所以也等价于 http://IPaddr/test.map 的访问

情况2:

proxy_pass  http://IPaddr    #匹配段和此地址段拼接

这个也分两种情况
1) location /abc
这种可以匹配 /abc 和 /abc/
2)location /abc/
这种只能匹配 /abc/ 匹配目录

容器中的JVM资源该如何被安全的限制

前言

Java与Docker的结合,虽然更好的解决了application的封装问题。但也存在着不兼容,比如Java并不能自动的发现Docker设置的内存限制,CPU限制。

这将导致JVM不能稳定服务业务!容器会杀死你JVM进程,而健康检查又将拉起你的JVM进程,进而导致你监控你的pod一天重启次数甚至能达到几百次。

我们希望当Java进程运行在容器中时,java能够自动识别到容器限制,获取到正确的内存和CPU信息,而不用每次都需要在kubernetes的yaml描述文件中显示的配置完容器,还需要配置JVM参数。

使用JVM MaxRAM参数或者解锁实验特性的JVM参数,升级JDK到10+,我们可以解决这个问题(也许吧~.~)。

首先Docker容器本质是是宿主机上的一个进程,它与宿主机共享一个/proc目录,也就是说我们在容器内看到的/proc/meminfo/proc/cpuinfo
与直接在宿主机上看到的一致,如下。

  • Hostcat /proc/meminfo MemTotal: 197869260 kB MemFree: 3698100 kB MemAvailable: 62230260 kB
  • 容器docker run -it --rm alpine cat /proc/meminfo MemTotal: 197869260 kB MemFree: 3677800 kB MemAvailable: 62210088 kB

那么Java是如何获取到Host的内存信息的呢?没错就是通过/proc/meminfo来获取到的。

默认情况下,JVM的Max Heap Size是系统内存的1/4,假如我们系统是8G,那么JVM将的默认Heap≈2G。

Docker通过CGroups完成的是对内存的限制,而/proc目录是已只读形式挂载到容器中的,由于默认情况下Java
压根就看不见CGroups的限制的内存大小,而默认使用/proc/meminfo中的信息作为内存信息进行启动,
这种不兼容情况会导致,如果容器分配的内存小于JVM的内存,JVM进程会被理解杀死。

内存限制不兼容

我们首先来看一组测试,这里我们采用一台内存为188G的物理机。

#free -g
              total        used        free      shared  buff/cache   available
Mem:            188         122           1           0          64          64

以下的测试中,我们将包含openjdk的hotspot虚拟机,IBM的openj9虚拟机。

以下测试中,我们把正确识别到限制的jdk,称之为安全(即不会超出容器限制不会被kill),反之称之为危险。

测试用例1(OPENJDK)

这一组测试我们使用最新的openjdk8-12,给容器限制内存为4G,看JDK默认参数下的最大堆为多少?看看我们默认参数下多少版本的JDK是安全的

  • 命令如下,如果你也想试试看,可以用一下命令。
   docker run -m 4GB  --rm  openjdk:8-jre-slim java  -XshowSettings:vm  -version
   docker run -m 4GB --rm  openjdk:9-jre-slim java  -XshowSettings:vm  -version
   docker run -m 4GB --rm  openjdk:10-jre-slim java -XshowSettings:vm  -version
   docker run -m 4GB --rm  openjdk:11-jre-slim java -XshowSettings:vm  -version
   docker run -m 4GB --rm  openjdk:12 java -XshowSettings:vm  -version
  • OpenJDK8(并没有识别容器限制,26.67G) 危险
[root@xiaoke-test ~]# docker run -m 4GB --rm  openjdk:8-jre-slim java  -XshowSettings:vm  -version

VM settings:
    Max. Heap Size (Estimated): 26.67G
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "1.8.0_181"
OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-2~deb9u1-b13)
OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
  • OpenJDK8 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap (正确的识别容器限制,910.50M)安全
[root@xiaoke-test ~]# docker run -m 4GB --rm  openjdk:8-jre-slim java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm  -version
VM settings:
    Max. Heap Size (Estimated): 910.50M
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "1.8.0_181"
OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-2~deb9u1-b13)
OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
  • OpenJDK 9(并没有识别容器限制,26.67G)危险
[root@xiaoke-test ~]# docker run -m 4GB --rm  openjdk:9-jre-slim java  -XshowSettings:vm  -version
VM settings:
    Max. Heap Size (Estimated): 29.97G
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "9.0.4"
OpenJDK Runtime Environment (build 9.0.4+12-Debian-4)
OpenJDK 64-Bit Server VM (build 9.0.4+12-Debian-4, mixed mode)
  • OpenJDK 9 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap (正确的识别容器限制,1G)安全
[root@xiaoke-test ~]# docker run -m 4GB --rm  openjdk:9-jre-slim java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm  -version
VM settings:
    Max. Heap Size (Estimated): 1.00G
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "9.0.4"
OpenJDK Runtime Environment (build 9.0.4+12-Debian-4)
OpenJDK 64-Bit Server VM (build 9.0.4+12-Debian-4, mixed mode)
  • OpenJDK 10(正确的识别容器限制,1G)安全
[root@xiaoke-test ~]# docker run -m 32GB --rm  openjdk:10-jre-slim java -XshowSettings:vm -XX:MaxRAMFraction=1  -version
VM settings:
    Max. Heap Size (Estimated): 1.00G
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "10.0.2" 2018-07-17
OpenJDK Runtime Environment (build 10.0.2+13-Debian-2)
OpenJDK 64-Bit Server VM (build 10.0.2+13-Debian-2, mixed mode)
  • OpenJDK 11(正确的识别容器限制,1G)安全
[root@xiaoke-test ~]# docker run -m 4GB --rm  openjdk:11-jre-slim java -XshowSettings:vm  -version
VM settings:
    Max. Heap Size (Estimated): 1.00G
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment (build 11.0.1+13-Debian-3)
OpenJDK 64-Bit Server VM (build 11.0.1+13-Debian-3, mixed mode, sharing)
  • OpenJDK 12(正确的识别容器限制,1G)安全
[root@xiaoke-test ~]# docker run -m 4GB --rm  openjdk:12 java -XshowSettings:vm  -version
VM settings:
    Max. Heap Size (Estimated): 1.00G
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "12-ea" 2019-03-19
OpenJDK Runtime Environment (build 12-ea+23)
OpenJDK 64-Bit Server VM (build 12-ea+23, mixed mode, sharing)

测试用例2(IBMOPENJ9)

docker run -m 4GB --rm  adoptopenjdk/openjdk8-openj9:alpine-slim  java -XshowSettings:vm  -version
docker run -m 4GB --rm  adoptopenjdk/openjdk9-openj9:alpine-slim  java -XshowSettings:vm  -version
docker run -m 4GB --rm  adoptopenjdk/openjdk10-openj9:alpine-slim  java -XshowSettings:vm  -version
docker run -m 4GB --rm  adoptopenjdk/openjdk11-openj9:alpine-slim  java -XshowSettings:vm  -version
  • openjdk8-openj9 (正确的识别容器限制,3G)安全
    [root@xiaoke-test ~]# docker run -m 4GB --rm  adoptopenjdk/openjdk8-openj9:alpine-slim  java -XshowSettings:vm  -version
    VM settings:
        Max. Heap Size (Estimated): 3.00G
        Ergonomics Machine Class: server
        Using VM: Eclipse OpenJ9 VM
    
    openjdk version "1.8.0_192"
    OpenJDK Runtime Environment (build 1.8.0_192-b12_openj9)
    Eclipse OpenJ9 VM (build openj9-0.11.0, JRE 1.8.0 Linux amd64-64-Bit Compressed References 20181107_95 (JIT enabled, AOT enabled)
    OpenJ9   - 090ff9dcd
    OMR      - ea548a66
    JCL      - b5a3affe73 based on jdk8u192-b12)
  • openjdk9-openj9 (正确的识别容器限制,3G)安全
    [root@xiaoke-test ~]# docker run -m 4GB --rm  adoptopenjdk/openjdk9-openj9:alpine-slim  java -XshowSettings:vm  -version
    VM settings:
        Max. Heap Size (Estimated): 3.00G
        Using VM: Eclipse OpenJ9 VM
    
    openjdk version "9.0.4-adoptopenjdk"
    OpenJDK Runtime Environment (build 9.0.4-adoptopenjdk+12)
    Eclipse OpenJ9 VM (build openj9-0.9.0, JRE 9 Linux amd64-64-Bit Compressed References 20180814_248 (JIT enabled, AOT enabled)
    OpenJ9   - 24e53631
    OMR      - fad6bf6e
    JCL      - feec4d2ae based on jdk-9.0.4+12)
  • openjdk10-openj9 (正确的识别容器限制,3G)安全
    [root@xiaoke-test ~]# docker run -m 4GB --rm  adoptopenjdk/openjdk10-openj9:alpine-slim  java -XshowSettings:vm  -version
    VM settings:
        Max. Heap Size (Estimated): 3.00G
        Using VM: Eclipse OpenJ9 VM
    
    openjdk version "10.0.2-adoptopenjdk" 2018-07-17
    OpenJDK Runtime Environment (build 10.0.2-adoptopenjdk+13)
    Eclipse OpenJ9 VM (build openj9-0.9.0, JRE 10 Linux amd64-64-Bit Compressed References 20180813_102 (JIT enabled, AOT enabled)
    OpenJ9   - 24e53631
    OMR      - fad6bf6e
    JCL      - 7db90eda56 based on jdk-10.0.2+13)
  • openjdk11-openj9(正确的识别容器限制,3G)安全
    [root@xiaoke-test ~]# docker run -m 4GB --rm  adoptopenjdk/openjdk11-openj9:alpine-slim  java -XshowSettings:vm  -version
    VM settings:
        Max. Heap Size (Estimated): 3.00G
        Using VM: Eclipse OpenJ9 VM
    
    openjdk version "11.0.1" 2018-10-16
    OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.1+13)
    Eclipse OpenJ9 VM AdoptOpenJDK (build openj9-0.11.0, JRE 11 Linux amd64-64-Bit Compressed References 20181020_70 (JIT enabled, AOT enabled)
    OpenJ9   - 090ff9dc
    OMR      - ea548a66
    JCL      - f62696f378 based on jdk-11.0.1+13)

分析

分析之前我们先了解这么一个情况:

JavaMemory (MaxRAM) = 元数据+线程+代码缓存+OffHeap+Heap...

一般我们都只配置Heap即使用-Xmx来指定JVM可使用的最大堆。而JVM默认会使用它获取到的最大内存的1/4作为堆的原因也是如此。

安全性(即不会超过容器限制被容器kill)

OpenJdk

OpenJdk8-12,都能保证这个安全性的特点(8和9需要特殊参数,-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap)。

OpenJ9

IbmOpenJ9所有的版本都能识别到容器限制。

资源利用率

OpenJdk

自动识别到容器限制后,OpenJdk把最大堆设置为了大概容器内存的1/4,对内存的浪费不可谓不大。

当然可以配合另一个JVM参数来配置最大堆。-XX:MaxRAMFraction=int。下面是我整理的一个常见内存设置的表格,
从中我们可以看到似乎JVM默认的最大堆的取值为MaxRAMFraction=4,随着内存的增加,堆的闲置空间越来越大,在16G容器内存时,java堆只有不到4G。

MaxRAMFraction取值堆占比容器内存=1G容器内存=2G容器内存=4G容器内存=8G容器内存=16G
1≈90%910.50M1.78G3.56G7.11G14.22G
2≈50%455.50M910.50M1.78G3.56G7.11G
3≈33%304.00M608.00M1.19G2.37G4.74G
4≈25%228.00M455.50M910.50M1.78G3.56G

OpenJ9

关于OpenJ9的的详细介绍你可以从这里了解更多
对于内存利用率OpenJ9的策略是优于OpenJdk的。以下是OpenJ9的策略表格

容器内存<size>最大Java堆大小
小于1 GB50%<size>
1 GB – 2 GB<size>– 512 MB
大于2 GB大于2 GB

结论

  • 注意:这里我们说的是容器内存限制,和物理机内存不同,

自动档

  • 如果你想要的是,不显示的指定-Xmx,让Java进程自动的发现容器限制。

1.如果你想要的是jvm进程在容器中安全稳定的运行,不被容器kiil,并且你的JDK版本小于10(大于等于JDK10的版本不需要设置,参考前面的测试)
你需要额外设置JVM参数-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap,即可保证你的Java进程不会因为内存问题被容器Kill。
当然这个方式使用起来简单,可靠,缺点也很明显,资源利用率过低(参考前面的表格MaxRAMFraction=4)。

2.如果想在基础上我还想提高一些内存资源利用率,并且容器内存为1 GB – 4 GB,我建议你设置-XX:MaxRAMFraction=2,在大于8G的可以尝试设置-XX:MaxRAMFraction=1(参考上表格)。

手动挡

  • 如果你想要的是手动挡的体验,更加进一步的利用内存资源,那么你可能需要回到手动配置时代-Xmx。
  • 手动挡部分,请可以完全忽略上面我的BB。
    1.上面的我们说到了自动挡的配置,用起来很简单很舒服,自动发现容器限制,无需担心和思考去配置-Xmx。
    2.比如你有内存1G那么我建议你的-Xmx750M,2G建议配置-Xmx1700M,4G建议配置-Xmx3500-3700M,8G建议设置-Xmx7500-7600M,
    总之就是至少保留300M以上的内存留给JVM的其他内存。如果堆特别大,可以预留到1G甚至2G。
    3.手动挡用起来就没有那么舒服了,当然资源利用率相对而言就更高了。

a tiny but valid `init` for containers

tini

Using Tini has several benefits:

  • It protects you from software that accidentally creates zombie processes, which can (over time!) starve your entire system for PIDs (and make it unusable).
  • It ensures that the default signal handlers work for the software you run in your Docker image. For example, with Tini, SIGTERM properly terminates your process even if you didn’t explicitly install a signal handler for it.
  • It does so completely transparently! Docker images that work without Tini will work with Tini without any changes.

In Docker, you will want to use an entrypoint so you don’t have to remember to manually invoke Tini:

# Add Tini
ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]

# Run your program under Tini
CMD ["/your/program", "-and", "-its", "arguments"]
# or docker run your-image /your/program ...

find 之 prune

在查找某个目录的时候,如果要排除其中某个子目录可以用-path pathname -prune

例:查找根目录下24小时内修改过的文件,但是不要查询proc目录可用如下命令

find / -path /proc -prune -mtime -1 -type f
#排除多个目录
find / \( -path /proc -o -path /run \) -prune -mtime -1 -type f

例2:系统被病毒攻击,会产生很多可执行文件,如果发现被攻击时间是2天前

#全局查找命令如下
find / -mtime -3 -perm /111 -type -f 
#查找并显示详细信息
find / -mtime -3 -perm /111 -type -f -exec ls -la {} \;
#查找并删除文件
find / -mtime -3 -perm /111 -type -f -exec rm -f {} \;
#查找并删除文件 xargs
find / -mtime -3 -perm /111 -type -f  | xargs rm -f