SSH的安全设置

前言

在阿里云部署了一台虚拟主机,安装了zabbix,主要用于监控用户WIFI系统,平常很少登录;今天登录查看某些配置时,系统提示如下:

未分类

竟然有840次试图登录系统,真是有些担忧,需要马上加强安全。

安全加固

Linux中sshd服务的验证方式一般有2种:密码和密钥认证,平时用的最多的就是密码认证,这台zabbix的云主机就是使用密码认证,并且允许root直接远程登录;这台云机只有本人在访问,可以随意设置。

此次加固的方法:
禁用root用户远程登录,使用普通用户登录
修改为密钥认证

既然要修改为密钥登录,肯定需要一对密钥了,先介绍一下使用x-shell如何生成密钥对

生成密钥对

启动x-shell程序,tools->User Key Manager

未分类

未分类

未分类

未分类

未分类

未分类

未分类

这样密钥对生成完毕,等会需要将生成的公钥信息复制粘贴到用户的家目录内.ssh/authorized_keys文件内。

创建普通用户及授权文件

# 创建用户   
useradd yxq

# 设置账号密码 
passwd yxq

# su到普通用户yxq
su - yxq

# 用户家目录下创建.ssh目录
mkdir .ssh

# 创建授权文件并将生成的公钥信息复制到文件内
vim .ssh/authorized_keys 

sh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuTNmA/jofPrDhbChITDHpaWlt6UeD/rA/xzIckwOXdBCFDow87XsTnRtUeFZkQyH4PXgWfkSbEA7OKDvIRi0OfIUgGDf1ST1hUQRaEKnN1peKCCOZN0F6p3l6dyQHZ8BMtofmnWNRznOm/VO4I/h85LX6PPJJNxLXphyQKZIGaF4kuV6etgAMS5sqLfxfythJ6DFR4NQoxWbzYXgH+GKljvJ+8b/+SUNx07j5Lmbn0Q6CPX7Mrm7w2yKU26KfpR5yb476VZRMEpm6+UdBQ4G6pBk5rXhJ+iZ4oKPDxseydkIZZvtKO4z2uMbUcnfnd+NfSMPg1dZkwIpoI9Gy3mU/Q==

修改SSH服务的配置

修改配置文件/etc/ssh/sshd_config

vim /etc/ssh/sshd_config      
# 禁用root用户远程登录         
PermitRootLogin no   

# 禁用密码认证      
PasswordAuthentication no   

# 启用密钥认证   
PubkeyAuthentication yes   

# 密钥文件及文件路径      
AuthorizedKeysFile      .ssh/authorized_keys   

重启sshd服务

systemctl restart sshd.service   

测试

使用root登录测试

未分类

可以看到password位置是灰色的,即时将公钥也复制到root家目录下的授权文件内也是无法登录的,因为设置了root不允许远程ssh连接登录

使用yxq用户测试

未分类

在User Key的下拉菜单选择ali-yxq,点ok

未分类

提示登录成功。

解决ssh登陆过慢问题

我们经常会遇到的一个情况是telnet到server速度很快,但是ssh连接的时候却很慢,大概
要等半分钟甚至更久。ping的速度也非常好,让人误以为是ssh连接不上。
 
下面说下如何解决这样的问题,最为常见的原因是因为server的sshd会去DNS查找访问
client IP的hostname,如果DNS不可用或者没有相关记录,就会耗费大量时间。
 
1、在server上/etc/hosts文件中把你本机的ip和hostname加入
 
2、在server上/etc/ssh/sshd_config文件中修改或加入UseDNS=no,另外在authentication gssapi-with-mic也有可能出现问题,在server上/etc/ssh/sshd_config文件中修改GSSAPIAuthentication no.

3、修改server上/etc/nsswitch.conf中hosts为hosts: files //这个会导致服务器无法访问外网

4、reboot server使配置生效

/etc/init.d/sshd restart重启sshd进程使配置生效。

SaltStack 使用总结

SaltStack是一个开源的、新的基础平台管理工具,使用Python语言开发,同时提供Rest API方便二次开发以及和其他运维管理系统进行集成。相对于出道比较早的Puppet,SaltStack先天的优势就是简单、易用,可以非常快速的在团队中推广和使用,而且运行多平台。

SaltStack目前拥有四大主要功能

  • 远程执行:就是在管理节点上实现在上百台、上千台机器上同时执行一个命令。
  • 配置管理:也可以称之为状态管理,你可以描述一个状态。例如,某台机器要安装Nginx软件包、Nginx必须是启动的状态、Nginx有一个配置文件(内容和某个地方的一样)。你用一种描述语法描述出来后交给SaltStack,SaltStack就可以帮你实现,而不用你手动进行Nginx软件包的安装、配置文件的修改、启动等。
  • 云管理:SaltStack有一个组件叫作salt-cloud,它可以帮你自动化的进行云主机的创建和管理,支持很多公有云或私有云,例如AWS、阿里云、HP云、OpenStack、CloudStack等。
  • 事件驱动:事件驱动基础设施是SaltStack最强大也是最神秘的功能,前面的远程执行和配置管理是最基础的的,事件驱动是指SaltStack在日常运行中可以产生和捕捉事件,并根据捕捉到的事件触发对应的操作。

SaltStack的四种运行方式

  • Local:在本地运行或者说单台使用SaltStack
  • Minion/Master: 传统的客户端/服务器端(C/S)架构
  • Syndic: 使用代理实现架构扩展,用于管理更多的节点
  • Salt SSH: 无须安装客户端,直接通过SSH通信

目标机器匹配方法

SaltStack有以下几种方式来选择目标机器,灵活而又强大。大的来讲分为两大类:

1. 基于Minion ID

Minion ID是客户端(minion)的唯一标识符。可以在minion配置文件里面使用ID选项进行配置,如果不指定,其默认是主机的FQDN名。Minion ID是不能变动的,因为在进行key认证的时候,生成的文件名是以Minion ID命名的。如果Minion发生变动,就需要使用salt-key -d删除老的Minion ID,然后重新加入新的Minion ID。

  • Globbing(通配符)
  • regex(正则表达式)
  • list(列表)

2. 不基于Minion ID

  • 子网/IP地址
  • Grains
  • Grains PCRE
  • Pillar
  • Compound matchers(复合匹配)
  • Node groups(节点组)
  • Batching execution(批处理执行)

演示

指定Minion ID是最直接的选择目标的方法

查看所有minion节点

[root@salt ~]# salt-key  -L
Accepted Keys:
Denied Keys:
Unaccepted Keys:
128.docker.itnotebooks.com
Rejected Keys:

授权minion节点

可以修改/etc/salt/master的配置auto_accept:True自动认证

[root@salt ~]# salt-key -a 128.docker.itnotebooks.com
The following keys are going to be accepted:
Unaccepted Keys:
128.docker.itnotebooks.com
Proceed? [n/Y] y
Key for minion 128.docker.itnotebooks.com accepted.
  • salt-key -L: 显示已经或未认证的minion节点,Accepted Keys为已认证清单
  • salt-key -D: 删除所有Minion节点的证书
  • salt-key -d id: 删除单个minion节点的证书
  • salt-key -A: 接受所有minion节点的请求
  • salt-key -a id: 接受单个minion节点的请求

Globbing是指在Minion ID的基础上,通过通配符来定位Minion。SaltStack默认使用Shell风格通配符(如“” “?” “[]”)来匹配Minion ID。不过需要注意的是,使用salt命令时必须将’’放在单引号中,或是用’’转义,用来避免shell解析。

匹配所有itnotebooks.com域的所有minion

[root@salt ~]# salt '*.itnotebooks.com' test.ping

匹配docker后面单个任意字符的Minion

[root@salt ~]# salt 'docker?.itnotebooks.com' test.ping

匹配docker节点1到节点3的Minion

[root@salt ~]# salt 'docker[1-3].itnotebooks.com' test.ping

匹配docker不是节点1和节点3的Minion

[root@salt ~]# salt 'docker[!13].itnotebooks.com' test.ping

list和直接Minion ID都是最基本的模式,可以列出每一个Minion ID来指定多个目标机器,使用选项’-L’

[root@salt ~]# salt -L 'docker1.itnotebooks.com,docker2.itnotebooks.com' test.ping

Salt可以使用Perl风格的正则表达式来匹配Minion ID,使用选项-E

[root@salt ~]# salt -E 'linux-(node1|node2)*' test.ping

规范的Minion ID可以很好的反映出该服务器运行的相关服务及所在位置

redis-node1-redis03-idc04-soa.itnotebooks.com
  • redis-node1:运行的服务是Redis,这是第一个节点
  • redis03:说明这个redis是Redis集群编号03里面的节点
  • idc04:这台服务器运行在编号04的IDC机房中
  • soa:这台服务器是给SOA服务使用的
  • itnotebooks.com:运行的服务器是itnotebooks.com业务

也可以使用IP地址或CIDR子网来指定目标,目前仅支持IPv4的地址

[root@salt ~]# salt -S '192.168.18.33' test.ping
[root@salt ~]# salt -S '192.168.18.0/24' test.ping

也可以使用Grains对Trageting进行匹配,使用选项’-G’

匹配所有CentOS系统的Minion

[root@salt ~]# salt -G 'os:CentOS' test.ping

通过Grain匹配非常灵活,如果你想进行更复杂的基于Grains的匹配,SaltStack提供了Grain PCRE,可以在Grains的基础上使用正则表达式

[root@salt ~]# salt --grain-pcre 'os_family:Red(Hat|Flag)' test.ping

Pillar的数据可以用来定位Minion,为定位Minions提供了灵活性和终极控制

[root@salt ~]# salt -I 'apache:httpd' test.ping

Compound matchers(混合匹配)可以使用布尔操作符连接多个目标条件。混合匹配可以用前面讨论的多种方式实现精确的匹配。混合配匹配默认使用Globbing,如果要使用其它匹配方式,需要加上类型前缀字母如下表所示。

未分类

复合匹配中也可以使用and、or、not操作符,例如要匹配主机名以及webserv开始且运行Debain系统的Minion,还能匹配主机名满足正则表达式web-dc1-srv.*的Minion

[root@salt ~]# salt -C 'webserv* and G@os:Debian or E@web-dc1-srv.*' test.ping
  • G表示用shell通配符匹配Grains
  • E表示用正则表达式匹配Minion ID

需要注意的是not不能用于第一个条件,需要用时可以像下面这样写:

[root@salt ~]# salt -C '* and not G@kernel:Darwin' test.ping

Node group是在Master中nodegroup用复合条件字义的一组Minion

[root@salt ~]# vim /etc/salt/master
nodegroups:
  group1: '[email protected],linux-node2.itnotebooks.com'
[root@salt ~]# systemctl restart salt-master
[root@salt ~]# salt -N group1 test.ping
linux-node2.itnotebooks.com
    True
linux-node1.itnotebooks.com
    True

远程执行命令-查看内存使用

[root@salt ~]# salt 'linux-node1.itnotebooks.com' cmd.run 'free -m'
              total        used        free      shared  buff/cache   available
Mem:           1838         749         119           0         969         887
Swap:             0           0           0

远程执行命令-查看操作系统类型

[root@salt ~]# salt 'linux-node1.itnotebooks.com' grains.item osfullname
linux-node1.itnotebooks.com:
  osfullname: CentOS

远程执行命令-查看指定发行版本号为6.4的主机的python版本

[root@salt ~]# salt -G 'osrelease:6.4' cmd.run 'python -V'
linux-node1.itnotebooks.com:
  Python 2.6.6

远程执行命令-解压文件

[root@salt ~]# salt 'linux-node1.itnotebooks.com' archive.gunzip /tmp/jdk-8.1.0.gz

远程执行命令-压缩文件

[root@salt ~]# salt 'linux-node1.itnotebooks.com' archive.gzip /tmp/test.txt

除了上面所提到的外,其它类似的模块还有很多很多
如cp、cron、file、iptables、network、dnsuti、service、pkg等等,详细的自己用过就知道了,当然你也可以在cmd.run里面去完成这一切

saltstack的jinja模

[root@master ~]# cd /srv/salt/base/
[root@master base]# ll
总用量 12
-rw-r--r-- 1 root root 172 11月 14 21:26 apache.sls
-rw-r--r-- 1 root root 128 11月 16 00:12 dns.sls
drwxr-xr-x 2 root root  25 11月 16 00:23 files
-rw-r--r-- 1 root root  28 11月 16 00:22 top.sls
[root@master base]# vim dns.sls 
[root@master base]# cat dns.sls 
/etc/resolv.conf:
  file.managed:
     - source: salt://files/resolv.conf
     - user: root
     - group: root
     - mode: 777
     - template: jinja
     - defaults:    #定义变量
       DNS_SERVER: 192.168.43.118

[root@master base]# vim files/resolv.conf 
[root@master base]# cat files/resolv.conf
#jjjjjjjjjjjjjjjjjj
nameserver {{ DNS_SERVER }}   #2个大括号表示变量

[root@master base]# salt '*'  state.highstate
192.168.43.118:
----------
          ID: /etc/resolv.conf
    Function: file.managed
      Result: True
     Comment: File /etc/resolv.conf updated
     Started: 00:43:27.222821
    Duration: 21.809 ms
     Changes:   
              ----------
              diff:
                  --- 
                  +++ 
                  @@ -1,2 +1,3 @@
                   #jjjjjjjjjjjjjjjjjj
                  -nameserver 192.168.43.1
                  +nameserver 192.168.43.118
                  +

Summary
------------
Succeeded: 1 (changed=1)
Failed:    0

[root@master base]# vim files/resolv.conf 
[root@master base]# cat files/resolv.conf
#jjjjjjjjjjjjjjjjjj
#  {{ grains['fqdn_ip4'] }}
nameserver {{ DNS_SERVER }}
[root@master base]# salt '*'  state.highstate
192.168.43.118:
----------
          ID: /etc/resolv.conf
    Function: file.managed
      Result: True
     Comment: File /etc/resolv.conf updated
     Started: 00:47:03.799795
    Duration: 32.514 ms
     Changes:   
              ----------
              diff:
                  --- 
                  +++ 
                  @@ -1,3 +1,3 @@
                   #jjjjjjjjjjjjjjjjjj
                  +#  ['192.168.43.118']
                   nameserver 192.168.43.118
                  -

Summary
------------
Succeeded: 1 (changed=1)
Failed:    0

系统初始化配置:

[root@master base]# pwd
/srv/salt/base
[root@master base]# mkdir init
[root@master base]# mv apache.sls dns.sls files/ /tmp/
[root@master base]# tree
.
├── init
└── top.sls

1 directory, 1 file

[root@master base]# cp /tmp/dns.sls init/
[root@master base]# ll
总用量 4
drwxr-xr-x 2 root root 21 11月 16 00:55 init
-rw-r--r-- 1 root root 28 11月 16 00:22 top.sls
[root@master base]# cd init/
[root@master init]# ls
dns.sls

[root@master init]# vim dns.sls 
[root@master init]# cat dns.sls
/etc/resolv.conf:
  file.managed:
     - source: salt://init/files/resolv.conf
     - user: root
     - group: root
     - mode: 777

[root@master init]# mkdir files
[root@master init]# cp /etc/resolv.conf files/
[root@master init]# cp /etc/resolv.conf files/
[root@master init]# vim history.sls
[root@master init]# cat history.sls
/etc/profile:
  file.append:  #file模块的追加方法
    - text:
      - export HISTTIMEFORMAT="%F %T 'whoami'"

[root@master init]# export  PROMPT_COMMAND=' { msg=$(history 1 | { read x y; echo $y; });logger "[euid=$(whoami)]":$(who am i):['pwd']"$msg";} '
[root@master init]# who
root     pts/0        2018-11-16 00:29 (desktop-4a0ohej)
root     pts/1        2018-11-16 00:38 (desktop-4a0ohej)
[root@master init]# tail -f /var/log/messages
Nov 16 01:01:01 master systemd: Starting Session 34 of user root.
Nov 16 01:10:01 master systemd: Started Session 35 of user root.
Nov 16 01:10:01 master systemd: Starting Session 35 of user root.
Nov 16 01:14:00 master root: [euid=root]:root pts/0 2018-11-16 00:29 (desktop-4a0ohej):[pwd]export PROMPT_COMMAND=' { msg=$(history 1 | { read x y; echo $y; });logger "[euid=$(whoami)]":$(who am i):['pwd']"$msg";} '
Nov 16 01:14:04 master root: [euid=root]:root pts/0 2018-11-16 00:29 (desktop-4a0ohej):[pwd]uptime
Nov 16 01:14:39 master root: [euid=root]:root pts/0 2018-11-16 00:29 (desktop-4a0ohej):[pwd]tail -f /var/log/messages
Nov 16 01:14:42 master root: [euid=root]:root pts/0 2018-11-16 00:29 (desktop-4a0ohej):[pwd]uptime
Nov 16 01:15:06 master root: [euid=root]:root pts/0 2018-11-16 00:29 (desktop-4a0ohej):[pwd]tail -f /var/log/messages
Nov 16 01:15:12 master root: [euid=root]:root pts/0 2018-11-16 00:29 (desktop-4a0ohej):[pwd]tail -f /var/log/messages
Nov 16 01:15:17 master root: [euid=root]:root pts/0 2018-11-16 00:29 (desktop-4a0ohej):[pwd]who

[root@master init]# ll
总用量 12
-rw-r--r-- 1 root root 172 11月 16 01:17 audit.sls
-rw-r--r-- 1 root root 137 11月 16 00:57 dns.sls
drwxr-xr-x 2 root root  25 11月 16 00:58 files
-rw-r--r-- 1 root root  88 11月 16 01:03 history.sls
[root@master init]# cat audit.sls 
/etc/bashrc:
  file.append:
    - text:
      - export  PROMPT_COMMAND=' { msg=$(history 1 | { read x y; echo $y; });logger "[euid=$(whoami)]":$(who am i):['pwd']"$msg";} '

[root@master init]# cat sysctl.sls
vm.swappinese:   #尽量不适用swap分区
  sysctl.present:
    - value: 0

net.ipv4.ip_local_port_range:
  sysctl.present:
    - value: 10000 65000

fs.file-max:    #最大打开文件数
  sysctl.present:
    - value: 100000

[root@master init]# vim env_init.sls
[root@master init]# cat env_init.sls
include:
  - init.dns
  - init.history
  - init.audit
  - init.sysctl

[root@master init]# cd ..
[root@master base]# ls
init  top.sls
[root@master base]# vim top.sls 
[root@master base]# cat top.sls
base:
  '*':
    - init.env_init  #在base路径下去init目录找env_init文件并执行

[root@master base]# salt '*' state.highstate test=True  测试不执行
[root@master base]# salt '*' state.highstate

saltstack配置管理

状态模块:

https://docs.saltstack.com/en/latest/ref/states/all/salt.states.file.html#module-salt.states.file

[root@master ~]# grep -v '^$' /etc/salt/master |grep -v '#'
client_acl:
  luo:
    - test.ping
    - network.*
file_roots:     #top.sls路径,可以写多个
  base:         #但是只读取base路径
    - /srv/salt/base
  test:
    - /srv/salt/test
  prod:
    - /srv/salt/prod
pillar_roots:
  base:
    - /srv/pillar
mysql.host: '192.168.43.118'
mysql.user: 'salt'
mysql.pass: 'Myq1231!'
mysql.db: 'salt'
mysql.port: 3306

[root@master ~]# systemctl restart salt-master

[root@master ~]# mkdir /srv/salt/{base,test,prod}

[root@master salt]# ls
apache.sls  base  prod  test  top.sls
[root@master salt]# mv apache.sls top.sls base/

编写基本文件管理:

[root@master ~]# mkdir /srv/salt/base/files
[root@master base]# pwd
/srv/salt/base
[root@master base]# vim dns.sls
[root@master base]# cat dns.sls
/etc/resolv.conf:
  file.managed:     #file模块的managed方法
     - source: salt://files/resolv.conf  #路径,salt://=/srv/salt/base ,files新建的文件。
     - user: root   #用户
     - group: root  #用户组
     - mode: 777    #权限

[root@master base]# cp /etc/resolv.conf ./files/
[root@master base]# vim files/resolv.conf 
[root@master base]# cat files/resolv.conf
nameserver 192.168.43.1

[root@master base]# salt '*' state.sls dns   state状态模块的sls方法,dns为状态名,可以任意写。
192.168.43.118:
----------
          ID: /etc/resolv.conf
    Function: file.managed
      Result: True
     Comment: File /etc/resolv.conf updated
     Started: 00:18:45.928344
    Duration: 18.082 ms
     Changes:   
              ----------
              diff:
                  --- 
                  +++ 
                  @@ -1,3 +1 @@
                  -# Generated by NetworkManager
                  -search com
                   nameserver 192.168.43.1
              mode:
                  0777

Summary
------------
Succeeded: 1 (changed=1)

[root@master base]# pwd
/srv/salt/base
[root@master base]# vim top.sls 
[root@master base]# cat top.sls
base:
  '*':
    - dns

[root@master files]# pwd
/srv/salt/base/files
[root@master files]# vim resolv.conf 
[root@master files]# cat resolv.conf 
#jjjjjjjjjjjjjjjjjj
nameserver 192.168.43.1

[root@master base]# salt '*' state.sls dns  state状态模块的sls方法,dns为状态名,可以任意写。
192.168.43.118:
----------
          ID: /etc/resolv.conf
    Function: file.managed
      Result: True                
     Comment: File /etc/resolv.conf updated
     Started: 00:26:07.017848
    Duration: 24.144 ms
     Changes:   
              ----------
              diff:      
                  --- 
                  +++ 
                  @@ -1 +1,2 @@
                  +#jjjjjjjjjjjjjjjjjj
                   nameserver 192.168.43.1

Summary
------------
Succeeded: 1 (changed=1)
Failed:    0

[root@master base]# cat /etc/resolv.conf 
#jjjjjjjjjjjjjjjjjj
nameserver 192.168.43.1

这个Python资源在GitHub上标星超8000,现在被翻译成了中文

未分类

最近,GitHub上一个关于Python的工程完工了。

一个名为“暮晨”的贡献者,把一个非常有趣的Python项目,翻译成了中文版。

这个项目是《What the f*ck Python!》,专门介绍 Python 里面那些奇奇怪怪的语言坑。

未分类

关于项目

项目的主体构成部分就是示例,一共分为5个部分,分别是:

Strain your brain!/大脑运动!

未分类

Appearances are deceptive!/外表是靠不住的!

未分类

Watch out for the landmines!/小心地雷!

未分类

The Hidden treasures!/隐藏的宝藏!

未分类

Miscellaneous/杂项

未分类

以上,总计51个示例。

每一个示例的结构都是一样的,以“Mutating the immutable!/强人所难”为例:

首先,会给出代码:

some_tuple = ("A", "tuple", "with", "values")
another_tuple = ([1, 2], [3, 4], [5, 6])

然后,给出Output( Python version):

>>> some_tuple[2] = "change this"
TypeError: 'tuple' object does not support item assignment
>>> another_tuple[2].append(1000) # 这里不出现错误
>>> another_tuple
([1, 2], [3, 4], [5, 6, 1000])
>>> another_tuple[2] += [99, 999]
TypeError: 'tuple' object does not support item assignment
>>> another_tuple
([1, 2], [3, 4], [5, 6, 1000, 99, 999])

然后,对意外输出的结果进行简短的描述,在这个示例中,就是:

我还以为元组是不可变的呢…

接下来,就会对示例进行说明,简要叙述发生了什么以及为什么会发生。如有必要, 也会举例说明。

在这个示例中是这样的:

  • 引用 https://docs.python.org/2/reference/datamodel.html
不可变序列 不可变序列的对象一旦创建就不能再改变。(如果对象包含对其他对象的引用,则这些其他对象可能是可变的并且可能会被修改; 但是,由不可变对象直接引用的对象集合不能更改。)
  • += 操作符在原地修改了列表. 元素赋值操作并不工作, 但是当异常抛出时, 元素已经在原地被修改了。

有些地方,贡献者还会给出译注,比如整个示例中就是:

对于不可变对象, 这里指tuple, +=并不是原子操作, 而是extend和=两个动作, 这里=操作虽然会抛出异常, 但 extend 操作已经修改成功了。

其他还有50个示例,等你来看~

怎么使用?

当然,要学习一下怎么使用这个资源。项目贡献者在用法部分表示,最好依次阅读下面的示例。

然后,在阅读每一个示例的时候,这样做:

仔细阅读设置例子最开始的代码。阅读输出结果。确认结果是否如你所料。确认你是否知道这背后的原理。如果不知道, 深呼吸然后阅读说明 (如果你还是看不明白, 别沉默!可以提问题)。如果知道, 给自己点奖励, 然后去看下一个示例。

此外,还可以在命令行阅读 WTFpython,有 pypi 包 和 npm 包(支持代码高亮),不过都是英文版的。

关于作者

这个项目的原作者,是一个名为Satwik Kansal的印度小哥。

未分类

GitHub上的介绍称,在深度学习和去中心化应用方面是一个“老司机”。

目前,英文版资源,标星已经8.3k了。

未分类

传送门

中文版:

https://github.com/leisurelicht/wtfpython-cn

英文原版:

https://github.com/satwikkansal/wtfpython

— 完 —

python玩转街机游戏,操作亲民!

未分类

这是一个允许你在几乎任何街机游戏中训练你的强化学习算法的Python库,它目前在Linux系统上可用。通过这个工具包,你可以定制算法逐步完成游戏过程,同时接收每一帧的数据和内部存储器地址值以跟踪游戏状态,以及发送与游戏交互的动作。

安装

GitHub地址:github.com/M-J-Murray/MAMEToolkit/blob/master/README.md

你可以用pip安装这个库,只需运行以下命令:

pip install MAMEToolkit

演示:街霸

未分类

街霸是史上最经典的游戏之一。现在工具包内包含的街霸版本是街头霸王3:三度冲击(Japan 990608, NO CD),我们以此为例,用以下代码写一个随机智能体:

import random

from MAMEToolkit.sf_environment import Environment

roms_path = "roms/"

env = Environment("env1", roms_path)

env.start()

while True:

   move_action = random.randint(0, 8)

   attack_action = random.randint(0, 9)

   frames, reward, round_done, stage_done, game_done = env.step(move_action, attack_action)

   if game_done:

       env.new_game()

   elif stage_done:

       env.next_stage()

   elif round_done:

       env.next_round()

支持hogwild!

hogwild!? Niu等人引入了一个叫做 Hogwild! 的更新策略,可以使 SGD 可以在多 CPU 上并行更新。处理器在无需对参数加锁的情况下就可以访问共享内存。但仅在输入的是稀疏数据时才有效,因为每次更新仅修改所有参数的一小部分。他们展示了在这种情况下,更新策略几乎可以达到一个最优的收敛率,因为处理器不太可能覆盖掉有用的信息。

from threading import Thread

import random

from MAMEToolkit.sf_environment import Environment

def run_env(env):

   env.start()

   while True:

       move_action = random.randint(0, 8)

       attack_action = random.randint(0, 9)

       frames, reward, round_done, stage_done, game_done = env.step(move_action, attack_action)

       if game_done:

           env.new_game()

       elif stage_done:

           env.next_stage()

       elif round_done:

           env.next_round()

def main():

   workers = 8

   # Environments must be created outside of the threads

   roms_path = "roms/"

   envs = [Environment(f"env{i}", roms_path) for i in range(workers)]

   threads = [Thread(target=run_env, args=(envs[i], )) for i in range(workers)]

   [thread.start() for thread in threads]

建立自己的游戏环境

这个工具包之所以易于上手,是因为它和模拟器本身不需要太多交互,只需注意两点——一是查找你关注的内部状态相关联的内存地址值,二是用选取的环境跟踪状态。你可以用MAME Cheat Debugger,它会反馈游戏的内存地址值如何随时间变化。如果要创建游戏模拟,你得先获得正在模拟的游戏的ROM,并知道MAME使用的游戏ID,比如街霸的ID是’sfiii3n’。

游戏ID

你可以通过运行以下代码找到游戏的ID

from MAMEToolkit.emulator import Emulator

emulator = Emulator("env1", "", "", memory_addresses)

这个命令会打开MAME仿真器。你可以搜索游戏列表以找到想要的游戏,游戏的ID位于游戏标题末尾的括号中。

内存地址

如果获得了ID,也有了想要跟踪的内存地址,你可以开始模拟:

from MAMEToolkit.emulator import Emulator

from MAMEToolkit.emulator import Address

roms_path = "roms/"

game_id = "sfiii3n"

memory_addresses = {

       "fighting": Address('0x0200EE44', 'u8'),

       "winsP1": Address('0x02011383', 'u8'),

       "winsP2": Address('0x02011385', 'u8'),

       "healthP1": Address('0x02068D0B', 's8'),

       "healthP2": Address('0x020691A3', 's8')

   }

emulator = Emulator("env1", roms_path, "sfiii3n", memory_addresses)

这会启动仿真器,并在工具包连接到模拟器进程时暂停。

分步运行仿真器

连接工具箱后,你可以分步运行仿真器:

data = emulator.step([])

frame = data["frame"]

is_fighting = data["fighting"]

player1_wins = data["winsP1"]

player2_wins = data["winsP2"]

player1_health = data["healthP1"]

player2_health = data["healthP2"]

step函数会把帧数据作为NumPy矩阵返回,同时,它也会返回该时间步长的所有内存地址整数值。

如果要向仿真器输入动作,你还需要确定游戏支持的输入端口和字段。比如玩街霸需要先投币,这个代码是:

from MAMEToolkit.emulator import Action

insert_coin = Action(':INPUTS', 'Coin 1')

data = emulator.step([insert_coin])

要确定哪些端口可用,请使用list actions命令:

from MAMEToolkit.emulator import list_actions

roms_path = "roms/"

game_id = "sfiii3n"

print(list_actions(roms_path, game_id))

下面这个返回的列表就包含街霸环境中可用于向步骤函数发送动作的所有端口和字段:

[

   {'port': ':scsi:1:cdrom:SCSI_ID', 'field': 'SCSI ID'},

   {'port': ':INPUTS', 'field': 'P2 Jab Punch'},

   {'port': ':INPUTS', 'field': 'P1 Left'},

   {'port': ':INPUTS', 'field': 'P2 Fierce Punch'},

   {'port': ':INPUTS', 'field': 'P1 Down'},

   {'port': ':INPUTS', 'field': 'P2 Down'},

   {'port': ':INPUTS', 'field': 'P2 Roundhouse Kick'},

   {'port': ':INPUTS', 'field': 'P2 Strong Punch'},

   {'port': ':INPUTS', 'field': 'P1 Strong Punch'},

   {'port': ':INPUTS', 'field': '2 Players Start'},

   {'port': ':INPUTS', 'field': 'Coin 1'},

   {'port': ':INPUTS', 'field': '1 Player Start'},

   {'port': ':INPUTS', 'field': 'P2 Right'},

   {'port': ':INPUTS', 'field': 'Service 1'},

   {'port': ':INPUTS', 'field': 'Coin 2'},

   {'port': ':INPUTS', 'field': 'P1 Jab Punch'},

   {'port': ':INPUTS', 'field': 'P2 Up'},

   {'port': ':INPUTS', 'field': 'P1 Up'},

   {'port': ':INPUTS', 'field': 'P1 Right'},

   {'port': ':INPUTS', 'field': 'Service Mode'},

   {'port': ':INPUTS', 'field': 'P1 Fierce Punch'},

   {'port': ':INPUTS', 'field': 'P2 Left'},

   {'port': ':EXTRA', 'field': 'P2 Short Kick'},

   {'port': ':EXTRA', 'field': 'P2 Forward Kick'},

   {'port': ':EXTRA', 'field': 'P1 Forward Kick'},

   {'port': ':EXTRA', 'field': 'P1 Roundhouse Kick'},

   {'port': ':EXTRA', 'field': 'P1 Short Kick'}

]

仿真器类还有一个frame_ratio参数,可用于调整算法所见的帧速率。默认情况下,MAME以每秒60帧的速度生成帧,如果你觉得这太多了,想把它改成每秒20帧,可以输入以下代码:

from MAMEToolkit.emulator import Emulator

emulator = Emulator(roms_path, game_id, memory_addresses, frame_ratio=3)

未分类

MAME性能基准测试

目前这个工具包的开发和测试已在8核AMD FX-8300 3.3GHz CPU以及3GB GeForce GTX 1060 GPU上完成。在使用单个随机智能体的情况下,街头霸王环境可以以正常游戏速度的600%+运行。而如果是用8个随机智能体进行hogwild!训练,环境可以以正常游戏速度的300%+运行。

ConvNet智能体

为了确保工具包能够训练算法,作者还设置了一个简单的5层ConvNet,只需少量调整,你就可以用它进行测试。在街霸实验中,这个算法能够成功学习到游戏的一些简单技巧,比如连击(combo)和格挡(blocking)。街霸本身的游戏机制是分成10个关卡(难度递增),玩家在每个关卡都要迎战不同的对手。刚开始的时候,这个智能体平均只能打到第2关。但在经过2200次训练后,它平均能打到第5关。

至于智能体的学习率,它是用每一局智能体所造成的净伤害和所承受的伤害来计算的。

python安装教程(Windows系统,python3.7为例)

1. 在python的官网下载python对应版本:https://www.python.org/downloads/windows/

64位下载Windows x86-64 executable installer 版本

32位下载Windows x86 executable installer 版本

打开链接如下图,版本会一直更新,选择任意一个适合自己电脑的版本就好

未分类

2. 勾选 Add python to PATH 添加路径

安装界面点击Customize installation 自定义安装

未分类

3. 不改变默认进行Next下一步

未分类

4. 选择一个自己喜欢的安装位置

点击Install开始安装

未分类

5. 等待进度条加载完毕

未分类

6. 安装完毕,点击Close关闭

若方框位置出现管理员字样则点击授权再关闭

未分类

7. 验证:运行cmd

进入到自己的安装目录下,运行语句:python -V

若显示出Python对应版本则表示安装成功

未分类

让你事半功倍的小众Python库

Python 是世界上发展最快的编程语言之一。它一次又一次地证明了自己在开发人员和跨行业的数据科学中的实用性。Python 及其机器学习库的整个生态系统使全世界的用户(无论新手或老手)都愿意选择它。Python 成功和受欢迎的原因之一是存在强大的库,这些库使 Python 极具创造力且运行快速。然而,使用 Pandas、Scikit-learn、Matplotlib 等常见库在解决一些特殊的数据问题时可能并不实用,本文介绍的这些非常见库可能更有帮助。

WGET

提取数据,特别是从网络中提取数据是数据科学家的重要任务之一。Wget 是一个免费的工具,用于以非交互式方式从 Web 上下载文件。它支持 HTTP、HTTPS 和 FTP 协议,通过 HTTP 代理进行检索。由于它是非交互式的,即使用户没有登录,它也可以在后台工作。所以,如果你想下载一个网站或一个页面上的所有图片,wget 会帮助你。

安装:

$ pip install wget

示例:

import wget
url = 'http://www.futurecrew.com/skaven/song_files/mp3/razorback.mp3'
filename = wget.download(url)
100% [................................................] 3841532 / 3841532
filename
'razorback.mp3'

对于那些在 python 中被处理datetimes困扰的人来说,Pendulum 是个好选择。它是一个 Python 包,用于简化 datetimes 操作。它是 Python「本机」类(native class)的代替。更多内容,请参阅文档:https://um.eustace.io/docs/# installation。

安装:

$ pip install pendulum

示例:

import pendulum
dt_toronto = pendulum.datetime(2012, 1, 1, tz='America/Toronto')
dt_vancouver = pendulum.datetime(2012, 1, 1, tz='America/Vancouver')
print(dt_vancouver.diff(dt_toronto).in_hours())
3

可以看出,当每个类的样本数量相等即平衡时,大多数分类算法的工作效果最好。但现实生活中充满了不平衡的数据集,这些数据集对机器学习的学习阶段和后续预测都有影响。创建这个库是为了解决这个问题。它与 scikit-learn 兼容,并且是 scikit-learn-contrib 项目的一部分。下次遇到不平衡的数据集时,可以尝试一下。

安装:

pip install -U imbalanced-learn

# or

conda install -c conda-forge imbalanced-learn

示例:

有关用法和示例,请参考:http://imbalancedlearn.org/en/stable/api.html。

FLASHTEXT

在 NLP 任务中,清理文本数据通常需要替换句子中的关键词或从句子中提取关键词。通常,这样的操作可以用正则表达式来完成,但是如果要搜索的词汇量过大,操作就会变得麻烦。Python 中基于 FlashText 算法的 FlashText 模块,为这种情况提供了一个合适的替代方案。FlashText 最大的优点是搜索词数量不影响运行时长。更多相关信息请见:https://flashtext.readthedocs.io/en/latest/#。

安装:

$ pip install flashtext

示例

提取关键词:

from flashtext import KeywordProcessor
keyword_processor = KeywordProcessor()
# keyword_processor.add_keyword(<unclean name>, <standardised name>)
keyword_processor.add_keyword('Big Apple', 'New York')
keyword_processor.add_keyword('Bay Area')
keywords_found = keyword_processor.extract_keywords('I love Big Apple and Bay Area.')
keywords_found
['New York', 'Bay Area']

替换关键词:

keyword_processor.add_keyword('New Delhi', 'NCR region')
new_sentence = keyword_processor.replace_keywords('I love Big Apple and new delhi.')
new_sentence
'I love New York and NCR region.'

更多使用示例,请参阅官方文档。

FUZZYWUZZY

虽然名字听起来很奇怪,但涉及到字符串匹配时,fuzzywuzzy 是一个非常有用的库,可以很容易地实现诸如字符串比较比率、token 比率等操作。对于匹配不同数据库中的记录也很方便。

安装:

$ pip install fuzzywuzzy

示例:

from fuzzywuzzy import fuzz
from fuzzywuzzy import process
# Simple Ratio
fuzz.ratio("this is a test", "this is a test!")
97
# Partial Ratio
fuzz.partial_ratio("this is a test", "this is a test!")
 100

更多有趣的例子可以在 GitHub 上找到:https://github.com/seatgeek/fuzzywuzzy。

PYFLUX

时间序列分析是机器学习领域最常见的问题之一。PyFlux 是 Python 中为处理时间序列问题而创建的开源库。该库有一系列极好的时间序列模型,包括但不限于 ARIMA、 GARCH 和 VAR 模型。简而言之,PyFlux 提供了一个时间序列建模的概率方法。值得尝试。

安装:

pip install pyflux

示例:

有关用法和示例,请参考:https://pyflux.readthedocs.io/en/latest/index.html。

IPYVOLUME

交流结果是数据科学的一个基本方面。能够将结果可视化是一个很大的优势。IPyvolume 是一个用于在 Jupyter notebook 中可视化 3d 体积和字形(如 3d 散点图)的 Python 库,只需少量配置即可。然而,它目前还处于前 1.0 版。IPyvolume 的 volshow 之于 3d 数组,就像 matplotlib 的 imshow 之于 2d 数组一样。更多相关信息请见:https://ipyvolume.readthedocs.io/en/latest/?badge=latest。

安装:

Using pip
$ pip install ipyvolume
Conda/Anaconda
$ conda install -c conda-forge ipyvolume

DASH

Dash 是一个用于构建 web 应用程序的高效 Python 框架。它写在 Flask、Plotly.js 和 React.js 之上,将下拉列表、滑块和图形等 UI 元素与你的分析性 Python 代码直接相连,无需 javascript。Dash 非常适合构建数据可视化应用程序。然后这些应用程序可以在 web 浏览器中进行渲染。用户指南请见:https://dash.plot.ly/。

安装:

pip install dash==0.29.0 # The core dash backend

pip install dash-html-components==0.13.2 # HTML components

pip install dash-core-components==0.36.0 # Supercharged components

pip install dash-table==3.1.3 # Interactive DataTable component (new!)

示例:

下图示例显示了具有下拉功能的高度交互图。当用户在下拉列表中选择一个值时,应用程序代码会动态地将 Google Finance 的数据导出为 Pandas DataFrame。资源:https://gist.github.com/chriddyp/3d2454905d8f01886d651f207e2419f0。

未分类

GYM

来自 OpenAI 的 Gym 是一个开发和对比强化学习算法的工具包。它兼容于任何数值计算库,如 TensorFlow 或 Theano。Gym 库是一个测试问题的集合,也被称为环境——可以用它来计算你的强化学习算法。这些环境有一个共享的接口,允许你写通用算法。

安装:

pip install gym

示例:

运行环境 CartPole-v0 的 1000 个时间步骤实例,在每个步骤渲染环境。

未分类

阅读其他环境请见:https://gym.openai.com/。

结论

这些是作者为数据科学挑选的实用 python 库,而非常见的 numpy、panda 等。值得一试。

Python的闭包

Python代码中,可以定义嵌套函数,即在函数中再定义一个函数。嵌套函数有什么特别之处吗?因为闭包。

简单说,闭包就是嵌套的内层函数能够记住外层函数的namespace,在外层函数返回之后,内层函数还可以正常访问外层的这些变量。看如下代码:

def outer():
    msg = 'hello world'
    def inner():
        print(msg)
    return inner
>>> func = outer()
>>> func()
hello world

闭包有2个特点:

  1. inner能访问outer及其祖先函数的命名空间内的变量(局部变量,函数参数)。
  2. 调用outer已经返回了,但是它的命名空间被返回的inner对象引用,所以还不会被回收。

这部分想深入可以去了解Python的LEGB规则。

Python有了闭包,就可以创建函数的装饰器了。