亚马逊AWS官方博客

利用 S3FS 将 S3 作为共享存储挂载到 Kubernetes Pod

背景介绍:

Amazon S3是互联网存储解决方案,能让客户访问同一个具备可扩展性、可靠性、安全性和性能优越、快速价廉的数据存储基础设施。Amazon S3 提供了简单的REST API服务接口,可用于随时在 互联网上的任何位置存储和检索任何数量的数据。开发人员可以利用Amazon S3提供的接口,命令行接口或者支持不同语言的SDK访问S3服务。

 

为什么要将 Amazon S3 以文件存储的方式挂载到 Kubernetes 平台?

对于原来使用本地目录访问数据的应用程序,比如使用本地磁盘或网络共享盘保存数据的应用系统,如果用户希望把数据放到S3上,则需要修改数据的访问方式,比如修改为使用AWS SDK 或CLI访问S3中存储的数据。

同时在AWS上实现kubernetes集群是很多用户的需求,无论是使用托管服务还是自建kubernetes集群,存储都是kubernetes集群搭建的重点。并且docker的部署方式也让客户程序减少了对于底层环境的依赖。为了让用户原来的应用系统能在不做修改的情况下直接使用Amazon S3服务,需要把S3存储桶作为目录挂载到用户EKS集群中的worker结点上。本文主要介绍如何利用S3fs将S3存储桶在EKS平台上以“sidecar”方式挂载到Amazon EKS的worker实例上的pod中,挂载后需要读写此存储桶的pod都可以对此桶进行读写,以实现共享存储功能。

 

什么是 S3FS ?

S3fs是基于FUSE的文件系统,允许Linux和Mac Os X 挂载S3的存储桶在本地文件系统,S3fs能够保持对象原来的格式,S3FS是POSIX的大子集,包括读/写文件、目录、符号链接、模式、uid/gid和扩展属性,与AmazonS3、Google云存储和其他基于S3的对象存储兼容。关于S3fs的详细介绍,请参见:https://github.com/s3fs-fuse/s3fs-fuse

 

Kubernetes pod 中使用S3FS架构图:

 

前提条件:

1.已经搭建完成kubernetes 集群。

2.Worker结点具备相关的权限,如:操作S3等权限。

 

实施过程:

1.下载S3fs代码到kubectl 可与kubernetes master结点交互执行的机器上:

#Git clone https://github.com/freegroup/kube-s3.git

 

2.如果此结点没有安装aws cli,请按以下文档进行安装:

https://docs.aws.amazon.com/zh_cn/cli/latest/userguide/cli-chap-install.html

 

3.搭建镜像仓库(如有可使用现有的)

本文档使用AWS ECR来做镜像仓库:

a.可根据此文档来创建仓库:

https://docs.aws.amazon.com/zh_cn/AmazonECR/latest/userguide/ECR_GetStarted.html

b.使用如下命令来登录镜像仓库:

$aws ecr get-login --no-include-email --region <region>

返回结果类似:

docker login -u AWS -p eyJwYXlsb2FkIjoiY1o5MTNIQUErVkdNZmhvTS9JdFJuMWNJK05yVTFyVU53ZFRPcWlTMW1KaVRoQ0tPYkwxdDlOaEtNL3MvOWpyelgrYzBXMXdHbDlCanJkTkVRNGVVWVR5QldHZnNHL3U0NytQVVZOMzkvN3hWTHFmL0IxSVp0ak1Tbk4vRVFxZ3RGZ2k4LzgwSEhhR2lJalU1L0lCbm1EeXJUQzVhQW5kU1M4TzBaSkdieEdGZWp3b2FOZ2F2TThzbXdMcFU2cWdHM3FUZmN2N0tleG1YS00rNE90VlR5dDBHNUdUVXhDdmlvaTFaZ1Ura1NtSlZURWlnRFZvSzFLVUViTG1IcXVRZkNWQkN5QTgvOG5tZW81REtIKzlIQ1N2QlBkSG02VWJwZ3BYUm82Zk1weXcrd25VYU1sVkJWdHl6Ymo1ZkhyRjhkbkFhanFnZ3lUSDhBT3hOYVZHYzBUaVdldFhlRWwreU1Ha1ZKZm4rRlBaNWxDSkNiVUlvTUFWUXZQeU5SY3AyTmNHNVZxQ0pJcGU0T3h2eEIyeVFkaHBRaStoOC9VM25Yc1l1VG1qcmFmUU1WbVRwNjB5VjBUcHBadWI4a2JyYXYyWXlhdnZCWGFZWG8wL3hzbkxwR2c5dzI0UkNvdWhYaVpWdlhFTG5VeHNpSmRKZFVQTTlGd0RTZ1ZoK3c1eG5VRDMxaXYrMzdtRWpUZ29Pd01QK2VlbERwT2xsR3VydFQ4KzgzTHJoT3E0ckZBeDgrVGhyTnpMYXdrKzFUSmpjemJGeEpncnpWNWhsSlMrR2JXUkJiazVuUXdlOGo2UHREV2xjUmJ2VFI1V1JDelFNdzNNZkllOXVTbGRWQ3V0cjVYQ3djT1NMYTdLc3JWcG8vV0JaWWh2Z05obHl0alpPVEVxaWh1b1pyMCtnL0ROZ3hObUlybnVDNzlxZUgzSVU2NFE0aUZnS0tYMnpyTjVrbzBpYWlzRzMzc2M5eS94djJJcXZSYVJySXh2OEl3eUUzaDFQWHVwUmowaSsyNWtiUTVKWERWU3hiKzdHcWQ4aXhjb21jVFFTNE5QWm14RHFHWWRUdTlrUHHeTJnN2hOd3IvbkJuWG1XeVZ5MmtMTVhYb0t0eHhvPSIsImRhdGFrZXkiOiJBUUVCQUhod20wWWFJU0plUnRKbTVuMUc2dXFlZWtYdW9YWFBlNVVGY2U5UnE4LzE0d0FBQUg0d2ZBWUpLb1pJaHZjTkFRY0dvRzh3YlFJQkFEQm9CZ2txaGtpRzl3MEJCd0V3SGdZSllJWklBV1VEQkFFdU1CRUVESWFXTXdkQVJ5S0E2aCtSb1FJQkVJQTdlT2JnMWtWbVNwTDV0UkxNWlNEWW5iM1poRHFRT3RYK2JDZXl2YW82WEp6a3ZxdElCcTRYZ05qcWJPRUs5cFRhNGVWVUlzUFRnSWJ4SWpVPSIsInZlcnNpb24iOiIyIiwidHlwZSI6IkRBVEFfS0VZIiwiZXhwaXJhdGlvbiI6MTU2MzQ3NzMzNX0= https://154900008054.dkr.ecr.us-east-1.amazonaws.com

 

c.运行上一步中返回的docker login命令。此命令提供一个在 12 小时内有效的授权令牌

 

4.确保您已经在集群中创建了“imagepullsecret”。(此命令中的username & password也在上面的命令中)

kubectl create secret docker-registry artifactory –docker-server=<YOUR-REGISTRY>.docker.repositories.sap.ondemand.com –docker-username=<USERNAME> –docker-password=<PASSWORD> –docker-email=<EMAIL> -n <NAMESPACE>

 

举例如下:(此处密码是上步中的返回)

kubectl create secret docker-registry artifactory –docker-server=154998728054.dkr.ecr.us-east-1.amazonaws.com/respository –docker-username=aws –docker-password=eyJwYXlsb2FkIjoiOWtlY3ZSQnY4VGpEbkw4cFFlblZKS1VLbzJJVUpQeXVzMW1keEF2NmZ6ZjA1ZDFaMHA5T282R1ZsR2VEdjJEWEVzNXZ0TFZSYWhOUlZKK2JzdHk3a0xWTnNXZTIwL2ZGZ1lWaEdlaFN4Wjk2WGdrSDNrMDgweXAwV2VnSm9NSXlDT2x5RjB1d0RFc2Z4TDI3VGpYcUdrU0d5WHdVZmdCZnhJUU1NT2wrQ25SbE1rTUtxMDVlQk0zbU9ENXJ3N3E2c2p3MUZsTDliMmNyS29zQ1RRbVdCblcwZEs0cEtvZVhOcHc4eGZWZGxwMjdHaDNTWWtlRDl0S3Q4OUx3MURvSm1VbUtEVGVRV2lqTzRuWnV3SEI1NWVGdG1veUYycTd2cmdPOGlZQ29Nb3Y3SVpuV2NxaEQ4eTJUajlYUTVlamNmUit2TDk3dFV0R0c1WkFpVGlHWDlRc2JkUFMvdzB0ZEFUck5BaWhjQU56aEFnZDZpWmRTQ0Z0b3dMNS9Id0tPMXMrbjQrYXI3RlNMQjIyVnlxOXR3Ujl0cS9FZk1pcnNLY3ZEYU9peUxLYkxtd3hXMXltUTcvYzFGNFBxZ0Z0dFhjVis0dmVqRWRtRjJacnRzMnRUTWM5ZEtVK1JVWU02ZDBCOFpxZG9PRWNibUdUdTZJL0hFN0xtT25yVGFlOEdWSDkzQ0FWTVFGZFl2YzBXV2FDazFHeVhDcURYZXB6MGRidjdYYWpQRUNrc1ltNExtcW9PdytLN0tyM3pVTTJSbTlZOWRlTmFZUXoxRjhmYUlEaEgyWkJoT0dJQlBQUGlVWWJmVWgwNG1ZTWRIUVltRjRsSWlaVTllbEd4ZzVIY2ZLOUJyZkVrcmYvTVBRVWxVVm4rc1JzdjdPc3EvU3JvLytuNlBaRmh2VmZZQldIL3dPdjNIWklVb0pqV043S0FWb1VKVi9TNEpLaXJzbHU4SlR2YWEyZHRYT3FkVXQrOHF1bjIvb3VMMDVlVXovZDJ4MlBKM0pTZDViQkRSUUpkLzRNTmFtVlRTUjd1WHpCWUQvNGdlN29mZDBBY09hMlZkMitpRGkzVU85YmYydm9aY2k0R3NKd3R6WDRaMEtTcWxBK205ZTk5a01uZkxML0U1V3FwRVNSczFBNFB3cFNZajNKVDRvcTVJOTRXQ3F4WiszdWxxa3Nva1ZSNGFhMENZaWpkRmlWUWtoR0RzU1V2Mjk2dnBaUC9rb3hLYzlycDVBTzFEQUVhbS9McWFSQ1ZVUWtUMFA5bUpGUkJzQU5MQVJFK2I5QUlRYnNDc1FZcjVQUzZvUjhTUVRVWDRuR1dNU1d3enkvRTA3anBiRjVVNUllOUNKcVcvM3pOUVFXZVFnQjArWTdqN3NFK0ROS3ZIU0pQSWNFVmlqQVgrTnU1dDVQZjdSMVFyWjBuS09tS0FyY0FpVXB2N1Y2emNzdythVVhNN0IvT3dUNVZDaUdEazhqeFd6c2M3Sk5PQUJuNndoQS9IMjljSXpJVHgyb1QvK1RMRnpIQkhpaTdhR1plMWdOUENHRm5DRFBZZlJwQS93VUNnOTZvT0l6VlpBMko4QkpKbXBCTytPZ3NuNndKSnVkcGhIOUhCTXJIQVdjM0lvZXRiTGtFQ2tib1VoRW1pZUV3Q0F5ektuOGRkRzMrS3hxdVRIRURkSjVVQmdIS1dvV0JWYkVRTEtZQXg4V2lmK3dtOU1CREpEeWswZ3psNjNMVnBIWlNlbG01SFQ4U3RCREJJVGdQYTRsM1kyMElySFpJazFDYWtkcFhMVUxvQjE1cm1hOXRIbVFVaGI5T3U4L0RKRjM4WWJuWVZlN2NxYW0rbDJqZXJZYzNaYWFIQ0kwbHdKeEJwYkxNbjVsZDNvWjNjSW5wOVBRbThFa0ZoeWE5elhvQnl1R0pKMS93djIrYjFSekxHVWhyUTR4V0ZqZUxaMWhKaHVOdEFVR0J5NGYwbWljQ2xMbklYVmVKczVMSy9MN1dURGVBeG1DOHozbzA3NElONnNsdVUxdnBocUNJR1ByM0Z3Q05WR281N3VVdklIazd3VnIzYlBMT0QrUEx1dVlCeUVETXhlS2NYU083b3p4WkxqdGJRV1pBekp0ZTRnSnhRMkkwaVBYWHZBST0iLCJkYXRha2V5IjoiQVFFQkFIaHdtMFlhSVNKZVJ0Sm01bjFHNnVxZWVrWHVvWFhQZTVVRmNlOVJxOC8xNHdBQUFINHdmQVlKS29aSWh2Y05BUWNHb0c4d2JRSUJBREJvQmdrcWhraUc5dzBCQndFd0hnWUpZSVpJQVdVREJBRXVNQkVFREd9

5.配置configmap

a.cd kube-s3/yaml/

b.将configmap_secrets_template.yaml复制到configmap_secrets.yaml并将您的aksk放置在正确的位置,如下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: s3-config
data:
  S3_BUCKET: <YOUR-S3-BUCKET-NAME>
  AWS_KEY: <YOUR-AWS-TECH-USER-ACCESS-KEY>
  AWS_SECRET_KEY: <YOUR-AWS-TECH-USER-SECRET>

6.构建和部署

a.修改build.sh文件,增加如下内容:

#replace version
REPOSITORY1=<ECR 对应的repository>
PROJECT1=kube-s3
b.修改Dockerfile,注意红色字体:
/usr/bin/s3fs $S3_BUCKET $MNT_POINT -f -o endpoint=${S3_REGION},nonempty,allow_other,use_cache=/tmp,max_stat_cache_size=1000,stat_cache_expire=900,retries=5,connect_timeout=10

ENV S3_REGION 'us-east-2'

修改后整体文件如下:
VERSION=$1
PROJECT=kube-s3
REPOSITORY=154998728054.dkr.ecr.us-east-1.amazonaws.com
#replace version
REPOSITORY1=cp-enablement.docker.repositories.sap.ondemand.com
PROJECT1=kube-s3

# causes the shell to exit if any subcommand or pipeline returns a non-zero status.
set -e

########################################################################################################################
# build the new docker image
########################################################################################################################
#
echo '>>> Building new image'
# Due to a bug in Docker we need to analyse the log to find out if build passed (see https://github.com/dotcloud/docker/issues/1875)
docker build --no-cache=true -t $REPOSITORY/$PROJECT:$VERSION . | tee /tmp/docker_build_result.log
RESULT=$(cat /tmp/docker_build_result.log | tail -n 1)
if [[ "$RESULT" != *Successfully* ]];
  then
    exit -1
fi

########################################################################################################################
# push the docker image to your registry
########################################################################################################################
#
echo '>>> Push new image'
docker push $REPOSITORY/$PROJECT:$VERSION


########################################################################################################################
# deploy your YAML files into your kubernetes cluster
########################################################################################################################

kubectl apply -f ./yaml/configmap_secrets.yaml
# Apply the YAML passed into stdin and replace the version string first
cat ./yaml/daemonset.yaml | sed "s/$REPOSITORY1\/$PROJECT1/$REPOSITORY\/$PROJECT:$VERSION/g" | kubectl apply -f -

 

b.运行如下命令:

	./build.sh 1.0 

c.运行如下命令检查pod是否正常运行

      kubectl get pods      

7.创建demo pod来验证S3fs是否可以正常工作:

a. kubectl apply -f ./yaml/example_pod.yaml

b. kubectl get pods

c. kubectl exec -ti test-pd  sh

d. ls -la /var/s3

e.创建一个文件

8.在S3和host中去验证,此文件是否存在。

 

注:详情请参考:https://github.com/freegroup/kube-s3

 

注意

如果对于性能有很强的需求并且要求和传统文件系统的体验一致,那么此方案并不适用,可以考虑使用AWS的EBS来做kubernetes的持久存储。

一般情况下S3不能提供像本地文件系统一样的功能。具体如下:

  • 随机写或追加写需要重写整个文件;
  • 由于网络延迟,所以元数据的操作如列出目录等的性能较差;
  • 最终一致性会暂时产生中间数据(AMAZON S3数据一致性模型);
  • 没有文件和目录的原子重命名;
  • 安装相同存储桶的多个客户端之间没有协调;
  • 没有硬链接;

 

本篇作者

王建利

王建利,AWS解决方案架构师,主要负责企业级大客户的上云工作,服务客户涵盖从能源,互联网,传统生产制造,擅长DevOps和容器领域。具备 15 年 IT 专业服务经验,历任程序设计师、项目经理、解决方案架构师。