Python虚拟环境工具Virtualenv的安装与使用

简介

Virtualenv可以为Python提供独立的运行环境,在一定程度上可解决解决依赖、版本以及间接权限等问题。

安装

使用pip命令安装:

$ [sudo] pip install virtualenv  

或使用

$ [sudo] pip install https://github.com/pypa/virtualenv/tarball/master  

安装最新版本。

使用

创建虚拟环境

$ virtualenv venv  

目前版本默认不使用全局Python安装的库,即参数–no-site-packages。如果要继承全局Python的库,则

$ virtualenv --system-site-packages venv  

指定Python的解释器:

$ virtualenv -p /usr/bin/python3.5  venv  

激活虚拟环境

使用前,需要先激活虚拟环境

source venv/bin/activate  

注意此时命令行会多一个(ENV),ENV为虚拟环境名称,接下来所有模块都只会安装到该目录中。

退出虚拟环境

(ENV)$ deactivate  

删除虚拟环境

退出虚拟环境后,在终端输入命令:

(ENV)$ deactivate  
$ rm -r /path/to/ENV  

PS:

Python3.3以上的版本通过venv模块原生支持虚拟环境,可以代替virtualenv。

ORM、SQLAlchemy数据库操作

ORM介绍

背景:
用底层的sql写的话,相当于通过pymysql 游标的方式连接“http://blog.51cto.com/jacksoner/2113454 ”,为了避免把sql语句写死在代码里,有没有一种方法直接把原生sql封装好了并且以你熟悉的方式操作,像面向对象那样?

ORM就是对象映射关系程序。相当于ORM帮我们SQL写成类的形式,然后通过类来调用,获取,而不是写底层的sql(insert,update,select)来获取。

ORM 相当于把数据库也给你实例化了,在代码操作mysql中级又加了orm这一层。

orm的优点:
1、隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。他使得我们的通用数据库交互变得简单易行,并且完全不用考虑该死的SQL语句。快速开发,由此而来。
2、ORM使我们构造固化数据结构变得简单易行。

sqlalchemy安装

在Python中,最有名的ORM框架是SQLAlchemy。用户包括openstack\Dropbox等知名公司或应用

安装:

pip install SQLAlchemy
SQLAlchemy==1.2.7

pip install pymysql

数据库:

CentOS Linux release 7.4.1708

mysql版本:5.6.35
IP:192.168.1.48
用户:root
密码:123456
创建一个超级用户:grant all privileges on . to jacker@’%’ identified by ‘123456’ WITH GRANT OPTION;
创建一个数据库: mysql> create database sqlalchemy;

方式一:

import pymysql
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column,Integer,String            #创建列,整型,字符串型
engine = create_engine('mysql+pymysql://jacker:[email protected]/sqlalchemy',encoding='utf-8',echo=True)
#echo=True:显示创建sql信息
Base = declarative_base()  # 生成orm基类

#这里的继承Base的类,创建user表,字段id(整型,主键) name(列 字符串32位) 密码(列 字符串64位)
class User(Base):
    __tablename__ = 'user'  # 表名
    id = Column(Integer, primary_key=True)
    name = Column(String(32))
    password = Column(String(64))
Base.metadata.create_all(engine) #创建表结构 (这里是父类调子类)

运行结果:

未分类

方式二 创建表,并写入数据:

创建表:

from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String

engine = create_engine('mysql+pymysql://jacker:[email protected]/sqlalchemy',encoding='utf-8')
metadata = MetaData(engine)

teacher = Table('user', metadata,
            Column('id', Integer, primary_key=True),
            Column('name', String(50), ),
            Column('fullname', Integer),
            Column('password', String(10)),
)
metadata.create_all(engine)

写入数据:

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

engine = create_engine('mysql+pymysql://jacker:[email protected]/sqlalchemy',encoding='utf-8')
#echo=True:显示信息
DBsession = sessionmaker(bind=engine)# 实例和engine绑定
session = DBsession()                 # 生成session实例,相当于游标

Base = declarative_base()# 生成orm基类

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String(100))
    fullname = Column(String(100))
    password = Column(String(100))

#实例化操作
user1 = User(id=1001, name='ling', password=123)
user2 = User(id=1002, name='molin', password="123abc")
user3 = User(id=1003, name='karl', password=16)

#需要添加到session中,然后再提交,表里才可以有数据
session.add(user1)
session.add(user2)
session.add(user3)
session.commit()

验证:

未分类

数据查询

my_user=session.query(User).filter_by(name='molin').first()#显示匹配name=molin的第一条数据,因为name='molin' 可能有多个值
my = session.query(User).filter_by().all()                  #显示所有
print(my)                                                   #这个是个列表,通过循环遍历
for i in my:
    print(i.name)
    print(i.password)
print(my_user.id,my_user.password,my_user.name)             #调用
#session.commit()                                          #查询就不用提交了
session.close()
'''
filter和filter_by   条件查询

filter_by(name="ling")  不能使用>  <  =
filter(Student.id>1001)  这个就必须使用Student.id  可以使用> < =等
'''
a = session.query(User).filter(User.id>1002).all()
for i in a:
    print(i.name)
    print(i.password)
session.close()
如果出现name相同的,想都打印出来的话:
#实例化操作
user1 = User(id=1001, name='test1', password=123)
user2 = User(id=1002, name='test2', password="123abc")
user4 = User(id=1004, name='test2', password="123abc")
user3 = User(id=1003, name='test3', password=16)

my_user = session.query(User).filter_by(name="test2").all()       #my_user:这个是列表
for i in my_user:
    print(i.id)
    print(i.name)
    print(i.password)
多条件查询

objs = Session.query(User).filter(User.id>0).filter(User.id<7).all()

上面2个filter的关系相当于 user.id >1 AND user.id <7 的效果

修改数据

my_user = session.query(User).filter_by(name="molin").first()
my_user.name = "fenggf" # 查询出来之后直接赋值修改
my_user.passwork = "123qwe"
session.commit()

bootstrap flask登录页面编写实例

本文章来为各位介绍一个python的例子,这个就是bootstrap+flask写登录页面的例子,希望文章能够对各位有所帮助。
Flask是一个使用 Python 编写的轻量级 Web 应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 。在一般应用或个人开发中,可以很容易的写出应用。本篇就结合bootstrap,写一个简单的login界面。

一、效果图

无图无真像,先上效果图:

未分类

flask-login

未分类

二、目录结构

该代码写时采用动静分离的方法进行编写,目录树如下:

[root@jb51 login]# tree
.
├── run.py
├── static
│   └── css
│       ├── bootstrap.min.css
│       └── style.css
└── templates
    ├── index.html
    └── login.html

三、入口run文件

动态代码只有一个run.py文件,代码如下:

from flask import *
app = Flask(__name__,static_url_path='/static')
@app.route("/login",methods=['POST','GET'])
def login():
 error = None
 if request.method == 'POST':
 if request.form['username'] != 'admin' or request.form['password'] != 'admin123':
  error= "sorry"
 else:
  return redirect(url_for('index'))
 return render_template('login.html',error=error)
@app.route("/index")
def index():
 return render_template('index.html')
if __name__ == "__main__":
 app.run(
 host="0.0.0.0",
 port=80,
 debug=True)

实际应用中,根据需要,可以关闭debug模试。

四、静态模块

templates下有两个模块文件分别是login.html和index.html
login.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1.0" />
<title>Bootstrap响应式登录界面模板</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/bootstrap.min.css') }}">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<div class="box">
<div class="login-box">
<div class="login-title text-center">
<h1><small>登录</small></h1>
</div>
<div class="login-content ">
<div class="form">
<form action="#" method="post">
<div class="form-group">
 <div class="col-xs-12 ">
  <div class="input-group">
   <span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
   <input type="text" id="username" name="username" class="form-control" placeholder="用户名">
  </div>
 </div>
</div>
<div class="form-group">
 <div class="col-xs-12 ">
  <div class="input-group">
   <span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>
   <input type="text" id="password" name="password" class="form-control" placeholder="密码">
  </div>
 </div>
</div>
<div class="form-group form-actions">
 <div class="col-xs-4 col-xs-offset-4 ">
  <button type="submit" class="btn btn-sm btn-info"><span class="glyphicon glyphicon-off"></span> 登录</button>
 </div>
</div>
<div class="form-group">
 <div class="col-xs-6 link">
  <p class="text-center remove-margin"><small>忘记密码?</small> <a href="javascript:void(0)" ><small>找回</small></a>
  </p>
 </div>
 <div class="col-xs-6 link">
  <p class="text-center remove-margin"><small>还没注册?</small> <a href="javascript:void(0)" ><small>注册</small></a>
  </p>
 </div>
</div>
</form>
</div>
</div>
</div>
</div>
<div ><p>来源:<a href="http://www.jb51.net/" target="_blank">运维之路</a></p></div>
</body>
</html>

index.html
index.html 模板中内容如下:

<h1>welcome to www.jb51.net/ <h1>

如果大家还想深入学习,可以点击这里进行学习,再为大家附两个精彩的专题:Bootstrap学习教程 Bootstrap实战教程
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持51dev开发社区。
以上就是bootstrap flask登录页面编写实例的全部内容,希望对大家的it技术学习有所帮助,希望大家多多支持技术开发者社区。

Django+Ngnix+Gunicorn+Mysql部署Centos的坑

环境配置

  • Centos 7
  • Python 3.6.5
  • Virtualenvwrapper 4.8.2
  • Django 2.0.5
  • Mysql 5.7.22
  • Ngnix 1.12.2
  • Gunicorn 19.8.1

注:这并不是什么教程

python虚拟环境配置

Virtualenvwrapper安装失败

试试这条命令 :-p

sudo pip install virtualenvwrapper --upgrade --ignore-installed six

简答解释就是包six版本有点低,详细解释点此

找不到virtualenvwrapper.sh文件

按照官方文档上说是安在 /usr/local/bin/virtualenvwrapper.sh,但是并没有,每个系统的情况不一样,使用如下命令

pip uninstall virtualenvwrapper

不用担心,这并不会立刻移除virtualenvwrapper,会输出以下内容,再输入n取消安装

Uninstalling virtualenvwrapper-4.8.2:
  /usr/bin/virtualenvwrapper.sh
  /usr/bin/virtualenvwrapper_lazy.sh
  /usr/lib/python2.7/site-packages/virtualenvwrapper-4.8.2-py2.7-nspkg.pth
  /usr/lib/python2.7/site-packages/virtualenvwrapper-4.8.2.dist-info/DESCRIPTION.rst
  /usr/lib/python2.7/site-packages/virtualenvwrapper-4.8.2.dist-info/INSTALLER
  /usr/lib/python2.7/site-packages/virtualenvwrapper-4.8.2.dist-info/METADATA
  ......
  Proceed (y/n)?

看第一行,这下知道在哪里的吧,对于我的centos7来说是在 /usr/bin/virtualenvwrapper.sh 下

具体见此https://stackoverflow.com/questions/12647266/where-is-virtualenvwrapper-sh-after-pip-install/41676706#41676706

Mysql配置

安装教程https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-centos-7 ,比较靠谱

中文乱码

问题可能出现在两个地方,一个是Django的配置文件中,还有一个就是Mysql的配置出问题

Django数据配置

找到project的settings.py,修改这两个地方,注意,对于较新版本的django,把zh-cn改成了zh-Hans

LANGUAGE_CODE = 'zh-Hans'

TIME_ZONE = 'Asia/Shanghai'

Mysql数据配置

先登录到你的mysql中,执行如下命令

SHOW VARIABLES LIKE 'character_set_%';

发现大多数行的值都不是utf-8,而是latin1

那么,找到mysql的配置文件my.cnf

对于 MySQL 5.7+,执行以下命令,别的情况见此

mysqladmin --help | grep 'Default options' -A 2

输出的第二行就是文件的所在

Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf

打开此文件 /etc/my.cnf

添加如下内容如下,别的地方别修改

[mysqld]
collation-server = utf8_unicode_ci
init-connect='SET NAMES utf8'
character-set-server = utf8

...

[mysql]
default-character-set=utf8

改完之后记得重启mysql服务

sudo systemctl restart mysqld

gunicorn找不到 django.core.xxx

找到gunicorn的所在地

which gunicorn

应为是在python虚拟环境下安装的,所以一般在//.virtualenvs//bin/gunicorn,如果不是这样的话终极解决方案是把要输入 gunicorn 的地方全改成 //.virtualenvs//bin/gunicorn

Django 静态文件404

在production模式下Django并不支持静态文件的处理,这一切都要交给一个服务器处理,比如此处的Nginx,千万要记住!!!!!!

Nginx无法正常启动

(ps1:centos7安装Nginx的教程见此,比较靠谱)

(ps2:默认相关防火墙已开启)

在输入

sudo systemctl start nginx
sudo systemctl status nginx

发现其启动失败,则多半是你配置文件写错的结果,输入一下命令排错

sudo nginx -t

修改完之后记得刷新哦

sudo service nginx restart
#或者
sudo service nginx reload

linux系统中编译安装postgresql

以postgresql-9.6.2为例

# wget https://ftp.postgresql.org/pub/source/v9.6.2/postgresql-9.6.2.tar.gz
# tar zxvf postgresql-9.6.2.tar.gz
# cd postgresql-9.6.2
# ./configure --prefix=/usr/local/postgresql
# make 
# make install

给postgresql添加用户 (因为创建database cluster时不能用root帐号)

# useradd postgres 
# passwd postgres

建立database cluster目标文件夹

# mkdir -p /mnt/data/pgsql 
# chown -R postgres /mnt/data/pgsql

环境变量设置

# su - postgres  //切换到postgres用户
$ vi .bash_profile

在末尾添加如下内容

# postgres 
PGDATA=/mnt/data/pgsql 
PATH=/usr/local/pgsql/bin:$PATH 
export PGDATA PATH

使环境变量生效

$ source .bash_profile

初始化数据库

pg_ctl initdb

启动数据库实例

$pg_ctl -D /mnt/data/pgsql -l logfile start //设置好PGDATA环境变量后,可以不带-D选项

关闭数据库实例

$ pg_ctl stop

CentOS7使用FirewallD管理防火墙

FirewallD 提供了支持网络/防火墙区域(zone)定义网络链接以及接口安全等级的动态防火墙管理工具,它拥有运行时配置和永久配置选项。CentOS 7中防火墙是一个非常的强大的功能,本文主要介绍FirewallD常用管理命令。

安装firewalld
Centos7自带FirewallD防火墙工具,如果你的系统是最小化安装的,可能就需要自己动手安装firewalld服务。

yum install firewalld firewall-config

运行和停止firewalld

systemctl是CentOS7的服务管理工具中主要的工具,它融合之前service和chkconfig的功能于一体。我们使用systemctl命令来控制firewalld。

启动防火墙:

systemctl start firewalld.service

关闭防火墙:

systemctl stop firewalld.service

重启防火墙:

systemctl restart firewalld.service

开机时启动防火墙:

systemctl enable firewalld.service

开机时禁用防火墙:

systemctl disable firewalld.service

查看防火墙运行状态:

systemctl status firewalld

配置firewalld-cmd管理防火墙端口
我们使用firewalld的字符界面管理工具firewall-cmd很方便就可以管理firewalld。

显示防火墙状态:

firewall-cmd --state

显示防火墙状态:

firewall-cmd --state

添加80端口,允许访问80端口,并永久生效:

firewall-cmd --zone=public --add-port=80/tcp --permanent

添加服务,允许https访问,并永久生效:

firewall-cmd --zone=public --add-service=https --permanent

移除80端口:

firewall-cmd --zone=public --remove-port=80/tcp --permanent

重新载入使配置生效:

firewall-cmd --reload

查看开放的端口:

firewall-cmd --list-ports

当然,你也可以到/etc/firewalld/zones/目录下直接修改xml配置文件。
习惯用centos7以前版本的伙伴都喜欢用iptable来管理防火墙,设置在使用CentOS7后还把系统自带的firewalld服务弃用,转而用老版本的iptable,可我觉得firewalld很好用啊,简单又实在,好东西为什么不用呢。

Linux系统/run/systemd空间不足问题解决

之前说Debian8直接升级到Debian9,发现升级完成之后遇到一个问题,就是升级到Debian9之后,在/run/systemd出现可用空间不足问题,连个Nginx都不能启动,于是花了点时间解决了下。

报错详情:

Failed to reload daemon: Refusing to reload, not enough space available on /run/systemd. Currently, 10.5M are free, but a safety buffer of 16.0M is enforced.
Processing triggers for systemd (232-25+deb9u3) ...
Failed to reload daemon: Refusing to reload, not enough space available on /run/systemd. Currently, 10.5M are free, but a safety buffer of 16.0M is enforced.

df -h一下,发现这个目录确实空间不多:

root@elsenow-virmach-128:~# df -h
Filesystem      Size  Used Avail Use% Mounted on
udev             47M     0   47M   0% /dev
tmpfs            12M  880K   11M   8% /run
/dev/vda1       9.7G  1.9G  7.4G  21% /
tmpfs            58M     0   58M   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs            58M     0   58M   0% /sys/fs/cgroup
tmpfs            12M     0   12M   0% /run/user/0

很明显,是提示/run/systemd空间不足,我们只需要想办法给这个目录增加空间就行,一开始我还以为会很麻烦,没想到最后也就一行配置的事情,不多说,直接上代码:

vim /etc/fstab

tmpfs /run tmpfs nosuid,noexec,size=18M,nr_inodes=4096 0 0

也就是到/etc/fstab增加一行就行了。增加之后,保存,重启,问题就解决了。

Ubuntu 18.04 rc.local systemd设置

ubuntu18.04不再使用initd管理系统,改用systemd。

然而systemd很难用,改变太大,跟之前的完全不同。

使用systemd设置开机启动
为了像以前一样,在/etc/rc.local中设置开机启动程序,需要以下几步:

1、systemd默认读取/etc/systemd/system下的配置文件,该目录下的文件会链接/lib/systemd/system/下的文件。一般系统安装完/lib/systemd/system/下会有rc-local.service文件,即我们需要的配置文件。
链接过来:

ln -fs /lib/systemd/system/rc-local.service /etc/systemd/system/rc-local.service  
cd /etc/systemd/system/  
cat rc-local.service  

rc-local.service内容

#  SPDX-License-Identifier: LGPL-2.1+  
#  
#  This file is part of systemd.  
#  
#  systemd is free software; you can redistribute it and/or modify it  
#  under the terms of the GNU Lesser General Public License as published by  
#  the Free Software Foundation; either version 2.1 of the License, or  
#  (at your option) any later version.  

# This unit gets pulled automatically into multi-user.target by  
# systemd-rc-local-generator if /etc/rc.local is executable.  
[Unit]  
Description=/etc/rc.local Compatibility  
Documentation=man:systemd-rc-local-generator(8)  
ConditionFileIsExecutable=/etc/rc.local  
After=network.target  

[Service]  
Type=forking  
ExecStart=/etc/rc.local start  
TimeoutSec=0  
RemainAfterExit=yes  
GuessMainPID=no  

[Install]  
WantedBy=multi-user.target  
Alias=rc-local.service  

1) [Unit] 区块:启动顺序与依赖关系。

2) [Service] 区块:启动行为,如何启动,启动类型。

3) [Install] 区块,定义如何安装这个配置文件,即怎样做到开机启动。

2、创建/etc/rc.local文件

touch /etc/rc.local  

3、赋可执行权限

chmod 755 /etc/rc.local  

4、编辑rc.local,添加需要开机启动的任务

#!/bin/bash  

echo "test rc " > /var/test.log  

5、执行reboot重启系统,然后查看test.log

systemd 的网络管理

0. 简介

systemd 是 freedesktop 的项目,官网 https://www.freedesktop.org/wiki/Software/systemd/ ,项目源码在 github 上发布,可以在 https://github.com/systemd/systemd 查看所有版本更新、 Bug Fix 和版本对应的文档等。
systemd-networkd 是 systemd 默认提供的网络管理服务,可以完全管理以太网,对于无线网卡,还需要其他服务支持,比如管理 Wi-Fi 的 [email protected] ,管理 PPP 的 [email protected]
管理网卡前,应该确保各网卡的驱动都已经正常加载,systemd 的 systemd-modules-load.service 负责在系统启动时静态加载内核模块。它会从以下路径搜索可用的配置文件:

/etc/modules-load.d/*.conf
/run/modules-load.d/*.conf
/usr/lib/modules-load.d/*.conf

配置文件的内容就是一个内核模块名称的列表,可以用井号 # 或者分号 ; 注释单个模块。

1. 基本配置

我的系统中,systemd 的版本是 216 ,有两个以太网卡和一个 Wi-Fi 网卡,先查看一下网卡列表,再查看 systemd-networkd.service 的状态:

~# networkctl list
IDX LINK             TYPE               OPERATIONAL SETUP     
1 lo               loopback           carrier     unmanaged 
2 wlp1s0           wlan               off         unmanaged 
3 enp0s20f6        ether              routable    configured
4 enp0s20f7        ether              no-carrier  configured
4 links listed.
~# systemctl status systemd-networkd 
a—? systemd-networkd.service - Network Service
Loaded: loaded (/lib/systemd/system/systemd-networkd.service; enabled)
Active: active (running) since Fri 2018-04-27 17:49:22 UTC; 24min ago
    Docs: man:systemd-networkd.service(8)
Main PID: 260 (systemd-network)
Status: "Processing requests..."
CGroup: /system.slice/systemd-networkd.service
        a””a”€260 /lib/systemd/systemd-networkd

Apr 27 17:49:21 quark systemd[1]: Starting Network Service...
Apr 27 17:49:22 quark systemd-networkd[260]: lo              : gained carrier
Apr 27 17:49:22 quark systemd[1]: Started Network Service.
Apr 27 17:49:22 quark systemd-networkd[260]: eth1            : renamed to enp0s20f7
Apr 27 17:49:22 quark systemd-networkd[260]: eth0            : renamed to enp0s20f6
Apr 27 17:49:23 quark systemd-networkd[260]: enp0s20f6       : gained carrier
Apr 27 17:49:23 quark systemd-networkd[260]: enp0s20f7       : gained carrier
Apr 27 17:49:25 quark systemd-networkd[260]: enp0s20f6       : lost carrier
Apr 27 17:49:26 quark systemd-networkd[260]: enp0s20f7       : lost carrier

sytemd-network.service 的配置文件可以位于 /usr/lib/systemd/network/ 或者 /etc/systemd/network/ 目录下,后者具有最高优先级。配置文件有三种类型:

  • .network 文件,设置网卡的 IP 等各项属性
  • .netdev 文件,新建一个虚拟网卡
  • .link 文件,每当一个网卡出现时,udev 都会查找与它同名的 .link 文件

这几类文件都遵循下面的规则:

  • 各选项的值都支持星号 * 通配符
  • 当 [Match] 段内的条件都匹配时,后面的配置项才会被激活
  • 如果 [Match] 段为空,表示后面的配置项在任何情况下都可用
  • 无论配置文件在哪个目录,都会统一安装字典顺序进行加载
  • 同名文件可以相互替换

如果要给 enp0s20f6 配置一个静态 IP ,可以在 /etc/systemd/network/ 目录下新建一个 eth0.network 文件,内容如下:

[Match]
Name=enp0s20f6  # 匹配名为 enp0s20f6 的网卡
[Network]
DHCP=none    # 关闭 DHCP 客户端,
Address=192.168.5.242/24  # 设置 IP 和子网掩码
Gateway=192.168.5.50   # 设置网关,这项设置会将该网卡添加到缺省路由
DNS=8.8.8.8  # 设置 DNS 

如果要使用 DHCP 自动获取 IP ,也将 DHCP 设为如下值:

  • v4 ,只接受 ipv4 的 IP
  • v6 ,只接受 ipv6 的 IP
  • both ,同时接受 ipv4 和 ipv6 格式的 IP

启动 DHCP 客户端后,Gateway 和 DNS 也会自动获取,有时我们不希望这样,可以在配置文件中添加一个 [DHCP] 段,做如下设置:

[DHCP]
UseDNS=false # 不使用 DHCP 分配的 DNS ,默认值是 true
UseRoutes=false # 不会将本网卡设为缺省路由,默认值是 true 

在这里会出现一个 Bug ,就是 UseRoutes 设置无效,高版本中已经解决,解决方案在 https://github.com/systemd/systemd/pull/3075 。

2. Wi-Fi 配置

Wi-Fi 连接还是使用 wpa_supplicant 程序,systemd 提供了 [email protected] 管理整个流程,然后再用 systemd-networkd.service 配置 IP 等。
[email protected] 的内容:

[Unit]
Description=WPA supplicant daemon (interface-specific version)
Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device

# NetworkManager users will probably want the dbus version instead.

[Service]
Type=simple
ExecStart=/usr/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I

[Install]
Alias=multi-user.target.wants/wpa_supplicant@%i.service

这是 service 模板,启动时在 @ 符号之后加入 Wi-Fi 网卡的名称使其实例实例化,这个名词还会关联到 wpa_supplicant 的配置文件,我们先在 /etc/ 下新建一个 wpa_supplicant 目录,然后新建一个 wpa_supplicant-wlp1s0.conf 文件,内容如下:

ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=wheel
update_config=1
eapol_version=1
ap_scan=1
fast_reauth=1

用 wpa_passphrase 添加无线路由器配置:

~# sudo wpa_passphrase [essid] [password] >> /etc/wpa_supplicant/wpa_supplicant-wlp1s0.conf
在 /etc/systemd/network/ 目录下添加配置文件 wireless.network ,内容如下:
[Match]
Name=wlp1s0
[Network]
DHCP=yes

最后重启各项服务:

~# systemctl restart systemd-networkd
~# systemctl restart wpa_supplicant@wlp1s0
~# systemctl restart systemd-resolved

3. 3G/4G 配置

依然使用 pppd 进行 3G/4G 拨号,systemd 提供了 [email protected] 服务管理 pppd 。首先在 /etc/ppp/peers/ 下建好 ppp 拨号文件 me909s ,然后启动服务:

~# systemctl start ppp@me909s 

4. 关闭 IPv6

向内核参数加入 ipv6.disable=1 可以完全关闭 IPv6 功能。此外,只加入 ipv6.disable_ipv6=1 内核参数可以保留 IPv6 功能,但不会向网卡分配 IPv6 地址,做法是:

~# echo 1 > /proc/sys/net/ipv6/conf/enp0s20f6/disable_ipv6

5. ssh server

目前流行的启动 ssh server 的方式是调用 sshd.socket :

~# systemctl start sshd.socket

旧有的 sshd.service 模式会在后台保持一个 sshd 的守护进程,每当有 ssh 连接要建立时,就创建一个新进程,比较适合 SSH 下有大量流量的系统;
新的 sshd.socket 方式也是在每次要建立新的ssh连接时生成一个守护进程的实例,不过监听端口则是交给了 systemd 来完成,意味着没有 ssh 连接的时候,也不会有 sshd 守护进程运行,大部分情况下,使用 sshd.socket 服务更为合适。这也与 MacOS 下的行为相一致,默认只监听端口,有连接时才创建进程。
另外,通过使用 .socket 文件来管理需要监听端口的服务,可以直接通过 systemctl 来查看一些网络相关的信息,如监听的端口、目前已经接受的连接数、目前正连接的连接数等。

基于 Keepalived + HAproxy 的 RabbitMQ 高可用配置实践

本文使用的高可用架构是 Keepalived + HAproxy,用 HAproxy 来做 RabbitMQ 负载均衡和高可用,用 Keepalived 来保证 HAproxy 的高可用。

RabbitMQ 集群的安装过程这里不再赘述,可以参考 https://blog.csdn.net/WoogeYu/article/details/51119101。

这里使用的三节点集群的安装方式,规划如下:

组件 IP 端口

RabbitMQ 主 192.168.151.7 5672
RabbitMQ 从 192.168.151.18 5672
RabbitMQ 从 192.168.151.19 5672
HAproxy 主 192.168.151.18
HAproxy 从 192.168.151.19
Keepalived 主 192.168.151.18
Keepalived 从 192.168.151.19
VIP 192.168.151.108

RabbitMQ 集群安装

在 192.168.151.7、192.168.151.18、192.168.151.19 三个节点上分别安装配置。

安装

yum -y install rabbitmq-server
service rabbitmq-server start

配置

rabbitmqctl add_user admin admin
rabbitmqctl set_user_tags admin administrator
set_permissions -p / admin ‘.*’ ‘.*’ ‘.*’
rabbitmqctl set_permissions -p / admin ‘.*’ ‘.*’ ‘.*’

rabbitmq-plugins enable rabbitmq_management

局域网配置
分别在三个节点的 /etc/hosts 下设置相同的配置信息

192.168.151.7 HRB-PCRP1-M-BCCLM-CTL7
192.168.151.18 HRB-PCRP1-M-BCCLM-CTL18
192.168.151.19 HRB-PCRP1-M-BCCLM-CTL19

设置不同节点间同一认证的 Erlang Cookie
采用从主节点 copy 的方式保持 Cookie 的一致性。

# scp /var/lib/rabbitmq/.erlang.cookie 192.168.151.18:/var/lib/rabbitmq
# scp /var/lib/rabbitmq/.erlang.cookie 192.168.151.19:/var/lib/rabbitmq12

使用 -detached 运行各节点

rabbitmqctl stop
rabbitmq-server -detached

查看各节点的状态

rabbitmqctl cluster_status

创建并部署集群,以 192.168.151.7 节点为例:

# rabbitmqctl stop_app
# rabbitmqctl reset
# rabbitmqctl join_cluster rabbit@HRB-PCRP1-M-BCCLM-CTL7
# rabbitmqctl start_app

查看集群状态

# rabbitmqctl cluster_status
Cluster status of node ‘rabbit@HRB-PCRP1-M-BCCLM-CTL7’ …
[{nodes,[{disc,[‘rabbit@HRB-PCRP1-M-BCCLM-CTL18’,
‘rabbit@HRB-PCRP1-M-BCCLM-CTL19’,
‘rabbit@HRB-PCRP1-M-BCCLM-CTL7’]}]},
{running_nodes,[‘rabbit@HRB-PCRP1-M-BCCLM-CTL18’,
‘rabbit@HRB-PCRP1-M-BCCLM-CTL19’,
‘rabbit@HRB-PCRP1-M-BCCLM-CTL7’]},
{cluster_name,<<“rabbit@HRB-PCRP1-M-BCCLM-CTL7”>>},
{partitions,[]},
{alarms,[{‘rabbit@HRB-PCRP1-M-BCCLM-CTL18’,[]},
{‘rabbit@HRB-PCRP1-M-BCCLM-CTL19’,[]},
{‘rabbit@HRB-PCRP1-M-BCCLM-CTL7’,[]}]}]

RabbitMQ 集群至此安装完成。可以通过访问各节点的 http://192.168.151.7:15672/ 管理页面查看 RabbitMQ 状态。用户名密码使用之前配置的 admin/admin。

Keepalived 监控 192.168.151.18、192.168.151.19 上的 HAproxy,利用 Keepalived 的 VIP 漂移技术,若两台服务器上的 HAprox 都工作正常,则 VIP 与优先级别高的服务器(主服务器)绑定,当主服务器当掉时,则与从服务器绑定,而 VIP 则是暴露给外部访问的 IP;HAproxy 利用 Keepalived 生产的 VIP 对多台 RabbitMQ 进行读负载均衡。

下面对上面的 RabbitMQ 集群进行高可用配置,HAproxy 和 Keepalived 的安装方法这里不再赘述。

高可用架构 Keepalived + HAproxy

未分类

其中 Keepalived 来控制 HAproxy 的高可用,HAproxy 的作用是控制下层应用的负载均衡,同时可以用来保证下层应用的高可用。

HAproxy

HAproxy 是一个七层的负载均衡高度器,和 nginx 是属于一个层次上的,而 lvs 是一个四层的负载均衡高度器,它最多只能工作在 TCP/IP 协议栈上,所以对于代理转发,HAproxy 做的可以比 lvs 更细腻。

HAProxy 提供高可用性、负载均衡以及基于 TCP 和 HTTP 应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。HAProxy 特别适用于那些负载特大的 web 站点,这些站点通常又需要会话保持或七层处理。HAProxy 运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中,同时可以保护你的 web 服务器不被暴露到网络上。

HAproxy 配置

这里仅列出了主要内容。

HAProxy配置中分成五部分内容,当然这些组件不是必选的,可以根据需要选择部分作为配置。

#global :参数是进程级的,通常和操作系统(OS)相关。这些参数一般只设置一次,如果配置无误,就不需要再次配置进行修改
#defaults:配置默认参数的,这些参数可以被利用配置到frontend,backend,listen组件
#frontend:接收请求的前端虚拟节点,Frontend可以根据规则直接指定具体使用后端的 backend(可动态选择)。
#backend :后端服务集群的配置,是真实的服务器,一个Backend对应一个或者多个实体服务器。
#listen :Frontend和Backend的组合体。

listen rabbitmq
bind 192.168.151.108:5673
balance roundrobin
mode tcp
option tcplog
option tcpka
bind-process 7
timeout client 15s
timeout connect 3s
timeout server 15s
server HRB-PCRP1-M-BCCLM-CTL7 192.168.151.7:5672 check inter 5000 rise 2 fall 3
server HRB-PCRP1-M-BCCLM-CTL18 192.168.151.18:5672 check inter 5000 rise 2 fall 3
server HRB-PCRP1-M-BCCLM-CTL19 192.168.151.19:5672 check inter 5000 rise 2 fall 3
# weight – 调节服务器的负重
# check – 允许对该服务器进行健康检查
# inter – 设置连续的两次健康检查之间的时间,单位为毫秒(ms),默认值 2000(ms)
# rise – 指定多少次连续成功的健康检查后,可认定该服务器处于可操作状态,默认值 2
# fall – 指定多少次不成功的健康检查后,认为服务器为当掉状态,默认值 3
# maxconn – 指定可被发送到该服务器的最大并发连接数

# 配置haproxy web监控,查看统计信息
listen private_monitoring :8100
mode http
option httplog
stats enable
#设置haproxy监控地址为http://localhost:8100/stats
stats uri /stats
stats refresh 5s

这里使用了一个 listen 块来同时实现前端和后端,也可以由前端(frontend)和后端(backend)配置。

最后我们打开 http://192.168.151.18:8100/stats,看一下监控页面,如果显示出正常就表明已经将 HAProxy 负载均衡配置好了!

未分类

注意点

启动 HAproxy 时可能会出现 cannot bind socket 的异常,这是因为 HAproxy 配置中使用了 VIP,但此时还没有启动 Keepalived,那么就还没有 VIP 绑定。

这时需要在 /etc/sysctl.conf 文件中配置如下内容:

net.ipv4.ip_nonlocal_bind = 1 # 意思是启动haproxy的时候,允许忽视VIP的存在
net.ipv4.ip_forward = 1 # 打开内核的转发功能

然后运行 sysctl –p 使其生效。

Keepalived

Keepalived 的作用是检测服务器的健康状态,在所有可能出现单点故障的地方为其提供高可用。如果有一台服务器死机,或工作出现故障,Keepalived 将检测到,并将有故障的服务器从系统中剔除,当服务器工作正常后 Keepalived 自动将服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的服务器。

这里使用的实现方式是单活方式,即主节点的 HAproxy 正常运行,备节点的会被停止。当主节点的出现故障时,备节点的 HAproxy 会自动启动。当主节点的恢复后,备节点的会自动停止。

当然 Keepalived 的高可用控制不止这一种,也可以有其他配置方式。

Keepalived 主节点配置

vrrp_script chk_haproxy {
script “service haproxy status” # 服务探测,返回0说明服务是正常的
interval 1 # 每隔1秒探测一次
weight -2 # 不正常时,权重-1,即haproxy上线,权重加2;下线,权重减2
}

vrrp_instance haproxy {
state MASTER # 主机为MASTER,备机为BACKUP
interface bond0 # 监测网络端口,用ipconfig查看
virtual_router_id 108 # 主备机必须相同
priority 100 # 主备机取不同的优先级,主机要大。
advert_int 1 # VRRP Multicast广播周期秒数
authentication {
auth_type PASS # VRRP认证方式
auth_pass 1234 # VRRP口令 主备机密码必须相同
}

track_script { # 调用haproxy进程检测脚本,备节点不配置
chk_haproxy
}
track_interface {
bond0
}
virtual_ipaddress { # VIP 漂移地址 即集群IP地址
192.168.151.108/25 dev bond0
}
}

Keepalived 备节点

vrrp_instance haproxy {
state BACKUP
interface bond0
virtual_router_id 108
priority 99
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
track_interface {
bond0
}
virtual_ipaddress {
192.168.151.108
}
notify_master “/etc/keepalived/notify.sh master” # 当前节点成为master时,通知脚本执行任务,一般用于启动某服务
notify_backup “/etc/keepalived/notify.sh backup” # 当前节点成为backup时,通知脚本执行任务,一般用于关闭某服务

}

notify.sh 脚本
放在 /etc/keepalived/ 目录下,并赋予可执行权限。

#!/bin/bash

case “$1” in
master)
notify master
service haproxy start
exit 0
;;
backup)
notify backup
service haproxy stop
exit 0
;;
fault)
notify fault
service haproxy stop
exit 0
;;
*)
echo ‘Usage: `basename $0` {master|backup|fault}’
exit 1
;;
esac

Keepalived 执行过程
MASTER – 初始 priority 为 100,BACKUP – 初始 priority 为 99

模拟 MASTER 产生故障:

当检测到 chk_haproxy 执行结果为 down 时,priority 每次减少 2,变为 98;低于 BACKUP 的 priority;
此时 MASTER 变成 BACKUP;
同时 BACKUP 变成 MASTER,同时执行 notify_master 的脚本文件(启动haproxy);
模拟 MASTER 故障恢复:

当 MASTER 节点的 HAproxy 恢复后,原 MASTER 的优先级又变为 100,高于原 BACKUP 的 priority;
此时原 MASTER 由 BACKUP 又抢占成了 MASTER;
同时原 BACKUP 由 MASTER 又变了 BACKUP,同时执行 notify_backup 的脚本文件(关闭haproxy);