从ECS Docker容器写入cloudwatch时缺少日志行

tan*_*nvi 7 amazon-web-services amazon-ecs docker amazon-cloudwatchlogs docker-container

(在将所有日志打印到CloudWatch Logs之前退出AWS-ECS上的Docker容器)为什么CloudWatch Logs组的某些流不完整(即Fargate Docker Container成功退出,但日志突然停止更新)?间歇地在几乎所有日志组中看到此消息,但并不是在每个日志流/任务运行时都看到这一点。我正在1.3.0版上运行


说明:
A Dockerfile使用该CMD命令运行node.js或Python脚本。

这些不是服务器/长时间运行的进程,我的用例要求容器在任务完成时退出。

样本Dockerfile:

FROM node:6
WORKDIR /path/to/app/
COPY package*.json ./
RUN npm install
COPY . .
CMD [ "node", "run-this-script.js" ]
Run Code Online (Sandbox Code Playgroud)


当使用本地在终端上运行此命令时,所有日志都会正确打印到终端的stdout / stderr中docker run。
要将其作为Fargate上的ECS任务运行,请awslogs从CloudFormation模板设置日志驱动程序为。

...
LogConfiguration:
   LogDriver: 'awslogs'
     Options:
        awslogs-group: !Sub '/ecs/ecs-tasks-${TaskName}'
        awslogs-region: !Ref AWS::Region
        awslogs-stream-prefix: ecs
...
Run Code Online (Sandbox Code Playgroud)

看到cloduwatch日志输出有时不完整,我进行了测试并检查了CW Logs Limits中的每个限制,并且确定问题不存在。
我最初以为这是节点js在console.log()刷新之前异步退出的问题,或者进程退出得太早了,但是当我也使用另一种语言时,也会出现相同的问题-这使我相信这与代码,而是专门使用cloudwatch。
通过添加一个睡眠计时器在代码中引起延迟对我没有用。

有可能由于docker容器在任务完成后立即退出,因此日志没有足够的时间写到CWLogs,但是必须有一种方法来确保不会发生这种情况?

样本日志:流不完整:

{ "message": "configs to run", "data": {"dailyConfigs":"filename.json"]}}
running for filename
Run Code Online (Sandbox Code Playgroud)

完成的日志流:

{ "message": "configs to run", "data": {"dailyConfigs":"filename.json"]}}
running for filename

stdout: entered query_script
... <more log lines>
stderr:
real 0m23.394s
user 0m0.008s
sys 0m0.004s
(node:1) DeprecationWarning: PG.end is deprecated - please see the upgrade guide at https://node-postgres.com/guides/upgrading
Run Code Online (Sandbox Code Playgroud)

asa*_*voy 6

更新:现在看来这是固定的,因此无需实施下面描述的解决方法


使用ECS Fargate容器运行Python脚本时,我已经看到了相同的行为-并产生了同样的挫败感!

我认为这是由于CloudWatch Logs Agent批量发布日志事件所致:

日志事件如何批处理?

满足以下任一条件时,批次将满并发布:

  1. 该buffer_duration的时间已经过去了,因为加入的第一个日志事件。

  2. batch_size累计的日志事件少于,但添加新的日志事件超过batch_size。

  3. 日志事件的数量已达到batch_count。

  4. 批处理中的日志事件不会超过24小时,但是添加新的日志事件会超过24小时限制。

(参考:https : //docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AgentReference.html)

因此,可能的解释是,日志事件由代理缓冲,但在ECS任务停止时尚未发布。(如果是这样,这似乎是一个ECS问题-是否有任何AWS ECS工程师愿意对此发表看法??)

似乎没有直接的方法可以确保发布日志,但是它确实建议人们可以等待至少buffer_duration几秒钟(默认情况下为5秒),并且应该发布任何先前的日志。

我将在下面描述一些测试,这是我采用的解决方法。Shell脚本run_then_wait.sh包装命令以触发Python脚本,并在脚本完成后添加睡眠。

Docker文件

FROM python:3.7-alpine
ADD run_then_wait.sh .
ADD main.py .

# The original command
# ENTRYPOINT ["python", "main.py"]

# To run the original command and then wait
ENTRYPOINT ["sh", "run_then_wait.sh", "python", "main.py"]
Run Code Online (Sandbox Code Playgroud)

run_then_wait.sh

FROM python:3.7-alpine
ADD run_then_wait.sh .
ADD main.py .

# The original command
# ENTRYPOINT ["python", "main.py"]

# To run the original command and then wait
ENTRYPOINT ["sh", "run_then_wait.sh", "python", "main.py"]
Run Code Online (Sandbox Code Playgroud)

main.py

#!/bin/sh
set -e

# Wait 10 seconds on exit: twice the `buffer_duration` default of 5 seconds
trap 'echo "Waiting for logs to flush to CloudWatch Logs..."; sleep 10' EXIT

# Run the given command
"$@"
Run Code Online (Sandbox Code Playgroud)

希望这种方法可以适应您的情况。您也可以在脚本中实现睡眠,但是要确保它不管终止如何发生都可能比较棘手。

很难证明所提出的解释是正确的,因此我使用上面的代码来测试解决方法是否有效。测试是原始命令vs. with run_then_wait.sh,每次运行30次。结果是,分别在30%的时间和0%的时间观察到此问题。希望这对您同样有效!


Zhe*_*nya 5

刚刚就这个问题联系了 AWS 支持,他们的回复如下:

...

基于这种情况,我可以看到 Fargate 任务中的容器在输出到 stdout/stderr 后快速退出时会发生这种情况。它似乎与 awslogs 驱动程序的工作方式以及 Fargate 中的 Docker 如何与 CW 端点通信有关。

看看我们的内部票证,我可以看到我们的服务团队仍在努力为这个报告的错误找到永久解决方案。不幸的是,没有透露何时部署修复程序的预计时间。但是,我借此机会将此案例添加到内部票证中,以通知团队类似情况并尝试加快流程

同时,可以通过在应用程序的日志输出和进程退出(容器退出)之间添加延迟(~>10 秒)来延长退出容器的生命周期,从而避免这种情况。

...

更新:2019 年 8 月 1 日左右联系 AWS,他们说这个问题已经解决。


归档时间:

查看次数:

1341 次

最近记录:

7 年,1 月 前