Ceph兼容S3 API,这意味着可以直接使用S3 Rest API进行连接,不过也有已经封装的SDK可供选择。
简单来说,如果需要使用aws-sdk连接ceph,主要是需要获取以下三个值:
- AK
- SK
- Ceph rgw暴露的端口
以下使用Rook部署的方法来讲解如何获取这四个值。
获取Ceph用户配置
要想获取AK和SK很简单,首先需要保证已经创建了一个用户。
然后根据已创建的服务来获取秘钥,比如对于官方教程
kubectl -n rook-ceph get secret rook-ceph-object-user-my-store-my-user -o jsonpath='{.data.AccessKey}' | base64 --decode
kubectl -n rook-ceph get secret rook-ceph-object-user-my-store-my-user -o jsonpath='{.data.SecretKey}' | base64 --decode
rook-ceph 定义在cluster.yaml这样的配置文件中,用户名定义在metadata的name一栏。
RGW可以通过端口转发的方式来进行访问,虽然Rook官网有提到需要部署成NodePort类型来提供外部访问接口,但是直接转发似乎也可以达到类似的效果
kubectl -n rook-ceph port-forward --address 0.0.0.0 svc/rook-ceph-rgw-my-store 7080:80
这样就可以通过访问虚拟机的IP来访问RGW了。
配置AWS-SDK环境变量
现在假设已经获取到了这些值:
{
AK: "926R3V2NRO9G8JKTL11X",
SK: "IrQyBhf8EMU6e4uFBarrOTerWza4lhBCibvxW7Rx",
EndpointURL: "http://192.168.130.135:7080"
}
将AK和SK设置至$HOME/.aws/credentials(Linux、MACOS)或%USERPROFILE%\.aws\credentials(Windows)
# ~/.aws/credentials
[default]
aws_access_key_id=926R3V2NRO9G8JKTL11X
aws_secret_access_key=IrQyBhf8EMU6e4uFBarrOTerWza4lhBCibvxW7Rx
使用aws-sdk-go-v2
由于使用的主要是对象存储,因此需要安装以下三个依赖
go get -u "github.com/aws/aws-sdk-go-v2/aws"
go get -u "github.com/aws/aws-sdk-go-v2/config"
go get -u "github.com/aws/aws-sdk-go-v2/service/s3"
Endpoint的配置需要单独写一个Resolver
endpointURL := "http://192.168.130.135:7080"
customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
return aws.Endpoint{
URL: endpointURL,
}, nil
})
然后使用这个Resolver创建一个S3客户端
cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithEndpointResolverWithOptions(customResolver))
if err != nil {
panic(err)
}
svc := s3.NewFromConfig(cfg, func(options *s3.Options) {
options.UsePathStyle = true
})
需要注意的是Ceph的S3 Rest API和AWS的并不完全一致,比如下面两个创建桶的操作
# Ceph
PUT /{bucket} HTTP/1.1
Host: cname.domain.com
# AWS S3 REST API
PUT / HTTP/1.1
Host: `Bucket`.s3.amazonaws.com
可以看到AWS的桶名放在了域名中,所以需要设置options.UsePathStyle = true。
桶操作
列出所有桶
func listBuckets(svc *s3.Client) {
out, err := svc.ListBuckets(context.TODO(), nil)
if err != nil
panic(err)
}
fmt.Print("[")
for i := range out.Buckets {
if i > 0 {
fmt.Print(", ")
}
bkt := out.Buckets[i]
fmt.Print(*bkt.Name)
}
fmt.Print("]")
}
创建桶
func createBucket(svc *s3.Client, bktName string) {
bktInput := s3.CreateBucketInput{
Bucket: &bktName,
}
_, err := svc.CreateBucket(context.TODO(), &bktInput)
if err != nil {
panic(err)
}
}
删除桶
func deleteBucket(svc *s3.Client, bktName string) {
bktInput := s3.DeleteBucketInput{
Bucket: &bktName,
}
_, err := svc.DeleteBucket(context.TODO(), &bktInput)
if err != nil {
panic(err)
}
}
对象操作
列出桶中的对象
// 假设已经存在 Bucket: "test-bucket"
bkt := "test-bucket"
bktInput := s3.ListObjectsV2Input{
Bucket: &bkt,
}
out, err := svc.ListObjectsV2(context.TODO(), &bktInput)
if err != nil {
panic(err)
}
for i := range out.Contents {
obj := out.Contents[i]
fmt.Printf("out: %v\n", *obj.Key)
}