How to Deploy RustFS with Docker and Integrate It into a SpringBoot Application

This guide walks you through installing the RustFS distributed object storage via Docker, using its visual console, and configuring a SpringBoot project to upload and delete files through the RustFS S3‑compatible API, complete with code snippets and practical screenshots.

macrozheng
macrozheng
macrozheng
How to Deploy RustFS with Docker and Integrate It into a SpringBoot Application

Overview

RustFS is a high‑performance distributed object storage system written in Rust, compatible with the AWS S3 API and released under the Apache 2.0 license.

Docker Deployment

Run RustFS quickly with Docker.

Pull the official image: docker pull rustfs/rustfs Start the container, setting access credentials and mounting a host directory for data:

docker run -p 9000:9000 --name rustfs \
  -e RUSTFS_ACCESS_KEY=rustfsadmin \
  -e RUSTFS_SECRET_KEY=rustfsadmin \
  -v /mydata/rustfs/data:/data \
  -v /etc/localtime:/etc/localtime \
  -d rustfs/rustfs

Open the management console at http://<em>host</em>:9000 using the default credentials rustfsadmin:rustfsadmin.

Spring Boot Integration

Example shows how to upload and delete files on RustFS from a Spring Boot application.

Dependencies

<dependency>
  <groupId>software.amazon.awssdk</groupId>
  <artifactId>s3</artifactId>
  <version>${aws-s3-sdk.version}</version>
</dependency>

Configuration

rustfs:
  endpoint: http://192.168.3.101:9000
  bucketName: simple
  accessKey: rustfsadmin
  secretKey: rustfsadmin
@Configuration
public class RustFSConfig {
    @Value("${rustfs.endpoint}") private String ENDPOINT;
    @Value("${rustfs.accessKey}") private String ACCESS_KEY;
    @Value("${rustfs.secretKey}") private String SECRET_KEY;

    @Bean
    public S3Client s3Client() {
        return S3Client.builder()
            .endpointOverride(URI.create(ENDPOINT))
            .region(Region.US_EAST_1) // region is ignored by RustFS
            .credentialsProvider(StaticCredentialsProvider.create(
                AwsBasicCredentials.create(ACCESS_KEY, SECRET_KEY)))
            .forcePathStyle(true) // required for RustFS
            .build();
    }
}

Controller

@RestController
@RequestMapping("/rustfs")
public class RustFSController {
    @Autowired private S3Client s3Client;
    @Value("${rustfs.bucketName}") private String BUCKET_NAME;
    @Value("${rustfs.endpoint}") private String ENDPOINT;

    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public CommonResult upload(@RequestPart("file") MultipartFile file) {
        if (!bucketExists(BUCKET_NAME)) {
            s3Client.createBucket(CreateBucketRequest.builder().bucket(BUCKET_NAME).build());
            String policy = JSONUtil.toJsonStr(createBucketPolicyConfigDto(BUCKET_NAME));
            s3Client.putBucketPolicy(PutBucketPolicyRequest.builder()
                .bucket(BUCKET_NAME).policy(policy).build());
        }
        try {
            s3Client.putObject(PutObjectRequest.builder()
                .bucket(BUCKET_NAME)
                .key(file.getOriginalFilename())
                .contentType(file.getContentType())
                .build(),
                RequestBody.fromInputStream(file.getInputStream(), file.getSize()));
            RustFSUploadResult result = new RustFSUploadResult();
            result.setName(file.getOriginalFilename());
            result.setUrl(ENDPOINT + "/" + BUCKET_NAME + "/" + file.getOriginalFilename());
            return CommonResult.success(result);
        } catch (IOException e) {
            e.printStackTrace();
            return CommonResult.failed();
        }
    }

    @PostMapping("/delete")
    public CommonResult delete(@RequestParam("objectName") String objectName) {
        s3Client.deleteObject(DeleteObjectRequest.builder()
            .bucket(BUCKET_NAME).key(objectName).build());
        return CommonResult.success(null);
    }

    private boolean bucketExists(String bucketName) {
        try {
            s3Client.headBucket(r -> r.bucket(bucketName));
            return true;
        } catch (NoSuchBucketException e) {
            return false;
        }
    }

    private BucketPolicyConfigDto createBucketPolicyConfigDto(String bucketName) {
        BucketPolicyConfigDto.Statement stmt = BucketPolicyConfigDto.Statement.builder()
            .Effect("Allow")
            .Principal(BucketPolicyConfigDto.Principal.builder()
                .AWS(new String[]{"*"}).build())
            .Action(new String[]{"s3:GetObject"})
            .Resource(new String[]{"arn:aws:s3:::" + bucketName + "/*"})
            .build();
        return BucketPolicyConfigDto.builder()
            .Version("2012-10-17")
            .Statement(CollUtil.toList(stmt))
            .build();
    }
}

Bucket Policy Example

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"AWS": ["*"]},
    "Action": ["s3:GetObject"],
    "Resource": ["arn:aws:s3:::simple/*"]
  }]
}

Testing

Swagger UI (e.g., http://localhost:8088/swagger-ui.html ) can be used to invoke the /upload and /delete endpoints.

References

RustFS repository: https://github.com/rustfs/rustfs Spring Boot example source:

https://github.com/macrozheng/spring-examples/tree/master/spring-rustfs
backend developmentSpringBootObject StorageRustFSAWS S3 Compatibility
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.