{"componentChunkName":"component---src-templates-post-template-jsx","path":"/works/posts/2023-01-29--001","result":{"data":{"site":{"siteMetadata":{"title":"Blog by Eunyoung","subtitle":"작업 기록 블로그","copyright":"© All rights reserved.","author":{"name":"EunYoung","twitter":"#"},"disqusShortname":"","url":"https://ssongey.github.io"}},"markdownRemark":{"id":"466e1688-070e-5674-a5fe-75ab01cdf559","html":"<p>이번에 내가 담당하고 있던 한 서비스를 PM장비에서 K8S로 이전하는 작업을 진행하게 됐는데,<br>\n해당 서버가 출력하고 있던 로그 사이즈가 16k 가 넘어버려서 로그가 제대로 ES에 적재되지 못하는 이슈가 발생했다.<br>\n이에 <strong>fluentd concat plugin</strong> 을 적용한 내용을 기록한다.</p>\n<br/>\n<br/>\n<p>Docker는 16k 버퍼에서 로그메시지를 받고 있기 때문에 기본적으로 16kb를 초과하는 로그 메시지를 분할한다.<br>\n때문에 로그가 16kb가 초과했을 경우 아래와 같이 다음줄에 이어서 로그가 출력된다.  </p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">k8s 환경의 container 로그\n\n<span class=\"token number\">2023</span>-05-29T17:31:12.139673797+09:00 stdout F <span class=\"token punctuation\">{</span><span class=\"token string\">\"log_index_type\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"stat\"</span>,<span class=\"token string\">\"request\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">..</span>.,<span class=\"token string\">\"service_id\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"service-A\"</span>\n<span class=\"token number\">2023</span>-05-29T17:31:12.139673797+09:00 stdout F <span class=\"token string\">\"service_name:\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"서비스에이\"</span><span class=\"token punctuation\">}</span>,<span class=\"token string\">\"response\"</span>:<span class=\"token punctuation\">{</span><span class=\"token punctuation\">..</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span>, request_uuid: <span class=\"token string\">\"TEST-01\"</span><span class=\"token punctuation\">}</span></code></pre></div>\n<br/>\n<p>우리 부서에서는 로그 수집기로 Fluentd 를 사용하고 있었고, 관련 plugin 을 찾아보니 <code class=\"language-text\">fluent-plugin-concat</code> 이 있다는걸 알게되었다.</p>\n<p>참고: <a href=\"https://github.com/fluent-plugins-nursery/fluent-plugin-concat\">https://github.com/fluent-plugins-nursery/fluent-plugin-concat</a></p>\n<br/>\n<h2>1. fluent-plugin-concat 을 추가한 docker file  작성</h2>\n<ul>\n<li><a href=\"https://github.com/fluent/fluentd-kubernetes-daemonset\">https://github.com/fluent/fluentd-kubernetes-daemonset</a> 에서는 여러 fluentd-daemonset 을 제공해준다. 여기서 베이스 이미지를 선택하였다.</li>\n</ul>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\">## v1.16.1-debian-kafka2-1.2_plugin_concat.Dockerfile</span>\nFROM fluentd-kubernetes-daemonset:v1.16.1-debian-kafka2-1.2\n\n<span class=\"token comment\"># Install concat plugin</span>\nRUN gem <span class=\"token function\">install</span> fluent-plugin-concat\n\n<span class=\"token comment\"># Environment variables</span>\nENV <span class=\"token assign-left variable\">FLUENTD_OPT</span><span class=\"token operator\">=</span><span class=\"token string\">\"\"</span>\nENV <span class=\"token assign-left variable\">FLUENTD_CONF</span><span class=\"token operator\">=</span><span class=\"token string\">\"fluent.conf\"</span>\n\n<span class=\"token comment\"># Overwrite ENTRYPOINT to run fluentd as root for /var/log / /var/lib</span>\nENTRYPOINT <span class=\"token punctuation\">[</span><span class=\"token string\">\"tini\"</span>, <span class=\"token string\">\"--\"</span>, <span class=\"token string\">\"/fluentd/entrypoint.sh\"</span><span class=\"token punctuation\">]</span></code></pre></div>\n<br/>\n<h2>2. 어플리케이션 로깅 수정</h2>\n<ul>\n<li>concat plugin 의 usage 내용을 보면 여러 방법이 있지만, 현재 내 상황에 맞는 방법은 start, end regexp 를 사용하는 방법이라 판단하였고, <strong>모든 로그의 시작을 <code class=\"language-text\">log_type</code> 으로, 끝을 <code class=\"language-text\">log_end</code>로 통일</strong>하였다.</li>\n</ul>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">k8s 환경의 container 로그\n\n<span class=\"token number\">2023</span>-05-29T17:31:12.139673797+09:00 stdout F <span class=\"token punctuation\">{</span><span class=\"token string\">\"log_type\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"stat\"</span>,<span class=\"token string\">\"request\"</span><span class=\"token builtin class-name\">:</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">..</span>.,<span class=\"token string\">\"service_id\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"service-A\"</span>\n<span class=\"token number\">2023</span>-05-29T17:31:12.139673797+09:00 stdout F <span class=\"token punctuation\">..</span>.,<span class=\"token string\">\"log_end\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"\"</span><span class=\"token punctuation\">}</span>\n<span class=\"token number\">2023</span>-05-29T17:31:12.139673797+09:00 stdout F <span class=\"token punctuation\">{</span><span class=\"token string\">\"log_type\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"stat\"</span>,<span class=\"token punctuation\">..</span>.,<span class=\"token string\">\"log_end\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"\"</span><span class=\"token punctuation\">}</span></code></pre></div>\n<br/>\n<h2>3. config 설정</h2>\n<ul>\n<li>\n<p>input&#x26;parse 설정</p>\n<ul>\n<li>로컬에서 테스트를 위한 설정 파일이므로, input을 forward 로 설정한다.</li>\n<li>실제 concat이 필요한 부분은 맨 끝 어플리케이션 로그쪽이라 구분을 위해 파싱을 한다.</li>\n</ul>\n</li>\n<li>\n<p>concat 설정</p>\n<ul>\n<li>로그의 시작과 끝의 패턴을 설정해준다.</li>\n<li>참고로, <code class=\"language-text\">separator</code> 은 로그를 concat 할때의 구분자이며, 기본값은 <code class=\"language-text\">\\n</code> 이다. 따로 설정을 해주지 않으면 concat 된 두 로그 사이에 <code class=\"language-text\">\\n</code> 값이 들어가게 된다.</li>\n</ul>\n</li>\n<li>\n<p>output 설정</p>\n<ul>\n<li>로컬에서 테스트를 위한 설정이므로 stdout으로 출력한다.</li>\n</ul>\n</li>\n</ul>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\">## fluentd.conf</span>\n\n<span class=\"token comment\"># 데이터가 위 예시와 같은 포맷으로 들어올때의 input과 parse 설정</span>\n<span class=\"token operator\">&lt;</span>source<span class=\"token operator\">></span>\n  @type                           http\n  port                            <span class=\"token number\">9880</span>\n  <span class=\"token builtin class-name\">bind</span>                            <span class=\"token number\">0.0</span>.0.0\n  <span class=\"token operator\">&lt;</span>parse<span class=\"token operator\">></span>\n    @type                         regexp\n    expression                    /^<span class=\"token punctuation\">(</span>?<span class=\"token operator\">&lt;</span>time<span class=\"token operator\">></span><span class=\"token punctuation\">[</span>^ <span class=\"token punctuation\">]</span>+<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">(</span>?<span class=\"token operator\">&lt;</span>stream<span class=\"token operator\">></span>stdout<span class=\"token operator\">|</span>stderr<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">(</span>?<span class=\"token operator\">&lt;</span>flags<span class=\"token operator\">></span><span class=\"token punctuation\">[</span>^ <span class=\"token punctuation\">]</span>+<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">(</span>?<span class=\"token operator\">&lt;</span>log<span class=\"token operator\">></span>.*<span class=\"token punctuation\">)</span>$/\n  <span class=\"token operator\">&lt;</span>/parse<span class=\"token operator\">></span>\n<span class=\"token operator\">&lt;</span>/source<span class=\"token operator\">></span>\n\n<span class=\"token comment\">#multiline start&amp;end regexp</span>\n<span class=\"token operator\">&lt;</span>filter **<span class=\"token operator\">></span>\n  @type                           concat\n  key                             log\n  separator                       <span class=\"token string\">\"\"</span>\n  multiline_start_regexp          /^<span class=\"token punctuation\">{</span><span class=\"token punctuation\">\\</span>\"log_type/\n  multiline_end_regexp            /log_end<span class=\"token punctuation\">\\</span>\":<span class=\"token punctuation\">\\</span>\"<span class=\"token punctuation\">\\</span>\"<span class=\"token punctuation\">}</span>$/\n<span class=\"token operator\">&lt;</span>/filter<span class=\"token operator\">></span>\n\n<span class=\"token operator\">&lt;</span>match **<span class=\"token operator\">></span>\n  @type stdout\n<span class=\"token operator\">&lt;</span>/match<span class=\"token operator\">></span></code></pre></div>\n<br/>\n<h3>4. 도커파일 빌드 후 실행</h3>\n<ul>\n<li>위에서 작성한 도커파일 빌드 후 실행한다.</li>\n</ul>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ docker build -t fluentd-kubernetes-daemonset:v1.16.1-debian-kafka2-1.2-with_concat_plugin -f v1.16.1-debian-kafka2-1.2_plugin_concat.Dockerfile <span class=\"token builtin class-name\">.</span>\n\n$ docker run --name fluentd <span class=\"token punctuation\">\\</span>\n\t-p <span class=\"token number\">9880</span>:9880 <span class=\"token punctuation\">\\</span>\n\t-v <span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token builtin class-name\">pwd</span><span class=\"token variable\">)</span></span>/fluentd.conf:/fluentd/etc/fluentd.conf <span class=\"token punctuation\">\\</span>\n\t-e <span class=\"token assign-left variable\">FLUENTD_CONF</span><span class=\"token operator\">=</span>fluentd.conf <span class=\"token punctuation\">\\</span>\n\tfluentd-kubernetes-daemonset:v1.16.1-debian-kafka2-1.2-with_concat_plugin</code></pre></div>\n<br/>\n<h3>5. 테스트</h3>\n<ul>\n<li>fluentd 로 보낼 테스트파일 2개를 생성한다.</li>\n</ul>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\"># test1.text</span>\n<span class=\"token number\">2023</span>-05-29T17:31:12.139673797+09:00 stdout F <span class=\"token punctuation\">{</span><span class=\"token string\">\"log_type\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"stat\"</span>,<span class=\"token string\">\"phase\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"beta\"</span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\"># test2.text</span>\n<span class=\"token number\">2023</span>-05-29T17:31:12.139673797+09:00 stdout F <span class=\"token string\">\"level\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"INFO\"</span>,<span class=\"token string\">\"log_end\"</span><span class=\"token builtin class-name\">:</span><span class=\"token string\">\"\"</span><span class=\"token punctuation\">}</span></code></pre></div>\n<br/>\n<ul>\n<li>먼저 test1.text 파일을 보내면 fluentd 로그에 stdout 이 나오지 않지만,</li>\n</ul>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">curl</span> -X POST <span class=\"token string\">\"http://127.0.0.1:9880/sample.test\"</span> -d @test1.text</code></pre></div>\n<ul>\n<li>다음에 test2.text 파일을 보내면, test1.text의 로그와 함께 concat이 되어 fluentd 로그에 출력되는걸 확인할 수 있다.</li>\n</ul>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">curl</span> -X POST <span class=\"token string\">\"http://127.0.0.1:9880/sample.test\"</span> -d @test2.text</code></pre></div>\n<p>\n  <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/devHistoryBlog/static/e1dafca50b6d901cd97dd0d51a9aa90c/e4d4a/Untitled.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n  \n  <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 960px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 6.25%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAYAAADeko4lAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAM0lEQVQI1z3IwQYAQAhF0aGSRKn//9c3tHiLw3Xf7qK7T1WxZ4YvMxERMDMSEba7Q1XPB4MfFkhxCpFzAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n    >\n      <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\"\n        alt=\"Untitled\"\n        title=\"\"\n        src=\"/devHistoryBlog/static/e1dafca50b6d901cd97dd0d51a9aa90c/d9199/Untitled.png\"\n        srcset=\"/devHistoryBlog/static/e1dafca50b6d901cd97dd0d51a9aa90c/8ff5a/Untitled.png 240w,\n/devHistoryBlog/static/e1dafca50b6d901cd97dd0d51a9aa90c/e85cb/Untitled.png 480w,\n/devHistoryBlog/static/e1dafca50b6d901cd97dd0d51a9aa90c/d9199/Untitled.png 960w,\n/devHistoryBlog/static/e1dafca50b6d901cd97dd0d51a9aa90c/07a9c/Untitled.png 1440w,\n/devHistoryBlog/static/e1dafca50b6d901cd97dd0d51a9aa90c/29114/Untitled.png 1920w,\n/devHistoryBlog/static/e1dafca50b6d901cd97dd0d51a9aa90c/e4d4a/Untitled.png 2198w\"\n        sizes=\"(max-width: 960px) 100vw, 960px\"\n      />\n    </span>\n  </span>\n  \n  </a>\n    </p>","fields":{"tagSlugs":["/tags/docker/","/tags/fluentd/"],"slug":"/works/posts/2023-01-29--001"},"frontmatter":{"title":"docker 로그 사이즈 16k limit 에 따른 조치","tags":["docker","fluentd"],"date":"2023-01-29","description":"fluent-concat-plugin"}}},"pageContext":{"slug":"/works/posts/2023-01-29--001"}},"staticQueryHashes":[]}