实战Kubernetes动态卷存储(NFS)

之前的《 Kubernetes持久卷实战两部曲》系列中,我们实战了先声明一个存储卷,再使用这个存储卷,这种方式要求每次都要提前申明存储,不是很方便,而动态卷存储不需要提前申明,而是使用时自动申明,今天我们就来一起实战;

原文地址:https://blog.csdn.net/boling_cavalry/article/details/79598905

本章概要

今天的实战,我们要做下列操作:

  1. 准备好NFS服务;
  2. 创建namespace;
  3. 创建NFS服务的provisioner;
  4. 创建存储类StorageClass,与刚刚创建的provisioner绑定;
  5. 创建应用Pod,此应用是个web服务,外部通过HTTP请求将二进制文件上传到服务端,存储在Pod的本地路径,而这个路径已经被挂载到NFS;
  6. 通过客户端上传文件,检查文件是否保存在NFS上;
  7. 将web应用的Pod数扩展到两个,检查动态卷存储是否自动扩展;

网络服务图

本次实战涉及到客户端、K8S、NFS等网络节点,如下图:

未分类

源码下载

您可以在GitHub下载web服务的源码,地址和链接信息如下表所示:

未分类

这个git项目中有多个目录,本次需要其中的三个,如下:

  1. 在K8S上创建Pod,service,StorageClass等资源的时候用到的各种yaml文件,存放在storageclass目录;
  2. 接收客户端上传文件的web应用,源码在k8spvdemo目录;
  3. 上传文件client工程,源码在uploadfileclient目录;

准备好NFS服务

参照 https://blog.csdn.net/boling_cavalry/article/details/79498346 搭建好NFS服务,服务器的IP地址是192.168.238.132,开放的目录/usr/local/work/nfs;

创建namespace

在能够执行kubectl的机器上执行命令kubectl create namespace bolingcavalry,即可创建本次实战要用到的namespace;

创建NFS服务的provisioner

创建provisioner对应的deployment-nfs.yaml脚本:

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: nfs-client-provisioner
  namespace: bolingcavalry
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      containers:
        - name: nfs-client-provisioner
          image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 192.168.238.132
            - name: NFS_PATH
              value: /usr/local/work/nfs
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.238.132
            path: /usr/local/work/nfs

在此文件所在目录下执行kubectl create -f deployment-nfs.yaml,即可创建NFS的provisioner的pod,创建成功后,在dashboard页面看到,如下图:

未分类

这里三处需要注意:

1、设置了NFS的共享目录后,记得执行以下命令使设置生效:

systemctl restart rpcbind.service && systemctl restart nfs.service

2、此处用到的镜像是”registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner”,这是我在阿里云的搜索到的,原本打算使用”quay.io/kubernetes_incubator/nfs-client-provisioner:v1”,但是在pull的时候报错:{“error”: “Permission Denied”},在实战过程中用了阿里云的镜像可以正常工作,没有影响;
3、环境变量中有个PROVISIONER_NAME,值为fuseim.pri/ifs,后面的StorageClass就以“fuseim.pri/ifs”作为参数来定位到此Pod作为NFS服务的提供者;

创建存储类StorageClass

1、创建provisioner对应的nfs-class.yaml脚本:

apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: fuseim.pri/ifs

2、在此文件所在目录下执行kubectl create -f nfs-class.yaml,即可创建存储类的资源,创建成功后,在dashboard页面看到,如下图:

未分类

创建web应用的Pod

存储已经准备好了,接下来制作一个web服务的应用来使用这个存储,该应用我已经做成镜像,可以直接使用;

1、创建web服务的部署脚本k8spvdemo.yaml:

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: k8spvdemo
  namespace:  bolingcavalry
spec:
  serviceName: "k8spvdemo"
  replicas: 1
  volumeClaimTemplates:
  - metadata:
      name: test 
      annotations:
        volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 2Gi 
  template:
    metadata:
     labels:
       name: k8spvdemo
    spec:
     containers:
     - name: k8spvdemo
       image: bolingcavalry/k8spvdemo:0.0.1-SNAPSHOT
       volumeMounts:
       - mountPath: "/usr/local/uploadfiles"
         name: test
       tty: true
       ports:
       - containerPort: 8080

2、在k8spvdemo.yaml文件所在目录执行命令kubectl create -f k8spvdemo.yaml,即可创建应用的Pod,如下图:

未分类

3、将应用Pod包裹成Service以便外部访问,创建服务配置文件k8spvdemo-svc.yaml:

apiVersion: v1
kind: Service
metadata:
  name: k8spvdemo
  namespace:  bolingcavalry
spec:
  type: NodePort
  ports:
       - port: 8080
         nodePort: 30010
  selector:
    name: k8spvdemo

4、在k8spvdemo.yaml文件所在目录执行命令kubectl create -f k8spvdemo-svc.yaml,即可创建服务,在dashboard页面看到服务如下图:

未分类

经历了以上四步,就把服务启动起来了,并且使用了NFS,小结出以下几个关键点需要注意:

  • 参数kind: StatefulSet表示使用了有状态资源,因为普通deployment是无法使用StorageClass资源的;
  • web工程中,收到客户端POST上来的文件后,保存在本地的/usr/local/uploadfiles目录,该目录在k8spvdemo.yaml的配置中通过volumeMounts参数挂在到StorageClass上;
  • 在k8spvdemo-svc.yaml的配置中做了端口映射,我的k8s节点机器的IP是192.168.238.130,那么通过192.168.238.130:30010就能访问到Pod服务;
  • 将springboot工程制作成镜像的方法请参考《maven构建docker镜像三部曲》系列文章;
  • 在NFS机器的/usr/local/work/nfs目录下,可以看到新创建的文件夹,如下图:

未分类

  • 在容器的事件中可以看到挂载信息,挂载的PV名称与NFS上创建的文件夹是可以对应起来的,如下图红框3所示:

未分类

服务已经准备好了,接下来试试上传文件,看应用能否正常使用动态卷存储;

运行客户端,上传本地文件到Tomcat

1、创建一个maven工程,pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.bolingcavalry</groupId>
    <artifactId>uploadfileclient</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 指明编译源代码时使用的字符编码,maven编译的时候默认使用的GBK编码, 通过project.build.sourceEncoding属性设置字符编码,告诉maven这个项目使用UTF-8来编译 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.3.5</version>
        </dependency>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpmime</artifactId>
            <version>4.3.5</version>
        </dependency>
    </dependencies>

</project>
  1. 工程中创建一个java类,源码如下:
package com.bolingcavalry;

import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.File;
import java.io.IOException;

/**
 * @Description : 上传文件的类,将本地文件POST到server
 * @Author : [email protected]
 * @Date : 2018-02-24 18:12
 */
public class UploadFileClient {

    /**
     * 文件服务的ULR
     */
    private static final String POST_URL = "http://192.168.238.130:30010//upload";

    /**
     * 要上传的本地文件的完整路径加文件名
     */
    private static final String UPLOAD_FILE_FULLPATH = "D:\temp\201802\21\abc.zip";

    public static void main(String[] args) throws Exception{
        System.out.println("start upload");
        CloseableHttpClient httpclient = HttpClients.createDefault();
        try {
            HttpPost httppost = new HttpPost(POST_URL);

            //基本的配置信息
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(200000).setSocketTimeout(200000).build();

            httppost.setConfig(requestConfig);

            //要上传的文件
            FileBody bin = new FileBody(new File(UPLOAD_FILE_FULLPATH));

            //在POST中添加一个字符串请求参数
            StringBody comment = new StringBody("This is comment", ContentType.TEXT_PLAIN);

            HttpEntity reqEntity = MultipartEntityBuilder.create().addPart("file", bin).addPart("comment", comment).build();

            httppost.setEntity(reqEntity);

            System.out.println("executing request " + httppost.getRequestLine());

            //发起POST
            CloseableHttpResponse response = httpclient.execute(httppost);

            try {

                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                    String responseEntityStr = EntityUtils.toString(response.getEntity());
                    System.out.println("response status : " + response.getStatusLine());
                    System.out.println("response content length: " + resEntity.getContentLength());
                    System.out.println("response entity str : " + responseEntityStr);
                }
                EntityUtils.consume(resEntity);
            } finally {
                response.close();
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        System.out.println("end upload");
    }
}

以上源码中,有两处要注意:
第一,POST_URL = “http://192.168.238.130:30010//upload”中的192.168.238.130是Pod所在的节点机器的IP地址,请替换为您的k8s环境中的节点IP地址;
第二,UPLOAD_FILE_FULLPATH = “D:temp20180221abc.zip”,这里配置的是要上传的本地文件的路径,请替换为您要上传的文件路径;

3、直接运行UploadFileClient.java,看到控制台输出如下信息表示上传成功:

start upload
executing request POST http://192.168.238.130:30010/upload HTTP/1.1
response status : HTTP/1.1 200 
response content length: 40
response entity str : SpringBoot环境下,上传文件成功
end upload

Process finished with exit code 0

上传成功了,在dashboard上查看容器的日志,能看到上传有关的日志如下图红框所示:

未分类

现在理论上现在文件已经保存在NFS Server的/usr/local/work/nfs目录下了,去检查一下;

去NFS Server检查上传的文件

登录NFS Server,进入/usr/local/work/nfs,查看文件信息如下图:

未分类

可见k8s上的tomcat应用可以通过动态卷存储的方式将客户端上传的文件保存在NFS服务器上;

扩展web应用的Pod数量

目前web应用的Pod数量是1,执行以下命令扩展到两个:

kubectl scale StatefulSet k8spvdemo --replicas=2 --namespace=bolingcavalry

执行完毕后,在dashboard可以看见创建的动态卷,如下图:

未分类

您可以再次上传文件,然后去NFS服务器检查是否已经创建了新的文件夹,并且存放了新的上传文件;

至此,Kubernetes动态卷存储的实战就全部完成了,希望PV&&PVC和动态存储两种方案可以帮助您在应用中解决独立存储的问题;

linux中NFS服务安全加固实例

概述

NFS 的不安全性,主要体现于以下 4 个方面:

  • 缺少访问控制机制
  • 没有真正的用户验证机制,只针对 RPC/Mount 请求进行过程验证
  • 较早版本的 NFS 可以使未授权用户获得有效的文件句柄
  • 在 RPC 远程调用中, SUID 程序具有超级用户权限

加固方案

为有效应对以上安全隐患,推荐您使用下述加固方案。

配置共享目录(/etc/exports)
使用 anonuid,anongid 配置共享目录,这样可以使挂载到 NFS 服务器的客户机仅具有最小权限。不要使用 no_root_squash。

使用网络访问控制
使用 安全组策略 或 iptable 防火墙限制能够连接到 NFS 服务器的机器范围。

iptables -A INPUT -i eth0 -p TCP -s 192.168.0.0/24 --dport 111 -j ACCEPT
iptables -A INPUT -i eth0 -p UDP -s 192.168.0.0/24 --dport 111 -j ACCEPT
iptables -A INPUT -i eth0 -p TCP -s 140.0.0.0/8 --dport 111 -j ACCEPT
iptables -A INPUT -i eth0 -p UDP -s 140.0.0.0/8 --dport 111 -j ACCEPT

账号验证

使用 Kerberos V5 作为登录验证系统,要求所有访问人员使用账号登录,提高安全性。

设置 NFSD 的 COPY 数目
在 Linux 中,NFSD 的 COPY 数目定义在启动文件 /etc/rc.d/init.d/nfs 中,默认值为 8。

最佳的 COPY 数目一般取决于可能的客户机数目。您可以通过测试来找到 COPY 数目的近似最佳值,并手动设置该参数。

选择传输协议
对于不同的网络情况,有针对地选择 UDP 或 TCP 传输协议。传输协议可以自动选择,也可以手动设置。

mount -t nfs -o sync,tcp,noatime,rsize=1024,wsize=1024 EXPORT_MACHINE:/EXPORTED_DIR /DIR

UDP 协议传输速度快,非连接传输时便捷,但其传输稳定性不如 TCP,当网络不稳定或者黑客入侵时很容易使 NFS 性能大幅降低,甚至导致网络瘫痪。一般情况下,使用 TCP 的 NFS 比较稳定,使用 UDP 的 NFS 速度较快。

在机器较少,网络状况较好的情况下,使用 UDP 协议能带来较好的性能。

当机器较多,网络情况复杂时,推荐使用 TCP 协议(V2 只支持 UDP 协议)。

在局域网中使用 UDP 协议较好,因为局域网有比较稳定的网络保证,使用 UDP 可以带来更好的性能。

在广域网中推荐使用 TCP 协议,TCP 协议能让 NFS 在复杂的网络环境中保持最好的传输稳定性。

限制客户机数量
修改 /etc/hosts.allow 和 /etc /hosts.deny 来限制客户机数量。

/etc/hosts.allow

portmap: 192.168.0.0/255.255.255.0 : allow
portmap: 140.116.44.125 : allow

/etc/hosts.deny

portmap: ALL : deny

改变默认的 NFS 端口
NFS 默认使用的是 111 端口,使用 port 参数可以改变这个端口值。改变默认端口值能够在一定程度上增强安全性。

配置 nosuid 和 noexec
SUID (Set User ID) 或 SGID (Set Group ID) 程序可以让普通用户以超过自己权限来执行。很多 SUID/SGID 可执行程序是必须的,但也可能被一些恶意的本地用户利用,获取本不应有的权限。

尽量减少所有者是 root,或是在 root 组中却拥有 SUID/SGID 属性的文件。您可以删除这样的文件或更改其属性,如:
使用 nosuid 选项禁止 set-UID 程序在 NFS 服务器上运行,可以在 /etc/exports 加入一行:

/www www.abc.com(rw, root_squash, nosuid)

使用 noexec 禁止直接执行其中的二进制文件。

NFS服务常见故障排查和解决方法

NFS,全名叫Network File System,中文叫网络文件系统,是Linux、UNIX系统的分布式文件系统的一个组成部分,可实现在不同网络上共享远程文件系统。NFS由Sun公司开发,目前已经成为文件服务的一种标准之一(RFC1904,RFC1813)。其最大的功能就是可以通过网络,让不同操作系统的计算机可以共享数据,所以可以把NFS看做是一个文件服务器。NFS缺点是其读写性能比本地硬盘要差一些。

一、NFS服务常见故障排查

NFS服务出现了故障,主要从以下几个方面检查原因:

(1)检查NFS客户机和服务器的负荷是否太高,Server和Client之间的网络是否正常;

(2)检查/etc/exports文件的正确性;

(3)必要时重启NFS和portmap服务;

(4)运行下列命令重新启动portmap和NFS:

# /etc/init.d/portmap restart
# /etc/init.d/nfs restart
# /etc/init.d/rpcbind restart (在RHEL/CentOS 6.x里面)
# chkconfig portmap on
# chkconfig nfs on
# chkconfig rpcbind on (在RHEL/CentOS 6.x里面)

注意:在RHEL/CentOS 6.x里面,portmap服务改名为rpcbind服务了;顺便说一下,rpcbind服务也是图形界面的关键基础服务,不启动此服务,不能启动图形桌面。

(5) 检查Client上的mount命令或/etc/fstab的语法是否正确;

(6) 查看内核是否支持NFS和RPC服务。一般正常安装的Linux系统都会默认支持NFS和RPC服务,除非你自己重新编译的内核,而且没选择nfs支持选项编译。

二、NFS常见故障解决方法

1、The rpcbind failure error
故障现象:
nfs mount: server1:: RPC: Rpcbind failure
RPC: Timed Out
nfs mount: retrying: /mntpoint
原因:
第一,可能因为客户机的hosts文件中存在错误的ip地址、主机名或节点名组合;
第二,服务器因为过载而暂时停止服务。
2、The server not responding error
现象:
NFS server server2 not responding, still trying
原因:
第一,网络不通,用ping命令检测一下。
第二,服务器关机。
3、The NFS client fails a reboot error
现象:
启动客户机后停住了,不断显示如下提示信息:
Setting default interface for multicast: add net 224.0.0.0: gateway:
client_node_name.
原因:
在etc/vfstab的mount选项中使用了fg而又无法成功mount服务器上的资源,改成bg或将该行注释掉,直到服务器可用为止。
4、The service not responding error
现象:
nfs mount: dbserver: NFS: Service not responding
nfs mount: retrying: /mntpoint
原因:
第一,当前级别不是级别3,用who -r查看,用init 3切换。
第二,NFS Server守护进程不存在,用ps -ef | grep nfs检查,用/etc/init.d/nfs start启动。
5、The program not registered error
现象:
nfs mount: dbserver: RPC: Program not registered
nfs mount: retrying: /mntpoint
原因:
第一,当前级别不是级别3。
第二,mountd守护进程没有启动,用/etc/init.d/nfs脚本启动NFS守护进程。
第三,看/etc/dfs/dfstab中的条目是否正常。
6、The stale file handle error
现象:
stale NFS file handle
原因:
服务器上的共享资源移动位置了,在客户端使用umount和mount重新挂接就可以了。
7、The unknown host error
现象:
nfs mount: sserver1:: RPC: Unknown host
原因:
hosts文件中的内容不正确。
8、The mount point error
现象:
mount: mount-point /DS9 does not exist.
原因:
该挂接点在客户机上不存在,注意检查命令行或/etc/vfstab文件中相关条目的拼写。
9、The no such file error
现象:
No such file or directory.
原因:
该挂接点在服务器上不存在,注意检查命令行或/etc/vfstab文件中相关条目的拼写。
10、No route to host
错误现象:
# mount 10.10.11.211:/opt/data/xmldb /c2c-web1/data/xmldb -t nfs -o rw
mount: mount to NFS server ‘10.10.11.211’ failed: System Error: No route to host.

原因:
防火墙被打开,关闭防火墙。
这个原因很多人都忽视了,如果开启了防火墙(包括iptables和硬件防火墙),NFS默认使用111端口,我们先要检测是否打开了这个端口,还要检查TCP_Wrappers的设定。
11、Not owner
现象:
# mount -F nfs -o rw 10.10.2.3:/mnt/c2c/data/resinfo2 /data/data/resinfo2
nfs mount: mount: /data/data/resinfo2: Not owner

原因:
这是Solaris 10版本挂载较低版本nfs时报的错误。

解决:
需要用-o vers=3参数

示例:
# mount -F nfs -o vers=3 10.10.2.3:/mnt/c2c/data/resinfo2 /data/data/resinfo2
12、RPC: Program not registered & retrying
现象:
nfs mount: 10.10.2.3: : RPC: Program not registered
nfs mount: retrying: /data/data/resinfo2

原因:
没有启动NFS共享端服务。

解决:需要重新启动share端的NFS服务,
Linux:
mount: RPC: Program not registered
# /etc/init.d/nfs restart

Solaris:
mount: RPC: Program not registered
# /etc/rc.d/init.d/nfs restart
13、can’t contact portmapper: RPC: Remote system error – Connection refused
现象:
# exportfs -a
can’t contact portmapper: RPC: Remote system error – Connection refused

原因:
出现这个错误信息是由于server端的portmap没有启动。

解决:
# /etc/init.d/portmap start

Linux下NFS的搭建

NFS是Network File System的简称,即网络文件系统。NFS是系统间进行文件共享的一种网络协议,它允许用户像访问本地文件一样去访问网络上共享的文件。

CentOS 自带NFS功能
若没有需安装:yum install -y nfs-utils rpcbind

  • 本次实验平台: CentOS release 6.8 (Final)
  • 服务端IP:172.17.99.67
  • 客服端IP:172.17.99.61

一、环境搭建

1. 编辑配置文件/etc/exports

vim /etc/exports

/ane/data/LBLOGS        172.17.99.61(rw,sync,no_root_squash)
/ane/data/LPLOGS        *(ro,sync)
#表示只有172.17.99.61有读写权限LBLOGS,只有读权限LPLOGS

2. 修改固定端口

vim /etc/sysconfig/nfs

RQUOTAD_PORT=30001
LOCKD_TCPPORT=30002
LOCKD_UDPPORT=30002
MOUNTD_PORT=30003
STATD_PORT=30004

二、搭建NFS

1. 创建nfs共享目录

mkdir /ane/data/LBLOGS -p
mkdir /ane/data/LPLOGS -p

2. 启动nfs

service nfs start
service rpcbind start

3. 在客服端查询

showmount -e 172.17.99.131
clnt_create: RPC: Program not registered
#此报错是因为启动nfs应用顺序错误导致

4. 重启nfs

service nfs stop
service rpcbind stop
#必须按以下方式顺序启动
service rpcbind start
service nfs start

5. 客服端查询

showmount -e 172.17.99.67
Export list for 172.17.99.67:
/ane/data/LBLOGS        172.17.99.61(rw,sync,no_root_squash)
/ane/data/LPLOGS        *(ro,sync)

6. 挂载

mount -t 172.17.99.67:/ane/data/LBLOGS /ane/data/LBLOGS
mount -t 172.17.99.67:/ane/data/LPLOGS /ane/data/LPLOGS

7. 检查

mount | grep nfs

172.17.99.67:/ane/data/LBLOGS on /ane/data/LBLOGS type nfs (ro,vers=4,addr=172.17.99.67,clientaddr=172.17.99.61)
172.17.99.67:/ane/data/LPLOGS/ on /ane/data/LPLOGS type nfs (rw,vers=4,addr=172.17.99.67,clientaddr=172.17.99.61)

三、nfs其他配置

1. 其他报错

mount 172.17.99.131:/ane/data/YTLOGS/ /ane/data/YTLOGS/
mount.nfs: access denied by server while mounting 172.17.99.131:/ane/data/YTLOGS/
#因为版本的问题导致
mount -o v3 172.17.99.131:/ane/data/YTLOGS/ /ane/data/YTLOGS/   #指定版本挂载即可

2. 按需自动挂载(间接映射)

#修改不活动状态的超时时间
vim /etc/sysconfig/autofs

TIMEOUT=300
修改为为
TIMEOUT=600
也就是将不活动状态的超时时间由5分钟修改为10分钟。

3. 开机挂载

vim /etc/fstab

172.17.99.67:/ane/data/LPLOGS /ane/data/LPLOGS nfs defaults 0 0

4. 卸载nfs挂载

umount /ane/data/LPLOGS

Over~

使用Samba替代NFS

之前项目组之中一位离职的同事给我们搭建的数据平台, 用的是Suse。 后来因为计算平台需要迁移到Spark之上, 我们就需要让Spark能方便的读取到SUSE之中的数据文件。

方案1:SUSE NFS Server

因为之前项目组最常用的文件分享协议就是NFS了。 我们的FreeNas服务器上面, 存储了几十T的数据文件。

因此我们首先尝试的是NFS的方法。 Google之后:

尝试了以下命令:

yast2 -i nfs-kernel-server 
# or zypper install -y nfs-kernel-server

但是不管上面哪个命令, 都会报错:

Warning: Legacy commandline option -y/--no-confirm detected. Please use -n/--non-interactive instead.
File '/repodata/repomd.xml' not found on medium 'http://download.opensuse.org/update/13.2/'

Abort, retry, ignore? [a/r/i/? shows all options] (a): a
ABORT request: Aborting requested by user

非常奇怪的问题, 后来又经过Google, 发现原因:

Yes, @tboerger is right. 13.2 reached EOL, this is why the repositories are no longer around. This doesn’t depend on this project.

From: https://github.com/openSUSE/docker-containers-build/issues/23

敢情是这位哥们用的SUSE版本太老了?!

方案2: Samba出马

正在一筹莫展甚至想把数据文件全部迁移到另外一个Ubuntu机器之时, 忽然发现这一台SUSE已经安装了Samba Server 服务, 只是没有启用而已。

现在回想起来, 这个SUSE的Samba Server的安装,也真是奇葩, 官网文档写的也很不详细。

现在总结一下:

  • 执行命令: yast2
    如图选中“Samba Server”

未分类

  • Workgroup 默认, 选择Next

未分类

  • Domain Controller 依然默认, Next

这一个功能我猜是某些域名才能访问。 具体没有试过~

未分类

  • 这一步要注意, 选择启动的时候自动启动

未分类

  • 注意, 需要手动设定账号信息, 否则在其他地方能看到目录, 就是进不去

假设原来已经有一个用户账号 hadoop, 执行下面的命令, 给这个账号设置一下密码:

suse2:~ # smbpasswd -a hadoop
New SMB password:
Retype new SMB password:
Added user hadoop.

这里设置的密码,可以跟原来的SSH密码一样。

设置完成之后, 我们可以在Windows上面直接使用UNC的方式访问了:

UNC的方式: \10.206.132.119

未分类

Ubuntu Client Mount Samba server

因为我们的需求是让Spark能方便的读取SMB服务器上面的数据, 最方便的方法还是直接mount。

当然可以使用smbclient, 不过在Spark之中读取数据的时候, 就不那么友好了。

mount命令也很简单,参考下面的格式:

sudo mount //10.206.132.119/users/hadoop/airsupport_da /data/airsupport/airsupport_da -o user=hadoop,password=xxxx

事后小结

  1. SUSE的文档相比Ubuntu感觉真心很少,而且也不是很友好。
    很多网友的文章, 感觉也是很久以前的东西。 特别是看到有人说某某东西EOS之后, 内心是有一些崩溃的。

  2. 后来简单调查了一下, Samba的稳定性确实要比NFS要好一些。
    我们的NFS Server 经常命令行卡死。
    解决方案: 不好意思, 暂时无解~ 重启服务器吧。

NFS-mount 跨服务器文件挂载

一、什么是NFS?

NFS:network file system,网络文件系统,允许服务器之间通过TCP/IP协议进行资源共享。NFS客户端可以透明的读写NFS服务器上的文件,就像操作本地文件一样。

二、为什么要用NFS?NFS什么好处?

  1. 节省空间:客户端磁盘空间较少,可以挂载到另外的服务器上,以节省本地存储空间。

  2. 网络受限:有些公司内部服务器无法访问外网,但是一些操作需要用到外网权限,就可以将公司服务器挂载到可以访问外网的服务器上,在另外的服务器上进行操作。

三、怎么挂载呢?

场景:服务器A的/mnt目录 挂载到 服务器B上的/test目录上

配置服务器A

1、需要检查是否具有nfs服务

$ ls -al /etc/init.d/nfs-kernel-server // 查看是否存在nfs服务

如果没有 需要手动安装 nfs-kernel-server 服务

$ sudo apt-get install nfs-kernel-server

2、修改 /etc/exports文件(需要root权限),增加要挂载的目录 /mnt *(rw,sync)

其中/mnt是要被挂在的目录,*表示任何服务器,也可以写客户端的IP地址,(rw,sync)表示挂载文件系统时的策略,rw表示读写,sync表示同步进行IO操作,还有其他的一些选项async(非同步进行IO操作)。

3、重启nfs服务

$ sudo /etc/init.d/nfs-kernel-server restart

配置服务器B

以root权限执行下面命令进行挂载

$ sudo mount -t nfs 10.24.21.143:/mnt /test

-t nfs 表示挂载类型是nfs,10.24.21.143:/mnt表示服务器A的IP及需要被挂载的目录,/test表示挂载到服务器B的目录。
执行下列命令查看是否已经挂载成功

$ mount | grep nfs // 如果成功,能够看到挂载的信息

四、配置过程中遇到的坑

其中在服务器B进行挂载时遇到报错如下:

mount: wrong fs type, bad option, bad superblock on 10.24.21.143:/mnt,
       missing codepage or helper program, or other error
       (for several filesystems (e.g. nfs, cifs) you might
       need a /sbin/mount.<type> helper program)

       In some cases useful info is found in syslog - try
       dmesg | tail or so.

错误信息中提到

you might need a /sbin/mount.<type> helper program

指在mount过程中用到了 /sbin/mount.nfs程序,而/sbin/mount.nfs是nfs-common提供的,需要手动运行下面的命令安装一下就好了。

$ sudo apt-get install nfs-common

NFS介绍、NFS服务端安装配置、NFS配置选项

NFS 介绍

NFS(Network File System)即网络文件系统,是FreeBSD支持的文件系统中的一种,它允许网络中的计算机之间通过TCP/IP网络共享资源。在NFS的应用中,本地NFS的客户端应用可以透明地读写位于远端NFS服务器上的文件,就像访问本地文件一样。NFS的数据传输基于RPC(remote procedure call)协议。

  • NFS 应用场景是:A,B,C 三台机器上需要保证被访问到的文件是一样的。A共享数据出来,B和C分别去挂载A共享的数据目录,从而B和C访问到的数据和A上的一致。
    • 例子:跑了一个网站,上面传输了很多图片,用户访问一个图片时,需要从A机器上去请求,但A机器负载高,为了分担负载,就多弄了两台机器,B机器C机器同时提供服务;正常的话,需要到A机器上才能拿到数据,但是B机器和C机器做了负载均衡,分担了相同的服务器,那么用户也有可能到B机器或者C机器上;那么用户请求到B机器上的时候,如何才能获取到A机器上的数据呢;要么把A机器的数据传输到B机器上,同时传输到C机器上,但是这个不能时时更新,(用户上传的数据是存放在A机器上,但用户请求的时候数据是请求到B机器上)这样A上的数据还没到B上面去,就会导致用户请求获取的数据访问不到,访问为空,为404;那么NFS服务就可以解决这个问题,将A机器的数据共享到B机器、C机器,通过NFS来实现。有NFS服务以后,上传到A机器上的数据,B机器或C机器上就能马上看到和调用。NFS可以实时同步数据。
  • NFS原理图

未分类

NFS服务需借助RPC协议实现通信。

服务端需要启动一个NFS服务,服务端要想给客户端提供服务,需要借助RPC协议,RPC协议是由rpcbind服务所实现的;在centos 5或者之前的版本叫portmap服务,centos6及之后的版本叫rpcbind服务,这两个都是一个服务,最终实现了RPC协议的通信,NFS服务默认不会监听任何端口(启动服务,但不会监听端口),最终监听端口,实现RPC通信的过程是由rpcbind服务产生的RPC协议实现的,RPC协议 默认监听的端口是111 端口;

整个流程为: 服务端的NFS服务监听一个端口通过RPC协议监听的端口,再去告诉客户端RPC协议,然后NFS客户端通过本机的RPC端口回传数据信息到服务端NFS监听的端口,最终实现通信.

NFS 服务端安装配置

准备两台虚拟机,一台作为服务端,一台作为客户端。

服务端配置

服务端IP:192.168.159.131

  • 安装NFS工具:
[root@localhost ~]# yum install -y nfs-utils rpcbind
  • 配置

编辑/etc/exports 文件,加入下面内容:

[root@localhost ~]# vim /etc/exports

/home/nfstestdir 192.168.159.0/24(rw,sync,all_squash,anonuid=1000,anongid=1000)
// /home/nfstestdir 要分享出去的目录是哪一个,这个目录是不存在的,后期还需要创建。
// ip段 为指定要给哪个ip段机器去分享这个目录,也可以写单个ip。
  • 启动NFS服务

在yum安装完成后,系统会自动启动rpcbind服务(在服务端进程名为systemd),默认监听的端口为111端口

[root@localhost ~]# ps aux | grep rpc

rpc 2390 0.0 0.0 64964 1044 ? Ss 21:19 0:00 /sbin/rpcbind -w
root 3826 0.0 0.0 112680 972 pts/0 R+ 21:31 0:00 grep --color=auto rpcbind
[root@localhost ~]# netstat -lntp 
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name 
tcp 0 0 0.0.0.0:111 0.0.0.0: LISTEN 1/systemd 
......
tcp6 0 0 :::111 ::: LISTEN 1/systemd 
......

启动NFS服务:

[root@localhost ~]# systemctl start nfs

//启动NFS 服务是会自动帮你启动rpc相关的服务
将NFS服务加入开机启动项:
[root@localhost ~]# systemctl enable nfs
Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service.

客户端配置

IP : 192.168.159.132

  • 安装NFS工具
[root@localhost ~]# yum install -y nfs-utils
  • 客户端挂载

检查客户端是否有权限访问服务端文件:

[root@localhost ~]# showmount -e 192.168.159.131 //131为服务端ip
clnt_create: RPC: Port mapper failure - Unable to receive: errno 113 (No route to host)
// 报错!说明网络不通,不能和192.168.159.131 的113端口通信。

解决办法:
1、检查服务端NFS服务是否开启(有没有监听111端口)
2、如果确认服务端NFS服务已经开启,那么检查防火墙状态,关闭服务端和客户端firewalld和SELinux防火墙(systemctl stop firewalld)
关闭防火墙后再次检查客户端是否有权限访问服务端文件:

[root@localhost ~]# showmount -e 192.168.159.131

Export list for 192.168.159.131:
/home/nfstestdir 192.168.159.0/24
// 客户端已有权限访问服务端

开始挂载:

[root@localhost ~]# mount -t nfs 

192.168.159.131:/home/nfstestdir /mnt/
// -t 指定文件系统类型
[root@localhost ~]# df -h

文件系统 容量 已用 可用 已用% 挂载点
......
192.168.159.131:/home/nfstestdir 16G 5.2G 11G 33% /mnt
  • 测试

在客户端/mnt目录下创建test文件

[root@localhost ~]# touch /mnt/test
[root@localhost ~]# ls -l /mnt/
总用量 0
-rw-r--r--. 1 mysql mysql 0 1月 16 22:05 test
查看服务端/home/nfstestdir/目录:
[root@localhost ~]# ls -l /home/nfstestdir/
总用量 0
-rw-r--r--. 1 mysql mysql 0 1月 16 22:05 test
// 存在个客户端上一样的文件,实现了同步共享。

其中,文件的用户和用户组都为mysql,是因为之前nfs服务端配置时,指定了anonuid=1000,anongid=1000。

服务端:

[root@localhost ~]# awk -F ':' '$3==1000 {print $0}' /etc/passwd
mysql:x:1000:1000::/home/mysql:/bin/bash
客户端:
[root@localhost ~]# awk -F ':' '$3==1000 {print $0}' /etc/passwd
mysql:x:1000:1000::/home/mysql:/bin/bash
// 由于两边uid都为1000,所以都为mysql用户。所以文件的所属组和所属主是由服务端配置文件中定义的anonuid,anongid决定的。(假设两个服务器上uid1000不是同一个用户,则同步文件在两个服务器上的属主和属组是不一样的。)

NFS配置选项

  • rw 读写
  • ro 只读
  • sync 同步模式,内存数据实时写入磁盘/ 内存数据实时写入磁盘,这样会降低磁盘效率。
  • async 非同步模式 // 每隔一段时间把内存数据刷入磁盘一次,如果突然断电,会丢失一本分数据。
  • no_root_squash 客户端挂载NFS共享目录后,root用户不受约束,权限很大
  • root_squash 与上面选项相对,客户端上的root用户收到约束,被限定成某个普通用户
  • all_squash 客户端上所有用户在使用NFS共享目录时都被限定为一个普通用户
  • anonuid/anongid 和上面几个选项搭配使用,定义被限定用户的uid和gid

CentOS 配置部署 NFS

对于服务器的文件共享,可以部署一台文件共享服务器,通过 NFS 去挂载使用。

安装

CentOS 6.x

下载安装

yum -y install rpcbind nfs

配置开机启动

chkconfig rpcbind on
chkconfig nfs on

Centos 7.x

下载安装

yum -y install rpcbind nfs-utils

配置开机启动

systemctl enable nfs-server.service
systemctl enable rpcbind.service

服务端配置

配置

在服务端,编辑配置文件 /etc/exports,添加如下行

/home/uploads 192.168.221.101(rw,all_squash,anonuid=0,anongid=0)

配置说明:

192.168.221.101 客户端 ip
rw 读写 ro 只读
all_squash 无论客户端以何用户连接服务端,对服务端而言均为匿名用户
anonuid 匿名用户的 uid
anongid 匿名用户的 gid

查看共享目录的 uid 和 gid,使用命令:

ls -nd /home/nfs

uid 和 gid 最好为客户端和服务端都存在的 uid 和 gid 值。

可用的配置说明列表:

未分类

exportfs -r # 生效

若在服务启动后修改了 /etc/exports 配置文件,执行该命令后,无需重启 nfs 服务和 rpcbind 服务。对该命令的说明如下:

-a 全部挂载或卸载 /etc/exports中的内容

-r 重新读取/etc/exports 中的信息 ,并同步更新/etc/exports、/var/lib/nfs/xtab

-u 卸载单一目录(和-a一起使用为卸载所有/etc/exports文件中的目录)

-v 在export的时候,将详细的信息输出到屏幕上。

防火墙端口配置

NFS 除 111 和 2049 外,其它端口均为随机生成,若 NFS 服务端需要启用防火墙,需要固定其它端口。

参考文章:http://linux.vbird.org/linux_server/0330nfs.php#nfsserver_security

# 先添加默认端口,随后添加额外端口
firewall-cmd  --permanent    --add-port=111/tcp
firewall-cmd  --permanent    --add-port=111/udp
firewall-cmd  --permanent    --add-port=2049/tcp
firewall-cmd  --permanent    --add-port=2049/udp
...

重启防火墙,重启 rpcbind:

rpcinfo -p

启动

查看本机共享目录:

showmount -e

CentOS 6.x

service rpcbind start
service nfs start

CentOS 7.x

systemctl start rpcbind.service
systemctl start nfs-server.service

客户端配置

查看服务端共享目录:

showmount -e server_ip

配置自动挂载:

vim /etc/fstab

添加一行

192.168.221.100:/home/nfs/ /home/test/uploads/ nfs defaults 0 0

在客户端,只需要启动 rpcbind 服务,但仍需要安装 nfs

# CentOS 6.x
chkconfig rpcbind on
service rpcbind start

# CentOS 7.x
systemctl enable rpcbind
systemctl start rpcbind

挂载测试

mount -a

查看挂载

nfsstat -m

错误解决

执行 mount 报错

clnt_create: RPC: Port mapper failure - Unable to receive: errno 113 (No route to host)

关闭防火墙,或者执行如下:

rpcinfo  -p  192.168.221.100

将列出端口都添加至防火墙规则,放行。

nfs设置固定端口并添加防火墙规则

nfs启动时会随机启动多个端口并向RPC注册,这样如果使用iptables对NFS端口进行限制就会有点麻烦,可以更改配置文件固定NFS服务相关端口。这样设置固定端口以后即便重启机器也很方便挂载,如果不设置固定端口,机器或服务重启后之前添加的iptables规则就失效了,

下面的是没有设置固定端口时的情况

未分类

设置固定端口:

编辑 /etc/sysconfig/nfs 文件:

vim    /etc/sysconfig/nfs

添加如下内容:

RQUOTAD_PORT=30001
LOCKD_TCPPORT=30002
LOCKD_UDPPORT=30002
MOUNTD_PORT=30003
STATD_PORT=30004

未分类

添加后保存退出并重启 rpcbind和nfs

service  rpcbind   restart

service   nfs  restart

重启服务后再查看端口:

未分类

添加iptables规则

[root@file-server ~]# iptables -A INPUT -s 192.168.214.0/24 -p tcp –dport 111 -j ACCEPT
[root@file-server ~]# iptables -A INPUT -s 192.168.214.0/24 -p udp –dport 111 -j ACCEPT
[root@file-server ~]# iptables -A INPUT -s 192.168.214.0/24 -p tcp –dport 2049 -j ACCEPT
[root@file-server ~]# iptables -A INPUT -s 192.168.214.0/24 -p udp –dport 2049 -j ACCEPT
[root@file-server ~]# iptables -A INPUT -s 192.168.214.0/24 -p tcp –dport 30001:30004 -j ACCEPT
[root@file-server ~]# iptables -A INPUT -s 192.168.214.0/24 -p udp –dport 30001:30004 -j ACCEPT

保存规则:

service   iptables    save

查看可以挂载的目录

[root@file-server ~]# showmount -e localhost

Export list for localhost:
/share 192.168.214.0/24

最后,可以编辑 /etc/exports 添加其他挂载目录

未分类

linux 配置nfs挂载共享目录

第一步:安装nfs;

第二步:启动nfs;

service nfs start

第三步:编辑/etc/exports文件;

加入:/xxxdir
xxx.xxx.xxx.xxx(rw,sync,no_root_squash),xxx.xxx.xxx.xxx是要挂载的IP

例如:

/temp      192.168.9.19(rw,sync,no_root_squash)
/共享目录        地址      (权限)

地址可以使用完整IP或网段,也可以地址可以使用主机名,DNS解析的和本地/etc/hosts解析的都行

权限有:  
rw:read-write,可读写;    注意,仅仅这里设置成读写客户端还是不能正常写入,还要正确地设置共享目录的权限,参考问题7  
ro:read-only,只读;  
sync:文件同时写入硬盘和内存;  
async:文件暂存于内存,而不是直接写入内存;  
no_root_squash:NFS客户端连接服务端时如果使用的是root的话,那么对服务端分享的目录来说,也拥有root权限。显然开启这项是不安全的。  
root_squash:NFS客户端连接服务端时如果使用的是root的话,那么对服务端分享的目录来说,拥有匿名用户权限,通常他将使用nobody或nfsnobody身份;  
all_squash:不论NFS客户端连接服务端时使用什么用户,对服务端分享的目录来说都是拥有匿名用户权限;  
anonuid:匿名用户的UID值,通常是nobody或nfsnobody,可以在此处自行设定;  
anongid:匿名用户的GID值。 

第四步:重启nfs服务

service nfs restart

不影响其他挂载目录情况下加载应用exports修改:

exportfs -r
或者
service nfs reload

第五步:在挂载机上(上面例子中192.168.9.19)新建目录,比如/itemp,并更改权限

chmod -R 777 itemp

最后挂载:

mount -t nfs 共享主机IP:/temp /itemp