113

假设我有一台机器,我希望它能够写入存储在 S3 存储桶上的某个日志文件。

因此,机器需要具有对该存储桶的写入能力,但是,我不希望它能够覆盖或删除该存储桶中的任何文件(包括我希望它写入的文件)。

所以基本上,我希望我的机器能够只将数据附加到该日志文件,而不覆盖它或下载它。

有没有办法将我的 S3 配置为这样工作?也许我可以附加一些 IAM 政策,这样它就可以像我想要的那样工作?

4

8 回答 8

165

不幸的是,你不能。

S3 没有“追加”操作。*对象上传后,无法原地修改;您唯一的选择是上传一个新对象来替换它,这不符合您的要求。

*:是的,我知道这篇文章已经有几年的历史了。不过,它仍然是准确的。

于 2017-01-21T20:15:16.547 回答
27

正如接受的答案所述,您不能。我知道的最佳解决方案是使用:

AWS Kinesis Firehose

https://aws.amazon.com/kinesis/firehose/

他们的代码示例看起来很复杂,但您的代码示例可能非常简单。您继续对应用程序中的 Kinesis Firehose 传输流执行 PUT(或 BATCH PUT)操作(使用 AWS 开发工具包),并配置 Kinesis Firehose 传输流以将流式数据发送到您选择的 AWS S3 存储桶(在AWS Kinesis Firehose 控制台)。

在此处输入图像描述

它仍然不如>>Linux 命令行方便,因为一旦您在 S3 上创建了一个文件,您就必须再次处理下载、附加和上传新文件,但您只需每批行执行一次,而不是而不是每行数据,因此您无需担心因追加操作量而产生的巨额费用。也许可以做到,但我无法从控制台看到如何做到这一点。

于 2017-08-19T02:20:59.593 回答
12

S3 上的对象不可追加。在这种情况下,您有 2 个解决方案:

  1. 将所有 S3 数据复制到新对象,附加新内容并写回 S3。
function writeToS3(input) {
    var content;
    var getParams = {
        Bucket: 'myBucket', 
        Key: "myKey"
    };

    s3.getObject(getParams, function(err, data) {
        if (err) console.log(err, err.stack);
        else {
            content = new Buffer(data.Body).toString("utf8");
            content = content + '\n' + new Date() + '\t' + input;
            var putParams = {
                Body: content,
                Bucket: 'myBucket', 
                Key: "myKey",
                ACL: "public-read"
             };

            s3.putObject(putParams, function(err, data) {
                if (err) console.log(err, err.stack); // an error occurred
                else     {
                    console.log(data);           // successful response
                }
             });
        }
    });  
}
  1. 第二种选择是使用 Kinesis Firehose。这是相当简单的。您需要创建 Firehose 传输流并将目标链接到 S3 存储桶。而已!
function writeToS3(input) {
    var content = "\n" + new Date() + "\t" + input;
    var params = {
      DeliveryStreamName: 'myDeliveryStream', /* required */
      Record: { /* required */
        Data: new Buffer(content) || 'STRING_VALUE' /* Strings will be Base-64 encoded on your behalf */ /* required */
      }
    };

    firehose.putRecord(params, function(err, data) {
      if (err) console.log(err, err.stack); // an error occurred
      else     console.log(data);           // successful response
    }); 
}
于 2018-11-07T16:35:33.803 回答
3

如果有人想通过类似 S3 的服务将数据附加到对象,阿里云 OSS(对象存储服务)原生支持

OSS 提供追加上传(通过 AppendObject API),允许您直接将内容追加到对象的末尾。使用该方法上传的对象是可附加对象,而使用其他方法上传的对象是普通对象。附加的数据是立即可读的。

于 2019-12-13T00:27:33.070 回答
2

S3存储桶不允许您附加现有对象,可以使用的方法是首先使用get方法从S3存储桶中获取数据,然后在本地添加您要附加的新数据,然后推送它返回 S3 存储桶。

因为,不可能附加到现有的 S3 对象。您需要将其替换为附加数据的新对象。这意味着每次向其附加新条目时,您都需要上传整个对象(日志文件)。这不会很有效。

您可以将日志条目发送到 SQS 队列,并且当队列大小达到设定数量时,您可以将日志消息批处理在一起并作为对象添加到 S3 存储桶中。这仍然不能满足您附加到单个对象的要求

于 2021-02-12T08:53:31.040 回答
2

我有类似的问题,这就是我问的

如何使用 AWS Lambda 在文件中追加数据

这是我想出解决上述问题的方法:

使用 getObject 从现有文件中检索

   s3.getObject(getParams, function(err, data) {
   if (err) console.log(err, err.stack); // an error occurred
   else{
       console.log(data);           // successful response
       var s3Projects = JSON.parse(data.Body);
       console.log('s3 data==>', s3Projects);
       if(s3Projects.length > 0) {
           projects = s3Projects;
       }   
   }
   projects.push(event);
   writeToS3(); // Calling function to append the data
});

写入函数以追加到文件中

   function writeToS3() {
    var putParams = {
      Body: JSON.stringify(projects),
      Bucket: bucketPath, 
      Key: "projects.json",
      ACL: "public-read"
     };

    s3.putObject(putParams, function(err, data) {
       if (err) console.log(err, err.stack); // an error occurred
       else     console.log(data);           // successful response
        callback(null, 'Hello from Lambda');
     });
}

希望这有帮助!!

于 2017-09-07T09:27:50.710 回答
2

正如其他人之前所说,S3 对象不可附加。
但是,另一种解决方案是写入 CloudWatch 日志,然后将您想要的日志导出到 S3。这也可以防止任何访问您服务器的攻击者从您的 S3 存储桶中删除,因为 Lambda 不需要任何 S3 权限。

于 2019-07-25T20:20:22.353 回答
1

你可以:

  1. 设置分段上传
  2. 调用 UploadPartCopy,将现有的 s3 对象指定为源
  3. 使用要附加的数据调用 UploadPart
  4. 关闭分段上传。

有许多限制,例如您现有的对象必须大于 5MB(但是如果它更小,则在大多数情况下将其复制到客户端应该足够快)它不如直接附加,但至少您不需要将数据从 aws 来回复制到本地计算机。

于 2021-10-22T15:56:39.810 回答