溫馨提示:如在執行過程中遇到問題,請仔細檢查執行命令的用戶和所在目錄。
1.環境准備
1.1系統配置說明
ip | 安裝服務 | 主機名 | 內核版本 | 備注 |
192.168.5.181 | ceph、ceph-deploy | admin-node | CentOS Linux release 7.9.2009 (Core) | 管理節點 |
192.168.5.182 |
ceph、mon、osd、rgw | node1 | CentOS Linux release 7.9.2009 (Core) | osd、rgw節點 |
192.168.5.183 | ceph、mon、osd | node2 | CentOS Linux release 7.9.2009 (Core) | osd |
192.168.5.184 | ceph、mon、osd | node3 | CentOS Linux release 7.9.2009 (Core) | osd |
1.2關閉selinux和防火牆(所有節點)
#關閉防火牆 systemctl stop firewalld systemctl disable firewalld #關閉selinux setenforce 0 sed -i '/SELINUX/s/enforcing/disabled/' /etc/selinux/config
1.2設置時間同步(所有節點)
# yum 安裝 ntp yum install ntp ntpdate ntp-doc # 校對系統時鍾 ntpdate 0.cn.pool.ntp.org
1.3修改主機名和hosts文件(所有節點)
#192.168.5.181上操作 hostnamectl set-hostname admin-node #192.168.5.182上操作 hostnamectl set-hostname node1 #192.168.5.183上操作 hostnamectl set-hostname node2 #192.168.5.184上操作 hostnamectl set-hostname node3 #所有節點上操作 vi /etc/hosts #將以下內容增加到/etc/hosts中 192.168.5.181 admin-node 192.168.5.182 node1 192.168.5.183 node2 192.168.5.184 node3
1.4創建 Ceph 部署用戶並設置其遠程登錄密碼(所有節點)
# 創建 ceph 特定用戶 useradd -d /home/cephd -m cephd echo cephd | passwd cephd --stdin # 添加 sudo 權限 echo "cephd ALL = (root) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/cephd chmod 0440 /etc/sudoers.d/cephd
# node1、node2、node3上操作,設置cephd用戶的遠程登錄密碼,記住此密碼,后面配置免密登錄會用到
passwd cephd
1.5配置免密登錄(admin-node節點)
# 切換到cephd用戶 su cephd # 生成ssh密鑰,一路回車即可 ssh-keygen # 將公鑰復制到 node1 節點,輸入cephd的用戶密碼即可 ssh-copy-id node1 # 將公鑰復制到 node2 節點,輸入cephd的用戶密碼即可 ssh-copy-id node2 # 將公鑰復制到 node3 節點,輸入cephd的用戶密碼即可 ssh-copy-id node3
2.Ceph集群搭建(ceph version 10.2.11)
2.1安裝ceph-deploy(admin-node節點)
配置ceph安裝源
# yum 配置其他依賴包 sudo yum install -y yum-utils && sudo yum-config-manager --add-repo https://dl.fedoraproject.org/pub/epel/7/x86_64/ && sudo yum install --nogpgcheck -y epel-release && sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 && rm /etc/yum.repos.d/dl.fedoraproject.org* # 添加 Ceph 源 sudo vi /etc/yum.repos.d/ceph.repo [ceph] name=ceph baseurl=http://mirrors.aliyun.com/ceph/rpm-jewel/el7/x86_64/ gpgcheck=0 [ceph-noarch] name=cephnoarch baseurl=http://mirrors.aliyun.com/ceph/rpm-jewel/el7/noarch/ gpgcheck=0
安裝 ceph-deploy
sudo yum update && sudo yum install ceph-deploy
2.2修改 ceph-deploy 管理節點上的 ~/.ssh/config 文件,這樣無需每次執行 ceph-deploy 都要指定 –username cephd(admin-node)
sudo vi ~/.ssh/config Host admin-node Hostname admin-node User cephd Host node1 Hostname node1 User cephd Host node2 Hostname node2 User cephd Host node3 Hostname node3 User cephd
sudo chmod 600 ~/.ssh/config
2.3清理配置(admin-node)
# 清理 Ceph 安裝包 sudo ceph-deploy purge admin-node node1 node2 node3 # 清理 Ceph 配置文件 sudo ceph-deploy purgedata admin-node node1 node2 node3 sudo ceph-deploy forgetkeys
2.4創建集群 mon節點(admin-node)
# 創建執行目錄 mkdir /home/cephd/ceph-cluster && cd /home/cephd/ceph-cluster # 創建集群 mon節點 sudo ceph-deploy new node1 node2 node3
2.5修改ceph.conf配置文件(admin-node)
vi ceph.conf #增加以下內容 osd pool default size = 2 #增加默認副本數為 2 osd max object name len = 256 osd max object namespace len = 64
2.6安裝ceph(admin-node)
sudo ceph-deploy install admin-node node1 node2 node3
2.7初始化 monitor 節點並收集所有密鑰(admin-node)
sudo ceph-deploy --overwrite-conf mon create-initial
2.8修改硬盤掛載目錄權限(node1、node2、node3)
前提:掛載存儲硬盤,參考我的另一篇博客,這里假設將硬盤掛載到/data目錄
chown -R ceph:ceph /data
2.9准備OSD(admin-node)
sudo ceph-deploy --overwrite-conf osd prepare node1:/data node2:/data node3:/data
2.10激活OSD(admin-node)
#激活osd sudo ceph-deploy osd activate node1:/data node2:/data node3:/data #通過 ceph-deploy admin 將配置文件和 admin 密鑰同步到各個節點 sudo ceph-deploy admin node1 node2 node3
2.11修改ceph.client.admin.keyring權限(node1、node2、node3)
sudo chmod +r /etc/ceph/ceph.client.admin.keyring
2.12查看ceph集群狀態(node1、node2、node3)
ceph -s
自此,恭喜你,集群已經部署完成,那么如何使用集群呢,請繼續往下看!
3.Ceph RGW網關部署及使用說明(ceph version 10.2.11)
3.1RGW網關部署(admin-node)
sudo ceph-deploy rgw create node1
網關創建后默認會監聽7480端口,請保證7480端口未被占用,否則可能會創建失敗。
3.2RGW創建一個test1用戶(node1)
radosgw-admin user create --uid test1 --display_name test1
打馬賽克的地方就是test1用戶連接ceph集群所需要的公私鑰,現在已經可以使用test1用戶通過S3 API連接ceph存儲集群做數據上傳操作了,連接端口為7480。
3.3RGW用戶容量限制(node1)
#限制test1用戶最大上傳的對象個數為1024個,最大使用空間為1024B,即1KB radosgw-admin quota set --quota-scope=user --uid=test1 --max-objects=1024 --max-size=1024B #啟用用戶空間限制 radosgw-admin quota enable --quota-scope=user --uid=test1
3.4RGW bucket容量限制(node1)
#限制用戶test1擁有的存儲桶最大上傳對象為1024個,最大空間為1024B radosgw-admin quota set --uid=test1 --quota-scope=bucket --max-objects=1024 --max-size=1024B #啟用桶容量限制 radosgw-admin quota enable --quota-scope=bucket --uid=test1
4.Java連接Ceph RGW網關進行存儲相關操作(ceph version 10.2.11)
4.1構建maven工程,並添加以下依賴
<dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk</artifactId> <version>1.9.6</version> </dependency>
4.2編寫S3Utils工具類
package com.fh.util; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import com.amazonaws.ClientConfiguration; import com.amazonaws.Protocol; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.S3ClientOptions; import com.amazonaws.services.s3.model.Bucket; import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; import com.amazonaws.services.s3.model.GetObjectRequest; import com.amazonaws.services.s3.model.ListBucketsRequest; import com.amazonaws.services.s3.model.ListObjectsRequest; import com.amazonaws.services.s3.model.ListVersionsRequest; import com.amazonaws.services.s3.model.ObjectListing; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.PutObjectRequest; import com.amazonaws.services.s3.model.S3Object; import com.amazonaws.services.s3.model.S3ObjectSummary; import com.amazonaws.services.s3.model.S3VersionSummary; import com.amazonaws.services.s3.model.VersionListing; public class S3Utils { /** * 刪除文件桶 * @param s3 * @param bucketName * @return */ public static boolean deleteBucket(AmazonS3 s3,String bucketName) { try { // 刪除桶中所有文件對象 System.out.println(" - removing objects from bucket"); ObjectListing object_listing = s3.listObjects(bucketName); while (true) { for (Iterator<?> iterator = object_listing.getObjectSummaries().iterator(); iterator.hasNext(); ) { S3ObjectSummary summary = (S3ObjectSummary) iterator.next(); s3.deleteObject(bucketName, summary.getKey()); } // more object_listing to retrieve? if (object_listing.isTruncated()) { object_listing = s3.listNextBatchOfObjects(object_listing); } else { break; } } // 刪除桶中所有文件對象版本信息 System.out.println(" - removing versions from bucket"); VersionListing version_listing = s3.listVersions( new ListVersionsRequest().withBucketName(bucketName)); while (true) { for (Iterator<?> iterator = version_listing.getVersionSummaries().iterator(); iterator.hasNext(); ) { S3VersionSummary vs = (S3VersionSummary) iterator.next(); s3.deleteVersion(bucketName, vs.getKey(), vs.getVersionId()); } if (version_listing.isTruncated()) { version_listing = s3.listNextBatchOfVersions( version_listing); } else { break; } } s3.deleteBucket(bucketName); return true; } catch (Exception e) { e.printStackTrace(); } return false; } /** * 刪除文件桶中文件對象 * @param s3 * @param bucketName 文件桶名 * @param key 對象key * @return */ public static boolean deleteObject(AmazonS3 s3,String bucketName,String key) { try { s3.deleteObject(bucketName, key); return true; } catch (Exception e) { e.printStackTrace(); } return false; } /** * 獲取文件桶中所有文件對象key * @param s3 * @param bucketName * @return */ public static List<String> getBucketObjects(AmazonS3 s3,String bucketName){ List<String> objectList = new ArrayList<>(); ObjectListing objectListing = s3.listObjects(new ListObjectsRequest().withBucketName(bucketName)); while (true) { for (Iterator<?> iterator = objectListing.getObjectSummaries().iterator(); iterator.hasNext(); ) { S3ObjectSummary summary = (S3ObjectSummary) iterator.next(); objectList.add(summary.getKey()); } // more object_listing to retrieve? if (objectListing.isTruncated()) { objectListing = s3.listNextBatchOfObjects(objectListing); } else { break; } } return objectList; } /** * 下載文件到本地 * @param s3 * @param bucketName * @param key * @param targetFilePath */ public static void downloadObject(AmazonS3 s3,String bucketName,String key,String targetFilePath){ S3Object object = s3.getObject(new GetObjectRequest(bucketName,key)); if(object != null){ System.out.println("Content-Type: " + object.getObjectMetadata().getContentType()); InputStream input = null; FileOutputStream fileOutputStream = null; byte[] data = null; try { //獲取文件流 input=object.getObjectContent(); data = new byte[input.available()]; int len = 0; fileOutputStream = new FileOutputStream(targetFilePath+key); while ((len = input.read(data)) != -1) { fileOutputStream.write(data, 0, len); } System.out.println("下載文件成功"); } catch (IOException e) { e.printStackTrace(); }finally{ if(fileOutputStream!=null){ try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if(input!=null){ try { input.close(); } catch (IOException e) { e.printStackTrace(); } } } } } /** * 獲取文件桶中對應key的文件大小,如key不存在你則返回-1 * @param s3 * @param bucketName * @param key * @return */ public static long getObjectSize(AmazonS3 s3,String bucketName,String key) { long size = -1l; try { ObjectMetadata objectMetada = s3.getObjectMetadata(bucketName, key); size = objectMetada.getContentLength(); }catch(Exception e) { } return size; } /** * 生成文件url * @param s3 * @param bucketName * @param objectName * @return */ public static String getDownloadUrl(AmazonS3 s3,String bucketName, String objectName) { if (bucketName.isEmpty() || objectName.isEmpty()) { return null; } // GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName); // System.out.println(conn.generatePresignedUrl(request)); // Date dateTime = new Date(); long msec = dateTime.getTime(); msec += 1000 * 60 * 5; dateTime.setTime(msec); GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName,objectName).withExpiration(dateTime); // if (versionId != null) { // request.setVersionId(versionId); // } System.out.println(s3.generatePresignedUrl(request)); return s3.generatePresignedUrl(request).toString(); }/** * 獲取S3連接對象 * * @return */ public static AmazonS3 getS3Client(String endPoint,String accessKey,String secretKey) { AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey); ClientConfiguration clientConfig = new ClientConfiguration(); clientConfig.setProtocol(Protocol.HTTP); clientConfig.setConnectionTimeout(6000);//設置連接超時時間 clientConfig.setSocketTimeout(30000); clientConfig.setMaxErrorRetry(1);//設置最大錯誤重試次數 // System.setProperty("com.amazonaws.services.s3.disablePutObjectMD5Validation","true"); AmazonS3 conn = new AmazonS3Client(credentials,clientConfig); conn.setEndpoint(endPoint); conn.setS3ClientOptions(new S3ClientOptions().withPathStyleAccess(true)); return conn; } /** * 獲取S3連接對象 * * @return */ public static AmazonS3 getS3SSLClient(String endPoint,String accessKey,String secretKey) { System.setProperty("com.amazonaws.sdk.disableCertChecking", "true"); AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey); ClientConfiguration clientConfig = new ClientConfiguration(); clientConfig.setProtocol(Protocol.HTTPS); clientConfig.setConnectionTimeout(3000);//設置連接超時時間 clientConfig.setSocketTimeout(3000); clientConfig.setMaxErrorRetry(2);//設置最大錯誤重試次數 // System.setProperty("com.amazonaws.services.s3.disablePutObjectMD5Validation","true"); AmazonS3 conn = new AmazonS3Client(credentials,clientConfig); conn.setEndpoint(endPoint); conn.setS3ClientOptions(new S3ClientOptions().withPathStyleAccess(true)); return conn; } }
4.3使用S3Utils工具類進行相關操作即可
創建S3對象的endPoint為http://192.168.5.182:7480
公私鑰是上面網關創建時生成的公私鑰