linux中firewalld几个使用场景

一、基础配置

查看当前配置

# firewall-cmd --get-active-zone 
public
  interfaces: eth0 eth1

改变域

# nmcli c mod eth0 connection.zone internal 
# nmcli c mod eth1 connection.zone external
# firewall-cmd --get-active-zone 
internal
  interfaces: eth0
external
  interfaces: eth1

设置IP伪装

# firewall-cmd --zone=external --add-masquerade --permanent 
success
# firewall-cmd --reload 
success

查看配置

# firewall-cmd --zone=external --query-masquerade 
yes

查看ip转发和ip伪装打开

# cat /proc/sys/net/ipv4/ip_forward 

场景1、本机端口转发

访问本机external网卡的8088端口转发到本机的22号端口

# firewall-cmd --zone=external --add-forward-port=port=8088:proto=tcp:toport=22  --permanent
success
# firewall-cmd --list-all --zone=external 
external (active)
  interfaces: eth1
  sources:
  services: ssh
  ports:
  masquerade: yes
  forward-ports: port=8088:proto=tcp:toport=22:toaddr=
  icmp-blocks:
  rich rules:  

未分类

场景2:端口映射

访问防火墙的external网卡eth1的8080端口直接转发到192.168.8.2的http端口

# firewall-cmd --zone=external --add-forward-port=port=8080:proto=tcp:toport=80:toaddr=192.168.8.2 --permanent
# firewall-cmd --list-all --zone=external

未分类

场景3:内部服务器通过防火墙上网

设置ip伪装

# firewall-cmd --zone=internal --add-masquerade --permanent 
success
# firewall-cmd --reload 
Success

设置网卡IP的nat

# firewall-cmd --direct --add-rule ipv4 nat POSTROUTING 0 -o eth1 -j MASQUERADE 

设置规则accept

# firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -i eth0 -o eth1 -j ACCEPT 
# firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -i eth1 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT

未分类

Ceph的Python接口

参考文章

ceph的python_api文档: http://docs.ceph.com/docs/master/rados/api/python/

连接ceph集群

import rados
cluster = rados.Rados(conffile='/etc/ceph/ceph.conf')
cluster.connect()

创建与删除池

# 列出可用的池
pools = cluster.list_pools()
for pool in pools:
    print pool
# 创建池test
cluster.create_pool('test')
# 删除池
cluster.delete_pool('test')
# 判断是否存在一个池
cluster.pool_exists('test')

列出池中所有的文件名

ioctx = cluster.open_ioctx('test')
# 列出test池中的所有文件名
object_iterator = ioctx.list_objects()
while True :
    try :
        rados_object = object_iterator.next()
        print "Object contents = " + rados_object.key
    except StopIteration :
        break
ioctx.close()

上传文件

# 连接到test池
ioctx = cluster.open_ioctx('test')
file_name = "yy.mp3"
f = open("yy.mp3", "r")
file_content = f.read()
f.close()
# 将文件写入池
ioctx.write_full(file_name, file_content)
ioctx.close()

下载文件

# 连接到test池
ioctx = cluster.open_ioctx('test')
f = open("yy.mp3", "w")
# 将文件下载(写入)到本地
f.write(ioctx.read("yy.mp3"))
f.close()
ioctx.close()

删除文件

ioctx = cluster.open_ioctx('test')
# 删除test池中的yy.mp3文件
ioctx.remove_object("yy.mp3")
ioctx.close()

断开ceph集群连接

cluster.shutdown()

graphite+grafana监控openstack和ceph

本文环境:CentOS 7.3.1611,openstack+ceph

架构图如下,服务端部分可以分开也可以部署在同一台主机上:

未分类

一、添加epel源和base源,安装carbon和whisper,whisper用于存储监控的数据,类似rrd文件那样固定大小:

yum install python-carbon python-whisper

编辑whisper存储规则,以下是自己写的规则:

vi /etc/carbon/storage-schemas.conf
[carbon]
pattern = ^carbon.
retentions = 60:90d

[vms]
pattern = ^instances.
retentions = 60s:30d,1h:180d,1d:2y,30d:10y

[cluster]
pattern = ^servers..*.CephCollector.ceph.mon..*.cluster.
retentions = 60s:30d,1h:180d,1d:2y,30d:10y

[CephStats]
pattern = ^servers..*.CephStatsCollector.
retentions = 60s:30d,1h:180d,1d:2y,30d:10y

[cpu]
pattern = ^servers..*.cpu.
retentions = 60s:30d,1h:180d,1d:2y,30d:10y

[diskspace]
pattern = ^servers..*.diskspace.
retentions = 60s:30d,1h:180d,1d:2y,30d:10y

[iostat]
pattern = ^servers..*.iostat.
retentions = 60s:30d,1h:180d,1d:2y,30d:10y

[loadavg]
pattern = ^servers..*.loadavg.
retentions = 60s:30d,1h:180d,1d:2y,30d:10y

[memory]
pattern = ^servers..*.memory.
retentions = 60s:30d,1h:180d,1d:2y,30d:10y

[network]
pattern = ^servers..*.network.
retentions = 60s:30d,1h:180d,1d:2y,30d:10y

[default_1min_for_1day]
pattern = .*
retentions = 60s:1d

注:监控字段可以在diamond的日志(/var/log/diamond/archive.log)或者grafana查看。

60s:30d,1h:180d 就是30天内的数据保存间隔为60秒,一个月到半年的保存间隔为1小时,规则是按顺序匹配,不是最长匹配,所以 default 规则一定要放最后,default设定为那么小只是为了不存储不需要的数据,diamond监控的字段太多,不需要全部存储。

carbon配置:

vi /etc/carbon/carbon.conf

[cache]部分,MAX_UPDATES_PER_SECOND(每秒钟最大更新条数)和MAX_CREATES_PER_MINUTE(每分钟最大创建文件数,diamon客户端首次推送数据的时候才会创建whisper数据文件)可能需要调整一下。

启动carbon-cache:

systemctl start carbon-cache

二、客户端安装diamond

(1)每个被监控的客户端都需要安装agent程序

在python官网上有,附链接:https://pypi.python.org/pypi/diamond/4.0.515

解压后 python setup.py install 即安装完成。

(2)配置

cd /etc/diamond
cp diamond.conf.example diamond.conf
vi diamond.conf
# Graphite server host
host = 127.0.0.1 #填上carbon-cache服务器IP,本机的话可以不修改。
[[default]]
hostname = test-node1
# 60秒推送一次数据
interval = 60

(3)配置监控项,diamond可以监控的项目很多,包括ceph、libvirt、mysql、haproxy、nginx等等等等

diamond-setup

基本上一直按回车就可以,由于项目太多,用setup也是繁琐,直接把需要监控的项目放到/etc/diamond/collectors/就可以,具体内容可以参照diamond-setup生成的配置文件。

(4)启动

/etc/init.d/diamond start

至此,监控的服务端和客户端已经部署好,接下来的是部署用于展示的web服务,可以使用 graphite-api + Grafana,也可以 graphite-web,graphite-web是基于django的,需要安装的东西也是一大堆,而且用户体验远远不及Grafana这个专业展示软件。

三、安装 graphite-api

graphite-api的作用只是向grafana提供访问whisper数据的接口。

(1)安装

yum install graphite-api

(2)配置

graphite-api默认启动 127.0.0.1:8888,故需要外部调用或者使用其他服务端口的话,修改/etc/sysconfig/graphite-api的GRAPHITE_API_ADDRESS=0.0.0.0或者GRAPHITE_API_PORT
配置文件 /etc/graphite-api.yaml 使用默认即可。

(3)启动

systemctl start graphite-api

四、安装grafana

grafana是个很流弊的画图软件,支持很多种数据源,展示图形也很多种。

官网下载地址:https://grafana.com/grafana/download

(1)yum本地安装,自动安装依赖包:

yum localinstall grafana-4.4.1-1.x86_64.rpm

(2)安装mysql-server并创建数据库:
由于我的grafana直接装在openstack的控制节点上,已经安装好了mysql-server,直接创建数据库:

CREATE DATABASE grafana ;
GRANT ALL PRIVILEGES ON grafana.* TO 'grafana'@'127.0.0.1' IDENTIFIED BY 'grafana';
FLUSH PRIVILEGES;

mysql在这里只是储存grafana的用户信息,dashboard信息等,不会保存监控的数据。

监控的数据是直接调用graphite-api接口读取whisper数据文件。

(3)配置文件:/etc/grafana/grafana.ini
配置url、mysql连接信息,禁止检查更新、自动发送”使用计数”给grafana,登录界面不使用用户注册功能。

[server]
root_url = http://0.0.0.0:3000
[database]
type = mysql
host = 127.0.0.1:3306
name = grafana
user = grafana
password = grafana
[analytics]
reporting_enabled = false
check_for_updates = false
[security]
[snapshots]
external_enabled = false
[users]
allow_sign_up = false

(4)启动 grafana :

/etc/init.d/grafana-server start

五、配置监控

(1)浏览器登录 grafana,默认初始用户名密码是admin/admin,在grafana.ini可配置。

(2)添加数据源:Data Sources ->Add data sources,输入自定义名称,Type选择【graphite】,url为graphite-api的地址和端口,默认本机8888端口即 【http://localhost:8888】,Access选择【proxy】,其他不填,点击保存并测试连接【Save&Test】,正常返回为绿色背景提示文字

"Success
Data source is working"

(3)至此,全部部署完成,直接在页面上添加dashboard->添加panel->编辑panel即可。

附上监控图两张:

未分类

未分类

openstack集成ceph

集成Ceph相关配置

创建Pool

# ceph osd pool create volumes 64
# ceph osd pool create images 64
# ceph osd pool create vms 64

安装Ceph Client包

配置centos7 ceph yum源

在glance-api(控制节点)节点上

yum install python-rbd -y

(计算节点)在nova-compute和cinder-volume节点上

yum install ceph-common -y

openstack安装Ceph客户端认证

集群ceph存储端操作

[root@ceph ~]# ssh controller sudo tee /etc/ceph/ceph.conf < /etc/ceph/ceph.conf

[root@ceph ~]# ssh compute sudo tee /etc/ceph/ceph.conf < /etc/ceph/ceph.conf

如果开启了cephx authentication,需要为Nova/Cinder and Glance创建新的用户,如下

ceph auth get-or-create client.cinder mon 'allow r' osd 'allow class-read object_prefix rbd_children, allow rwx pool=volumes, allow rwx pool=vms, allow rx pool=images'

ceph auth get-or-create client.glance mon 'allow r' osd 'allow class-read object_prefix rbd_children, allow rwx pool=images'

为client.cinder, client.glance添加keyring,如下

ceph auth get-or-create client.glance | ssh controller sudo tee /etc/ceph/ceph.client.glance.keyring

ssh controller sudo chown glance:glance /etc/ceph/ceph.client.glance.keyring



ceph auth get-or-create client.cinder | ssh compute sudo tee /etc/ceph/ceph.client.cinder.keyring

ssh compute sudo chown cinder:cinder /etc/ceph/ceph.client.cinder.keyring

为nova-compute节点上创建临时密钥

ceph auth get-key client.cinder | ssh {your-compute-node} tee client.cinder.key

此处为

ceph auth get-key client.cinder | ssh compute tee client.cinder.key

在所有计算节点上(本例就只有一台计算节点)执行如下操作:在计算节点上为libvert替换新的key

uuidgen
536f43c1-d367-45e0-ae64-72d987417c91

cat > secret.xml <<EOF

粘贴以下内容,注意将红色key替换为新生成的key。

<secret ephemeral='no' private='no'>
<uuid>536f43c1-d367-45e0-ae64-72d987417c91</uuid>
<usage type='ceph'>
<name>client.cinder secret</name>
</usage>
</secret>

EOF
virsh secret-define --file secret.xml

以下—base64 后的秘钥为计算节点上/root目录下的client.cinder.key。是之前为计算节点创建的临时秘钥文件

virsh secret-set-value  536f43c1-d367-45e0-ae64-72d987417c91  AQCliYVYCAzsEhAAMSeU34p3XBLVcvc4r46SyA==
[root@compute ~]#rm –f client.cinder.key secret.xml

Openstack配置

在控制节点操作

vim /etc/glance/glance-api.conf
[DEFAULT]

…

default_store = rbd
show_image_direct_url = True
show_multiple_locations = True

…

[glance_store]
stores = rbd
default_store = rbd
rbd_store_pool = images
rbd_store_user = glance
rbd_store_ceph_conf = /etc/ceph/ceph.conf
rbd_store_chunk_size = 8





取消Glance cache管理,去掉cachemanagement

[paste_deploy]
flavor = keystone

在计算节点操作

vim /etc/cinder/cinder.conf



[DEFAULT]

保留之前的

enabled_backends = ceph
#glance_api_version = 2
…

[ceph]

volume_driver = cinder.volume.drivers.rbd.RBDDriver
rbd_pool = volumes
rbd_ceph_conf = /etc/ceph/ceph.conf
rbd_flatten_volume_from_snapshot = false
rbd_max_clone_depth = 5
rbd_store_chunk_size = 4
rados_connect_timeout = -1
glance_api_version = 2
rbd_user = cinder
volume_backend_name = ceph
rbd_secret_uuid =536f43c1-d367-45e0-ae64-72d987417c91

请注意,每个计算节点uuid不同。按照实际情况填写。本例只有一个计算节点

注意,如果配置多个cinder后端,glance_api_version = 2必须添加到[DEFAULT]中。本例注释了

每个计算节点上,设置/etc/nova/nova.conf

vim /etc/nova/nova.conf

[libvirt]
virt_type = qemu
hw_disk_discard = unmap
images_type = rbd
images_rbd_pool = vms
images_rbd_ceph_conf = /etc/ceph/ceph.conf
rbd_user = cinder
rbd_secret_uuid = 536f43c1-d367-45e0-ae64-72d987417c91
disk_cachemodes="network=writeback"
libvirt_inject_password = false
libvirt_inject_key = false
libvirt_inject_partition = -2
live_migration_flag=VIR_MIGRATE_UNDEFINE_SOURCE, VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_LIVE, VIR_MIGRATE_TUNNELLED

重启OpenStack

控制节点

systemctl restart openstack-glance-api.service

计算节点

systemctl restart openstack-nova-compute.service openstack-cinder-volume.service

配置文件

1、nova

[root@controller nova]# cat nova.conf
[DEFAULT]
enabled_apis = osapi_compute,metadata
rpc_backend = rabbit
auth_strategy = keystone
my_ip = 192.168.8.100
use_neutron = True
firewall_driver = nova.virt.firewall.NoopFirewallDriver
[api_database]
connection = mysql+pymysql://nova:Changeme_123@controller/nova_api
[barbican]
[cache]
[cells]
[cinder]
os_region_name = RegionOne
[conductor]
[cors]
[cors.subdomain]
[database]
connection = mysql+pymysql://nova:Changeme_123@controller/nova
[ephemeral_storage_encryption]
[glance]
api_servers = http://controller:9292
[guestfs]
[hyperv]
[image_file_url]
[ironic]
[keymgr]
[keystone_authtoken]
auth_uri = http://controller:5000
auth_url = http://controller:35357
memcached_servers = controller:11211
auth_type = password
project_domain_name = default
user_domain_name = default
project_name = service
username = nova
password = Changeme_123
[libvirt]
[libvirt]
virt_type = qemu
hw_disk_discard = unmap
images_type = rbd
images_rbd_pool = nova
images_rbd_ceph_conf = /etc/cinder/ceph.conf
rbd_user = cinder
rbd_secret_uuid = 457eb676-33da-42ec-9a8c-9293d545c337
disk_cachemodes="network=writeback"
libvirt_inject_password = false
libvirt_inject_key = false
libvirt_inject_partition = -2
live_migration_flag=VIR_MIGRATE_UNDEFINE_SOURCE, VIR_MIGRATE_PEER2PEER, VIR_MIGRATE_LIVE, VIR_MIGRATE_TUNNELLED
[matchmaker_redis]
[metrics]
[neutron]
url = http://controller:9696
auth_url = http://controller:35357
auth_type = password
project_domain_name = default
user_domain_name = default
region_name = RegionOne
project_name = service
username = neutron
password = Changeme_123
service_metadata_proxy = True
metadata_proxy_shared_secret = Changeme_123
[osapi_v21]
[oslo_concurrency]
lock_path = /var/lib/nova/tmp
[oslo_messaging_amqp]
[oslo_messaging_notifications]
[oslo_messaging_rabbit]
rabbit_host = controller
rabbit_userid = openstack
rabbit_password = Changeme_123
[oslo_middleware]
[oslo_policy]
[rdp]
[serial_console]
[spice]
[ssl]
[trusted_computing]
[upgrade_levels]
[vmware]
[vnc]
vncserver_listen = 0.0.0.0
vncserver_proxyclient_address = 192.168.8.100
enabled = True
novncproxy_base_url = http://192.168.8.100:6080/vnc_auto.html
[workarounds]
[xenserver]

cinder

[root@controller nova]# cat /etc/cinder/cinder.conf
[DEFAULT]
rpc_backend = rabbit
auth_strategy = keystone
my_ip = 192.168.8.100
glance_host = controller
enabled_backends = lvm,ceph
glance_api_servers = http://controller:9292
[BACKEND]
[BRCD_FABRIC_EXAMPLE]
[CISCO_FABRIC_EXAMPLE]
[COORDINATION]
[FC-ZONE-MANAGER]
[KEYMGR]
[cors]
[cors.subdomain]
[database]
connection = mysql+pymysql://cinder:Changeme_123@controller/cinder
[keystone_authtoken]
auth_uri = http://controller:5000
auth_url = http://controller:35357
memcached_servers = controller:11211
auth_type = password
project_domain_name = default
user_domain_name = default
project_name = service
username = cinder
password = Changeme_123
[matchmaker_redis]
[oslo_concurrency]
lock_path = /var/lib/cinder/tmp
[oslo_messaging_amqp]
[oslo_messaging_notifications]
[oslo_messaging_rabbit]
rabbit_host = controller
rabbit_userid = openstack
rabbit_password = Changeme_123
[oslo_middleware]
[oslo_policy]
[oslo_reports]
[oslo_versionedobjects]
[ssl]
[lvm]
volume_driver = cinder.volume.drivers.lvm.LVMVolumeDriver
volume_group = cinder-volumes
iscsi_protocol = iscsi
iscsi_helper = lioadm
[ceph]
volume_driver = cinder.volume.drivers.rbd.RBDDriver
rbd_pool = cinder
rbd_ceph_conf = /etc/cinder/ceph.conf
rbd_flatten_volume_from_snapshot = false
rbd_max_clone_depth = 5
rbd_store_chunk_size = 4
rados_connect_timeout = -1
glance_api_version = 2
rbd_user = cinder
rbd_secret_uuid =457eb676-33da-42ec-9a8c-9293d545c337
volume_backend_name = ceph

glance

[root@controller nova]# cat /etc/glance/glance-api.conf

[DEFAULT]
#default_store = rbd
show_image_direct_url = True
#show_multiple_locations = True
[cors]
[cors.subdomain]
[database]
connection = mysql+pymysql://glance:Changeme_123@controller/glance
[glance_store]
stores = rbd
default_store = rbd
rbd_store_pool = glance
rbd_store_user = glance
rbd_store_ceph_conf = /etc/glance/ceph.conf
rbd_store_chunk_size = 8
[image_format]
[keystone_authtoken]
auth_uri = http://controller:5000
auth_url = http://controller:35357
memcached_servers = controller:11211
auth_type = password
project_domain_name = default
user_domain_name = default
username = glance
password = Changeme_123
project_name = service
[matchmaker_redis]
[oslo_concurrency]
[oslo_messaging_amqp]
[oslo_messaging_notifications]
[oslo_messaging_rabbit]
[oslo_policy]
[paste_deploy]
flavor = keystone
[profiler]
[store_type_location_strategy]
[task]
[taskflow_executor]

ceph

[root@controller nova]# cat /etc/cinder/cinder.conf
[DEFAULT]
rpc_backend = rabbit
auth_strategy = keystone
my_ip = 192.168.8.100
glance_host = controller
enabled_backends = lvm,ceph
glance_api_servers = http://controller:9292
[BACKEND]
[BRCD_FABRIC_EXAMPLE]
[CISCO_FABRIC_EXAMPLE]
[COORDINATION]
[FC-ZONE-MANAGER]
[KEYMGR]
[cors]
[cors.subdomain]
[database]
connection = mysql+pymysql://cinder:Changeme_123@controller/cinder
[keystone_authtoken]
auth_uri = http://controller:5000
auth_url = http://controller:35357
memcached_servers = controller:11211
auth_type = password
project_domain_name = default
user_domain_name = default
project_name = service
username = cinder
password = Changeme_123
[matchmaker_redis]
[oslo_concurrency]
lock_path = /var/lib/cinder/tmp
[oslo_messaging_amqp]
[oslo_messaging_notifications]
[oslo_messaging_rabbit]
rabbit_host = controller
rabbit_userid = openstack
rabbit_password = Changeme_123
[oslo_middleware]
[oslo_policy]
[oslo_reports]
[oslo_versionedobjects]
[ssl]
[lvm]
volume_driver = cinder.volume.drivers.lvm.LVMVolumeDriver
volume_group = cinder-volumes
iscsi_protocol = iscsi
iscsi_helper = lioadm
[ceph]
volume_driver = cinder.volume.drivers.rbd.RBDDriver
rbd_pool = cinder
rbd_ceph_conf = /etc/cinder/ceph.conf
rbd_flatten_volume_from_snapshot = false
rbd_max_clone_depth = 5
rbd_store_chunk_size = 4
rados_connect_timeout = -1
glance_api_version = 2
rbd_user = cinder
rbd_secret_uuid =457eb676-33da-42ec-9a8c-9293d545c337
volume_backend_name = ceph
[root@controller nova]# cat /etc/glance/glance-api.conf
[DEFAULT]
#default_store = rbd
show_image_direct_url = True
#show_multiple_locations = True
[cors]
[cors.subdomain]
[database]
connection = mysql+pymysql://glance:Changeme_123@controller/glance
[glance_store]
stores = rbd
default_store = rbd
rbd_store_pool = glance
rbd_store_user = glance
rbd_store_ceph_conf = /etc/glance/ceph.conf
rbd_store_chunk_size = 8
[image_format]
[keystone_authtoken]
auth_uri = http://controller:5000
auth_url = http://controller:35357
memcached_servers = controller:11211
auth_type = password
project_domain_name = default
user_domain_name = default
username = glance
password = Changeme_123
project_name = service
[matchmaker_redis]
[oslo_concurrency]
[oslo_messaging_amqp]
[oslo_messaging_notifications]
[oslo_messaging_rabbit]
[oslo_policy]
[paste_deploy]
flavor = keystone
[profiler]
[store_type_location_strategy]
[task]
[taskflow_executor]

[root@controller nova]# cat /etc/cinder/ceph.conf
[global]
heartbeat interval = 5
osd pool default size = 3
osd heartbeat grace = 10
#keyring = /etc/ceph/keyring.admin
mon osd down out interval = 90
fsid = 5e8080b0-cc54-11e6-b346-000c29976397
osd heartbeat interval = 10
max open files = 131072
auth supported = cephx

[mon]
mon osd full ratio = .90
mon data = /var/lib/ceph/mon/mon$id
mon osd nearfull ratio = .75
mon clock drift allowed = .200
mon osd allow primary affinity = true

[mon.0]
host = csm-node1
mon addr = 192.168.8.102:6789

[mon.1]
host = csm-node2
mon addr = 192.168.8.103:6789

[mon.2]
host = csm-node3
mon addr = 192.168.8.104:6789

[osd]
osd mount options xfs = rw,noatime,inode64,logbsize=256k,delaylog
osd crush update on start = false
filestore xattr use omap = true
#keyring = /etc/ceph/keyring.$name
osd mkfs type = xfs
osd data = /var/lib/ceph/osd/osd$id
osd heartbeat interval = 10
osd heartbeat grace = 10
osd mkfs options xfs = -f
osd journal size = 0

[osd.0]
osd journal = /dev/sdb1
devs = /dev/sdb2
host = csm-node1
cluster addr = 192.168.8.102
public addr = 192.168.8.102

[osd.1]
osd journal = /dev/sdb1
devs = /dev/sdb2
host = csm-node2
cluster addr = 192.168.8.103
public addr = 192.168.8.103

[osd.2]
osd journal = /dev/sdb1
devs = /dev/sdb2
host = csm-node3
cluster addr = 192.168.8.104
public addr = 192.168.8.104

[client.cinder]
keyring=/etc/ceph/ceph.client.cinder.keyring

Ceph出现”1 full osd(s)”,整个集群不可用的问题调查

问题描述

一个服务连接不上ceph的对象存储网关,重启ceph对象存储网关,也不生效。

ceph服务网关的日志如下:

2017-10-31 19:51:21.158008 7f3b789b99c0  0 deferred set uid:gid to 167:167 (ceph:ceph)
2017-10-31 19:51:21.158206 7f3b789b99c0  0 ceph version 10.2.7 (50e863e0f4bc8f4b9e31156de690d765af245185), process radosgw, pid 1321
2017-10-31 19:51:21.244854 7f3b789b99c0  0 client.34193.objecter  FULL, paused modify 0x7f3b7a1388d0 tid 0
2017-10-31 19:56:21.158388 7f3b5dc9b700 -1 Initialization timeout, failed to initialize
2017-10-31 19:56:21.410096 7f918b9bb9c0  0 deferred set uid:gid to 167:167 (ceph:ceph)
2017-10-31 19:56:21.410202 7f918b9bb9c0  0 ceph version 10.2.7 (50e863e0f4bc8f4b9e31156de690d765af245185), process radosgw, pid 1459
2017-10-31 19:56:21.546455 7f918b9bb9c0  0 client.34214.objecter  FULL, paused modify 0x7f918d689c70 tid 0

使用ceph health查看发现:

$ ceph health
1 full osd(s); pool default.rgw.buckets.data has many more objects per pg than average (too few pgs?); full flag(s) set;

问题解决

Ceph集群磁盘没有剩余空间的解决方法 (http://blog.csdn.net/xiaoquqi/article/details/45539847) 提到:

根据Ceph官方文档中的描述,当一个OSD full比例达到95%时,集群将不接受任何Ceph Client端的读写数据的请求。

通过命令ceph osd df,发现一个osd使用空间超过95:

$ ceph osd df
ID WEIGHT  REWEIGHT SIZE  USE    AVAIL  %USE  VAR  PGS
 0 0.48799  1.00000  499G   295G   204G 59.17 1.32  47
 5 0.97609  1.00000  999G 56253M   944G  5.50 0.12  84
 1 0.48799  1.00000  499G   341G   158G 68.33 1.53  64
 6 0.48318  1.00000  494G 42432k   494G  0.01    0  49
 2 0.48799  1.00000  499G   474G 25533M 95.01 2.13  78
 3 0.48799  1.00000  499G   204G   295G 40.92 0.92  68
 4 0.48799  1.00000  499G   411G 89998M 82.41 1.85  74
              TOTAL 3993G  1783G  2209G 44.66

虽然ceph full或者nearfull的解决方法探究 (https://www.itzhoulin.com/2016/04/20/deal_with_ceph_full/) 也提到,可以先将full的比例提高到98%。但是执行时发现不可更改:

$ ceph tell osd.* injectargs '--mon-osd-full-ratio 0.98'
osd.0: mon_osd_full_ratio = '0.98' (unchangeable)
osd.1: mon_osd_full_ratio = '0.98' (unchangeable)
osd.2: mon_osd_full_ratio = '0.98' (unchangeable)
osd.3: mon_osd_full_ratio = '0.98' (unchangeable)
osd.4: mon_osd_full_ratio = '0.98' (unchangeable)

增加了两块OSD之后,经过了漫长的数据重新分布:

$ ceph health
HEALTH_ERR clock skew detected on mon.registry-ceph02, mon.registry-ceph03; 21 pgs backfill_wait; 2 pgs backfilling; 7 pgs degraded; 6 pgs recovery_wait; 7 pgs stuck degraded; 29 pgs stuck unclean; 1 pgs stuck undersized; 1 pgs undersized; recovery 41684/1371951 objects degraded (3.038%); recovery 694899/1371951 objects misplaced (50.650%); 1 full osd(s); pool default.rgw.buckets.data has many more objects per pg than average (too few pgs?); full flag(s) set; Monitor clock skew detected

当osd使用比例下降到95%以下后,集群恢复正常。

OSD添加方法: http://www.lijiaocn.com/%E6%8A%80%E5%B7%A7/2017/06/01/ceph-deploy.html#%E6%B7%BB%E5%8A%A0osd

使用 Haproxy + Keepalived 构建基于 Docker 的高可用负载均衡服务(一)

适合具有 Docker 和 Bash 相关基础的开发、运维等同学。本文没有太过深入的介绍,也并没有用到一些高级特性,仅适合用来作为一个基础科普文来阅读。

背景

最近在搭新的 Coding 内部测试环境,老大说把以前使用 nginx 插件来做的 LB(Load balancing) 全部换成 HAProxy 来做。经过几天的不断“查阅资料”,简单实现了该服务的动态构建。

本文循序渐进按照以下几个层次来讲:

  • HAProxy 与 Keepalived 的简单介绍
    • HAProxy 介绍

    • Keepalived 介绍

  • 搭建 haproxy + keepalived 服务过程

    • 搭建业务服务

    • 使用 HAProxy 做业务服务的高可用和负载均衡

    • 使用 Keepalived 做 HAProxy 服务的高可用

环境准备:

  • 五台 Linux 主机

未分类

  • 一个虚拟的 IP

192.168.0.146(一个内网没人用的 IP)

HAProxy 与 Keepalived 简单介绍

HAProxy 是一个提供高可用、负载均衡和基于 HTTP/TCP 应用代理的解决方案。

Keepalived 是用 C 编写的路由软件,主要目标是为 Linux 系统及基于 Linux 的设施提供强大的高可用性和负载均衡。

在本文中,HAProxy 我们用来做 HTTP/TCP 应用的 HA + LB 方案,Keepalived 被用来做 HAProxy 的 HA 方案。下边是对两者的简单介绍和简单使用。

HAProxy

关于 HAProxy 的一些概念限于篇幅的原因不再详细说了,可以参考这篇文章: https://www.digitalocean.com/community/tutorials/an-introduction-to-haproxy-and-load-balancing-concepts

下边仅会介绍我们会使用到的一些概念。

HAProxy 的 Proxy 配置可以分为如下几个部分( http://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4 ):

  • defaults []
  • frontend
  • backend
  • listen

其中 defaults 包含一些全局的默认环境变量,frontend 定义了如何把数据 forward 到 backend,backend 描述了一组接收 forward 来的数据的后端服务。listen 则把 frontend 和 backend 组合到了一起,定义出了一个完整的 proxy。

未分类

下面是一段简单的 HAProxy 的配置:

listen app1-cluster
    bind *:4000
    mode http
    maxconn 300
    balance roundrobin
    server server1 192.168.0.189:4004 maxconn 300 check
    server server2 192.168.0.190:4004 maxconn 300 check
    server server3 192.168.0.191:4004 maxconn 300 check

listen app2-cluster
    bind *:5000
    mode http
    maxconn 300
    balance roundrobin
    server server1 192.168.0.189:5555 maxconn 300 check
    server server2 192.168.0.190:5555 maxconn 300 check
    server server3 192.168.0.191:5555 maxconn 300 check

我们在 HAProxy 的配置文件中定义了两个 listen 模块,分别监听在 4000、5000 端口。监听在 4000 端口的模块,使用 roundrobin (轮询)负载均衡算法,把请求分发到了三个后端服务。

Keepalived

关于 Keepalived 的详细介绍可以参考: http://keepalived.readthedocs.io/en/latest/introduction.html

Keepalived 是一个用于负载均衡和高可用的路由软件。

其负载均衡(Load balancing)的特性依赖于 Linux 虚拟服务器(LVS)的 IPVS 内核模块,提供了 Layer 4 负载均衡器(TCP 层级,Layer 7 是 HTTP 层级,即计算机网络中的OSI 七层网络模型与 TCP/IP 四层网络模型)。

Keepalived 实现了虚拟冗余路由协议(VRRP, Virtual Redundancy Routing Protoco),VRRP 是路由故障切换(failover)的基础。

简单来说,Keepalived 主要提供两种功能:

  • 依赖 IPVS 实现服务器的健康检查;
  • 实现 VRRPv2 协议来处理路由的故障切换。

我们接下来会用个简单的配置来描述后者的工作原理:

在 haproxy-master 机器上:

vrrp_script chk_haproxy {
    script "killall -0 haproxy" # verify haproxy's pid existance
    interval 2 # check every 2 seconds
    weight -2 # if check failed, priority will minus 2
}

vrrp_instance VI_1 {
    state MASTER # Start-up default state
    interface ens18 # Binding interface
    virtual_router_id 51 # VRRP VRID(0-255), for distinguish vrrp's multicast
    priority 105 # VRRP PRIO
    virtual_ipaddress { # VIP, virtual ip
        192.168.0.146
    }
    track_script { # Scripts state we monitor
        chk_haproxy              
    }
}

在 haproxy-backup 机器上:

vrrp_script chk_haproxy {
   script "killall -0 haproxy"
    interval 2
    weight -2
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens18
    virtual_router_id 51
    priority 100
    virtual_ipaddress {
        192.168.0.146
    }
    track_script {             
        chk_haproxy              
    }
}

我们为两台机器(master、backup)安装了 Keepalived 服务并设定了上述配置。

可以发现,我们绑定了一个虚拟 IP (VIP, virtual ip): 192.168.0.146,在 haproxy-master + haproxy-backup 上用 Keepalived 组成了一个集群。在集群初始化的时候,haproxy-master 机器的 被初始化为 MASTER。

间隔 2 seconds() 会定时执行 <script>脚本 ,每个 会记录脚本的 exit code。

关于 参数的使用:

  • 检测失败,并且 weight 为正值:无操作
  • 检测失败,并且 weight 为负值:priority = priority – abs(weight)
  • 检测成功,并且 weight 为正值:priority = priority + weight
  • 检测成功,并且 weight 为负值:无操作

weight 默认值为 0,对此如果感到迷惑可以参考:HAProxy github code

故障切换工作流程:

  • 当前的 MASTER 节点 <script> 脚本检测失败后,如果“当前 MASTER 节点的 priority” < “当前 BACKUP 节点的 priority” 时,会发生路由故障切换。
  • 当前的 MASTER 节点脚本检测成功,无论 priority 是大是小,不会做故障切换。

其中有几处地方需要注意:

  • 一个 Keepalived 服务中可以有个 0 个或者多个 vrrp_instance
  • 可以有多个绑定同一个 VIP 的 Keepalived 服务(一主多备),本小节中只是写了两个
  • 注意 ,同一组 VIP 绑定的多个 Keepalived 服务的 必须相同;多组 VIP 各自绑定的 Keepalived 服务一定与另外组不相同。否则前者会出现丢失节点,后者在初始化的时候会出错。

关于 Keepalived 各个参数代表含义的问题,可以同时参考下文与 Github 代码文档来看:

  • keepalived工作原理和配置说明: http://outofmemory.cn/wiki/keepalived-configuration

  • Github keepalived.conf.SYNOPSIS: https://github.com/acassen/keepalived/blob/master/doc/keepalived.conf.SYNOPSIS

搭建 haproxy + keepalived 服务过程

搭建业务服务

我们在 host-1、host-2、host-3 三台机器上,每台机器的 4004、5555 端口分别启起来一个服务,服务打印一段字符串,用来模拟业务集群中的三个实例。

如下所示:

  • 192.168.0.189/host-1

4004 端口:

未分类

5555 端口:

未分类

  • 192.168.0.190/host-2

4004 端口:

未分类

5555 端口:

未分类

  • 192.168.0.191/host-3

4004 端口:

未分类

5555 端口:

未分类

如上所示,我们在三台机器上搭建了两个集群,结构如下图所示:

未分类

使用 HAProxy 做业务服务的高可用和负载均衡

我们现在有两台机器:haproxy-master、haproxy-backup,本小节的目标是在这两台机器上分别搭一套相同的 HAProxy 服务。(为了方便,下边直接用 Docker 做了)

我们直接使用了 haproxy:1.7.9 版本的 Docker 镜像,下边是具体的步骤:

coding@haproxy-master:~/haproxy$ tree .
.
├── Dockerfile
└── haproxy.cfg

0 directories, 2 files

coding@haproxy-master:~/haproxy$ cat Dockerfile
FROM haproxy:1.7.9

COPY haproxy.cfg /usr/local/etc/haproxy/

coding@haproxy-master:~/haproxy$ cat haproxy.cfg
global
    daemon
    maxconn 30000
    log 127.0.0.1 local0 info
    log 127.0.0.1 local1 warning

defaults
    mode http
    option http-keep-alive
    option httplog
    timeout connect 5000ms
    timeout client 10000ms
    timeout server 50000ms
    timeout http-request 20000ms

#  custom your own frontends && backends && listen conf
# CUSTOM

listen app1-cluster
    bind *:4000
    mode http
    maxconn 300
    balance roundrobin
    server server1 192.168.0.189:4004 maxconn 300 check
    server server2 192.168.0.190:4004 maxconn 300 check
    server server3 192.168.0.191:4004 maxconn 300 check

listen app2-cluster
    bind *:5000
    mode http
    maxconn 300
    balance roundrobin
    server server1 192.168.0.189:5555 maxconn 300 check
    server server2 192.168.0.190:5555 maxconn 300 check
    server server3 192.168.0.191:5555 maxconn 300 check

listen stats
    bind *:1080
    stats refresh 30s
    stats uri /stats

在完成上述代码后,我们可以构建我们自己的 Docker 镜像,并运行它:

coding@haproxy-master:~/haproxy$ docker build -t custom-haproxy:1.7.9 .
Sending build context to Docker daemon 3.584kB
Step 1/2 : FROM haproxy:1.7.9
1.7.9: Pulling from library/haproxy
85b1f47fba49: Pull complete
3dee1a596b5f: Pull complete
259dba5307a2: Pull complete
9d51568f5880: Pull complete
d2c6077a1eb7: Pull complete
Digest: sha256:07579aed81dc9592a3b7697d0ea116dea7e3dec18e29f1630bc2c399f46ada8e
Status: Downloaded newer image for haproxy:1.7.9
 ---> 4bb854517f75
Step 2/2 : COPY haproxy.cfg /usr/local/etc/haproxy/
 ---> 4e846d42d719
Successfully built 4e846d42d719
Successfully tagged custom-haproxy:1.7.9

coding@haproxy-master:~/haproxy$ docker run -it --net=host --privileged --name haproxy-1 -d custom-haproxy:1.7.9
fb41ab81d2140af062708e5b84668b7127014eb9ae274e4c2761d06e2f6d7950

通过命令 docker ps -a 我们可以看到,容器已经正常运行了,接下来我们在 web 端打开相应的地址可以看到所有服务的状态:

未分类

我们刚才在 haproxy-master 机器上搭建了一个 haproxy 服务,在其 4000、5000 端口绑定了两个业务集群。我们在浏览器访问:http://192.168.0.144:4000/、http://192.168.0.144:5000/ ,并且重复刷新即可看到会打印不同的 JSON 出来。可以证明我们请求确实是分发到了业务集群的几个实例中。

接下来,还要在 haproxy-backup 上搭建一个一模一样的 HAProxy 服务,步骤同上。

使用 Keepalived 做 HAProxy 服务的高可用

在上一小节中,我们在 haproxy-master、haproxy-backup 两台机器上搭了两套相同的 HAProxy 服务。我们希望在一个连续的时间段,只由一个节点为我们提供服务,并且在这个节点挂掉后另外一个节点能顶上。

本小节的目标是在haproxy-master、haproxy-backup 上分别搭 Keepalived 服务,并区分主、备节点,以及关停掉一台机器后保证 HAProxy 服务仍然正常运行。

使用如下命令安装 Keepalived:

coding@haproxy-master:~$ sudo apt-get install keepalived
coding@haproxy-master:~/haproxy$ keepalived -v
Keepalived v1.2.19 (03/13,2017)

我们在 haproxy-master 机器上,增加如下配置:

coding@haproxy-master:~$ cat /etc/keepalived/keepalived.conf
vrrp_script chk_haproxy {
    script "killall -0 haproxy"
    interval 2                   
}

vrrp_instance VI_1 {
    state MASTER                 
    interface ens18              
    virtual_router_id 51        
    priority 105                
    virtual_ipaddress {         
        192.168.0.146
    }
    track_script {
        chk_haproxy
    }
}

在 haproxy-backup 机器上增加如下配置:

coding@haproxy-backup:~$ cat /etc/keepalived/keepalived.conf
vrrp_script chk_haproxy {
    script "killall -0 haproxy"
    interval 2
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens18
    virtual_router_id 51
    priority 100
    virtual_ipaddress {
        192.168.0.146
    }
    track_script {
        chk_haproxy
    }
}

在配置结束之后,我们分别重启两台机器上的 Keepalived 服务:

oot@haproxy-master:~# systemctl restart keepalived

(注:不同的发行版命令不同,本文基于 Ubuntu 16.04)

此时我们的 Keepalived 服务就搭建完成了,VIP 是 192.168.0.146。此时我们通过浏览器访问:http://192.168.0.146:1080/stats,即可看到 HAProxy 服务的状态。

我们也可以通过 ssh [email protected] 看目前 MASTER 节点为哪台机器。ssh 后发现目前的 MASTER 节点为 haproxy-master 机器,我现在把这台机器上的 haproxy 服务停掉:

root@haproxy-master:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fb41ab81d214 custom-haproxy:1.7.9 "/docker-entrypoin..." About an hour ago Up 1 second haproxy-1
root@haproxy-master:~# docker stop fb41ab81d214
fb41ab81d214

然后我们访问:http://192.168.0.146:1080/stats,会在稍微停顿下后仍然能显示出来 haproxy 服务的状态。我们再 ssh [email protected] 后,发现我们进入了 haproxy-backup 机器上。此时的 MASTER 节点就是 haproxy-backup 机器。

以此来看,我们已经搭建出来了一个简单的 HAProxy + Keepalived 服务了。整体结构图如下所示:

未分类

结尾

有一点需要注意,容易混淆:

区分主节点、备节点是 Keepalived 服务来做的,HAProxy 在所有节点上的配置应该是相同的。

Ubuntu 16.04 配置 Let’s Encrypt 实现站点 SSL

Let’s Encrypt 的服务相信很多人都知道了,我个人认为这是最好的免费 SSL 服务。下面内容即使如何在自己的网站上使用 Let’s Encrypt 实现 SSL.

前提条件

  • 自己拥有一个域名,备案了的域名最好。

  • Ubuntu 16.04 的服务器,你可以到腾讯云或者阿里云购买这样的云主机。

  • 将域名自己解析到你的 Ubuntu 16.04 的云主机 ip;注意如果你的域名没备案,在购买主机的时候,推荐大家购买腾讯云或者阿里云境外的主机。

1. 安装 Certbot

Certbot 其实就是维护 Let’s Encrypt 的 Package,在 Ubuntu 16.04 上,我们可以这样安装:

首先安装 Nginx:

sudo apt-get install nginx

以上过程,等待安装完毕就好。

然后添加 package repository

sudo add-apt-repository ppa:certbot/certbot

这个过程中,等待验证完毕,按下 ENTER 就好。然后更新 apt 源数据:

sudo apt-get update

最后,安装 Certbot 的 Nginx package:

sudo apt-get install python-certbot-nginx

2. 配置 Nginx

安装完 Nginx 和 Certbot 之后,需要简单配置 Nginx 以便于 Let’s Encrypt 能起作用:

sudo vi /etc/nginx/sites-available/default

使用 vi 编辑器打开 /etc/nginx/sites-available/default,可以直接删除里面的所有内容,然后再添加下面的配置:

server {
    listen 80;
    listen [::]:80;
    server_name your-domain.com www.your-domain.com;
}

注意这里的 your-domain.com 换成你自己的域名。

保存退出之后,执行以下命令来检测 Nginx 的配置文件是否有错:

sudo nginx -t

如果出现类似 syntax ok 这样的语句,就说明 Nginx 的配置文件没有问题。之后就是重新加载 Nginx 的配置文件了:

sudo service nginx reload

3. 签发 SSL 证书

前面的两大步配置完成,就可以使用 Let’s Encrypt 签发 SSL 证书了:

sudo certbot --nginx -d your-domian.com -d www.your-domain.com

注意这里的 your-domain.com 换成你自己的域名。

如果你第一次运行 certbot 命令的话,你需要在弹出的窗口输入你的邮箱地址还有需要接受 Let’s Encrypt 的协议,这样之后,你大概会看到下面的文字:

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
-------------------------------------------------------------------------------
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

在上面这里选择 1 或者 2,我推荐大家直接选择 2,因为这个会直接将你的 nginx 文件配置好并且是会将 http 跳转到 https 的。

选择完毕之后,等待 SSL 生成完毕,就会有类似这样的输出:

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/your-domain.com/fullchain.pem. Your cert will
   expire on 2017-12-29. To obtain a new or tweaked version of this
   certificate in the future, simply run certbot again with the
   "certonly" option. To non-interactively renew *all* of your
   certificates, run "certbot renew"
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

然后在上面的文字中,这个 /etc/letsencrypt/live/your-domain.com/fullchain.pem 路径很重要,就是你的 SSL 证书路径。

其实到这里,访问 your-domain.com 应该就可以看到 https 的效果了。

4. 自动更新证书

因为 Let’s Encrypt 签发的 SSL 证书有效期只有 90 天,所有在过期之前,我们需要自动更新 SSL 证书,而如果你使用最新的 certbot 的话,Let’s Encrypt 会帮你添加自动更新的脚本到 /etc/cron.d 里,你只需要去检测一下这个命令是否生效就OK!

sudo certbot renew --dry-run

如果这个命令你没看到什么 error 的话,那就是没什么问题了。

5. 总结

本文主要是介绍了在 Ubuntu 16.04 的云服务器上,使用 Nginx 作为服务器软件情况下,如何配置 Let’s Encrypt 的 SSL 证书,使得网站得以支持 https 的过程。内容很浅,但是我觉得还是挺有用的。

ubuntu安装nodejs并升级到最新版本

ubuntu版本信息如下:

Linux muir 4.13.0-16-generic #19-Ubuntu SMP Wed Oct 11 18:35:14 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

nodejs最新版本为:8.8.1

一、安装之前首先update

sudo apt-get update
sudo apt-get upgrade

二、安装nodejs

sudo apt-get install nodejs-dev
sudo apt-get install npm

三、查看版本

node -v
npm -v

可以看到版本是6.xxx.xx

四、升级node版本

sudo npm cache clean -f
sudo npm install -g n
sudo n stable

未分类

再看版本号:

未分类

Ubuntu配置和修改IP地址

配置Ubuntu的IP地址

鉴于目前的工作中需要经常配置Ubuntu的IP地址,所以百度一番之后发现了一个比较不错的文章,故此抄袭之。

第一步

sudo vi /etc/network/interfaces

auto eth0                  #设置自动启动eth0接口
iface eth0 inet static     #配置静态IP
address 192.168.1.100      #IP地址
netmask 255.255.255.0      #子网掩码
gateway 192.168.1.1        #默认网关

第二步

很多人都会第一步,但是会经常忽略第二部,我经常也会配置nameserver在resolve.conf文件中。

配置这个文件有什么问题呢?如果你一直不关机的话是没有问题。但是能一直不关么?显然不能。

sudo vi /etc/resolvconf/resolv.conf.d/base
# 在这个文件中添加以下内容,然后保存退出
nameserver 8.8.8.8
nameserver 114.114.114.114

第三步

重启网络

sudo /etc/init.d/networking restart

禁用 Ubuntu 自动挂载功能

打开终端

禁止自动挂载:

$ gsettings set org.gnome.desktop.media-handling automount false

禁止自动挂载并打开

$ gsettings set org.gnome.desktop.media-handling automount-open false

允许自动挂载

$ gsettings set org.gnome.desktop.media-handlingautomount true

允许自动挂载并打开

$ gsettings set org.gnome.desktop.media-handling automount-open true