溫馨提示:如果使用電腦查看圖片不清晰,可以使用手機打開文章單擊文中的圖片放大查看高清原圖。
Fayson的github: https://github.com/fayson/cdhproject
提示:代碼塊部分可以左右滑動查看噢
1
文章編寫目的
前面Fayson介紹了《如何使用Java API訪問HDFS爲目錄設置配額》,隨着開發語言的多樣性,也有基於Scala語言進行開發,本篇文章主要介紹如何使用Scala代碼訪問Kerberos環境的HDFS。
- 內容概述
1.環境準備
2.Kerberos環境連接示例
- 測試環境
1.CDH版本爲5.15.0
2.OS爲Redhat7.2
- 前置條件
1.CDH集羣運行正常
2.集羣已啓用Kerberos
2
環境準備
使用IDE工具通過Maven創建一個Scala工程,這裏就不詳細介紹Scala的開發環境搭建了。
1.在工程的pom.xml文件中增加如下依賴
<dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>2.6.0-cdh5.15.0</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <version>2.6.0-cdh5.15.0</version> </dependency>
(可左右滑動)
2.爲Kerberos集羣,需要導出一個keytab文件用於訪問HDFS,導出步驟如下
在CMD命令行執行如下命令導出AD中用戶的keytab文件
ktpass -princ hdfs/[email protected] -mapuser hdfs/admin -pass 123!QAZ -out hdfsadmin.keytab -crypto RC4-HMAC-NT
(可左右滑動)
導出的keytab文件會在當前命令執行目錄。
3.獲取集羣krb5.conf文件,內容如下
[root@cdh4 ~]# more /etc/krb5.conf # Configuration snippets may be placed in this directory as well includedir /etc/krb5.conf.d/ includedir /var/lib/sss/pubconf/krb5.include.d/ [logging] default = FILE:/var/log/krb5libs.log kdc = FILE:/var/log/krb5kdc.log admin_server = FILE:/var/log/kadmind.log [libdefaults] dns_lookup_realm = false ticket_lifetime = 24h renew_lifetime = 7d forwardable = true rdns = true default_realm = FAYSON.COM #default_ccache_name = KEYRING:persistent:%{uid} [realms] FAYSON.COM = { kdc = adserver.fayson.com admin_server = adserver.fayson.com } [domain_realm] .fayson.com = FAYSON.COM fayson.com = FAYSON.COM
(可左右滑動)
4.配置hosts文件,確保本地開發環境與集羣所有節點通且端口均放通(如8020等)
由於Fayson這裏使用的是公網環境所以hostname與外網的ip對應,這裏會導致一個問題在向集羣put數據文件時會失敗,如果開發環境和HDFS都屬於內網環境則不會有這個問題。
5.通過Cloudera Manager下載HDFS客戶端配置
6.將上述準備的配置文件及keytab等信息拷貝至本地目錄或工程中,Fayson的工程目錄結構如下:
3
客戶端訪問HDFS工具類
1.ClientUtils類主要提供客戶端初始化方法,內容如下:
package com.cloudera.utils import java.io.IOException import java.util.Properties import org.apache.hadoop.conf.Configuration import org.apache.hadoop.security.UserGroupInformation /** * package: com.cloudera.utils * describe: 客戶端訪問HDFS工具類 * creat_user: Fayson * email: [email protected] * creat_date: 2018/11/13 * creat_time: 下午9:16 * 公衆號:Hadoop實操 */ object ClientUtils { /** * 初始化HDFS的Configuration * @return */ def initConfiguration(): Configuration = { val configuration = new Configuration configuration.addResource(this.getClass().getResourceAsStream("/hdfs-client-kb/core-site.xml")) configuration.addResource(this.getClass().getResourceAsStream("/hdfs-client-kb/hdfs-site.xml")) configuration } /** * 初始化訪問Kerberos訪問 * @param configuration * @param debug 是否啓用Kerberos的Debug模式 * @param properties 客戶端配置信息 */ def initKerberosENV(configuration: Configuration, debug: Boolean, properties: Properties):Unit = { System.setProperty("java.security.krb5.conf", properties.getProperty("krb5.conf.path")) System.setProperty("javax.security.auth.useSubjectCredsOnly", "false") if (debug) System.setProperty("sun.security.krb5.debug", "true") try { UserGroupInformation.setConfiguration(configuration) UserGroupInformation.loginUserFromKeytab(properties.getProperty("kerberos.user"), properties.getProperty("kerberos.keytab.path")) System.out.println(UserGroupInformation.getCurrentUser) } catch { case e: IOException => { e.printStackTrace() } } } }
(可左右滑動)
2.HDFSUtils用於操作HDFS的工具類
package com.cloudera.utils import org.apache.hadoop.fs.permission._ import org.apache.hadoop.fs.{FileSystem, Path} import scala.collection.JavaConversions._ /** * package: com.cloudera.utils * describe: 用戶操作HDFS工具類 * creat_user: Fayson * email: [email protected] * creat_date: 2018/11/13 * creat_time: 下午10:05 * 公衆號:Hadoop實操 */ object HDFSUtils { /** * 使用HDFS API向HDFS創建目錄 * 在創建目錄指定目錄權限爲777時,該權限需要與HDFS默認的umask權限相減,最終得出目錄權限爲755 * umask默認爲022,0表示對owner沒有限制,2表示對group不允許有寫權限,2表示對other不允許有寫權限 * 因此在創建目錄指定777,但創建出來的目錄爲755的原因 * @param fileSystem * @param dirName */ def mkdir(fileSystem: FileSystem, dirName: String):Unit = { val path = new Path(dirName) if(fileSystem.exists(path)) { System.out.println("目錄已存在") } else { val isok = fileSystem.mkdirs(path) if(isok) { System.out.println("HDFS目錄創建成功:" + dirName) } else { System.out.println("HDFS目錄創建失敗:" + dirName) } } } /** * 設置HDFS指定目錄及文件權限 * @param fileSystem * @param path 文件或目錄路徑 * @param mode 權限模式,如:777、755、644,數字對應的R=4,W=2,X=1 */ def setPermission(fileSystem: FileSystem, path: String, mode: String): Unit = { val fspath = new Path(path) fileSystem.setPermission(fspath, new FsPermission(mode)) } /** * 設置HDFS指定目錄或文件的屬主及屬組 * @param fileSystem * @param path * @param username * @param groupname */ def setowner(fileSystem: FileSystem, path: String, username: String, groupname: String): Unit = { val fspath = new Path(path) fileSystem.setOwner(fspath, username, groupname) } /** * 設置HDFS指定目錄的ACL權限 * 在指定ACL時AclEntryScope.ACCESS表示當前目錄所擁有的訪問權限 * AclEntryScope.DEFAULT,表示該目錄下所有子目錄及文件集成父目錄的Default ACL權限 * @param fileSystem * @param path */ def setAcl(fileSystem: FileSystem,path: String): Unit = { val fspath = new Path(path) val listAcl = List[AclEntry]( new AclEntry.Builder().setType(AclEntryType.GROUP).setScope(AclEntryScope.ACCESS).setName("testa").setPermission(FsAction.ALL).build() ) fileSystem.modifyAclEntries(fspath, listAcl) } /** * 遞歸指定路徑下所有目錄及文件 * @param path * @param fileSystem * @return */ def recursiveDir(path: String, fileSystem: FileSystem): List[Path] = { var listPath = List[Path]() val fspath = new Path(path) val listfiles = fileSystem.listStatus(fspath) listfiles.foreach(f => { System.out.println(f.getPath.toString) if(f.isDirectory) { recursiveDir(f.getPath.toString, fileSystem) } }) listPath } }
(可左右滑動)
4
示例代碼及運行
1.OperatorHDFSByAPI爲測試類包含API的調用
package com.cloudera.hdfs import java.util.Properties import com.cloudera.utils.{ClientUtils, HDFSUtils} import org.apache.hadoop.fs.FileSystem /** * package: com.cloudera.hdfs * describe: Scala訪問Kerberos環境下的HDFS示例 * creat_user: Fayson * email: [email protected] * creat_date: 2018/11/13 * creat_time: 下午9:02 * 公衆號:Hadoop實操 */ object OperatorHDFSByAPI { def main(args: Array[String]): Unit = { //加載客戶端配置參數 val properties = new Properties() properties.load(this.getClass.getResourceAsStream("/client.properties")) //初始化HDFS Configuration 配置 val configuration = ClientUtils.initConfiguration() //集羣啓用Kerberos,代碼中加入Kerberos環境 ClientUtils.initKerberosENV(configuration, false, properties) val fileSystem = FileSystem.get(configuration) val testPath = "/fayson/test" //創建HDFS目錄 // HDFSUtils.mkdir(fileSystem, testPath) //設置目錄屬主及組 HDFSUtils.setowner(fileSystem, testPath, "hive", "hive") //設置指定HDFS路徑的權限 HDFSUtils.setPermission(fileSystem, testPath, "771") //設置指定HDFS目錄的ACL HDFSUtils.setAcl(fileSystem, testPath) //遞歸指定路徑下所有目錄及文件 HDFSUtils.recursiveDir("/user/hive/warehouse/test.db/", fileSystem) fileSystem.close() } }
(可左右滑動)
2.示例運行
3.查看HDFS上創建的目錄、權限及ACL等
未設置ACL權限的userc用戶無權限訪問該目錄
5
總結
1.在進行本地開發時,必須將集羣的hostname及IP配置在本地的hosts文件中(如果使用DNS服務則可以不配置hosts文件),否則無法與集羣互通,確保本地客戶端與集羣的端口是放通的。
2.在創建目錄指定目錄權限爲777時,創建目錄的權限只能到755,是由於HDFS的umask導致,默認的umask爲022(0表示對owner沒有限制,2表示對group不允許有寫權限,2表示對other不允許有寫權限),指定的777權限減去022即爲創建目錄的權限
3.設置HDFS目錄或文件的ACL時,需要區分AclEntryScope.ACCESS和DEFAULT。ACCESS表示爲當前目錄或文件指定ACL訪問權限,DEFAULT表示在該目錄下創建子目錄或文件會繼承該ACL權限。
GitHub源碼地址:
https://github.com/fayson/cdhproject/tree/master/scalademo
提示:代碼塊部分可以左右滑動查看噢
爲天地立心,爲生民立命,爲往聖繼絕學,爲萬世開太平。 溫馨提示:如果使用電腦查看圖片不清晰,可以使用手機打開文章單擊文中的圖片放大查看高清原圖。
推薦關注Hadoop實操,第一時間,分享更多Hadoop乾貨,歡迎轉發和分享。