<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>dbswjdahr 님의 블로그</title>
    <link>https://dbswjdahr.tistory.com/</link>
    <description>dbswjdahr 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Tue, 2 Jun 2026 02:20:27 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>dbswjdahr</managingEditor>
    <item>
      <title>모니터링 서버 구축해보기-4</title>
      <link>https://dbswjdahr.tistory.com/29</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;alertmanager가 설정됐으면 이걸 이제 받는 쪽이 있어야 함&lt;br /&gt;웹훅을 이용해 슬랙으로 메시지가 가게 할 수 있다 그래서 슬랙을 사용함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 새 작업공간을 만들어주고 웹훅도 활성화하고 새 웹훅 주소를 만들어준다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1843&quot; data-origin-height=&quot;782&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GNvT0/dJMcain9Keu/KuyHnlovsH2jm6Qho4nGa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GNvT0/dJMcain9Keu/KuyHnlovsH2jm6Qho4nGa0/img.png&quot; data-alt=&quot;새 앱을 만들기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GNvT0/dJMcain9Keu/KuyHnlovsH2jm6Qho4nGa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGNvT0%2FdJMcain9Keu%2FKuyHnlovsH2jm6Qho4nGa0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;272&quot; data-origin-width=&quot;1843&quot; data-origin-height=&quot;782&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;새 앱을 만들기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1155&quot; data-origin-height=&quot;798&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5cCGG/dJMcagDSlMH/of7P02NbPN1Ok2EkTNkKn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5cCGG/dJMcagDSlMH/of7P02NbPN1Ok2EkTNkKn1/img.png&quot; data-alt=&quot;웹훅 오는 거 허용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5cCGG/dJMcagDSlMH/of7P02NbPN1Ok2EkTNkKn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5cCGG%2FdJMcagDSlMH%2Fof7P02NbPN1Ok2EkTNkKn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;442&quot; data-origin-width=&quot;1155&quot; data-origin-height=&quot;798&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;웹훅 오는 거 허용&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1169&quot; data-origin-height=&quot;695&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdHOjF/dJMcaaXXBnV/kaWONbWaAZKqYJLK1iBXT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdHOjF/dJMcaaXXBnV/kaWONbWaAZKqYJLK1iBXT0/img.png&quot; data-alt=&quot;새 웹훅 주소 만들기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdHOjF/dJMcaaXXBnV/kaWONbWaAZKqYJLK1iBXT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdHOjF%2FdJMcaaXXBnV%2FkaWONbWaAZKqYJLK1iBXT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;380&quot; data-origin-width=&quot;1169&quot; data-origin-height=&quot;695&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;새 웹훅 주소 만들기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;711&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6AhAO/dJMcacuHX7K/E8if4XU0d3ockgIMZCvnXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6AhAO/dJMcacuHX7K/E8if4XU0d3ockgIMZCvnXK/img.png&quot; data-alt=&quot;웹훅 채널 만들어 지정해주기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6AhAO/dJMcacuHX7K/E8if4XU0d3ockgIMZCvnXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6AhAO%2FdJMcacuHX7K%2FE8if4XU0d3ockgIMZCvnXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;373&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;711&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;웹훅 채널 만들어 지정해주기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;666&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HoDjw/dJMcabP6nhy/h1Oj2P2nP7q1Iw6hvJQMkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HoDjw/dJMcabP6nhy/h1Oj2P2nP7q1Iw6hvJQMkK/img.png&quot; data-alt=&quot;웹훅 URL 생김&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HoDjw/dJMcabP6nhy/h1Oj2P2nP7q1Iw6hvJQMkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHoDjw%2FdJMcabP6nhy%2Fh1Oj2P2nP7q1Iw6hvJQMkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;560&quot; height=&quot;431&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;666&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;웹훅 URL 생김&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그러면 URL이 이렇게 뜨는데 /etc/alertmanger/alertmanager.yml에 웹훅 주소를 넣어주면 됨&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1308&quot; data-origin-height=&quot;639&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bobw0l/dJMcaap7FBn/uRe00LpgmA1wkx07aY748K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bobw0l/dJMcaap7FBn/uRe00LpgmA1wkx07aY748K/img.png&quot; data-alt=&quot;alertmanager.yml파일 설정해주기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bobw0l/dJMcaap7FBn/uRe00LpgmA1wkx07aY748K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbobw0l%2FdJMcaap7FBn%2FuRe00LpgmA1wkx07aY748K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;313&quot; data-origin-width=&quot;1308&quot; data-origin-height=&quot;639&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;alertmanager.yml파일 설정해주기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 시스템 재시작해서 적용시켜주고&lt;/p&gt;
&lt;pre id=&quot;code_1763226703664&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# systemctl restart alertmanager&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로메테우스 쪽에서도 맞춰줘야 함&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1593&quot; data-origin-height=&quot;947&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mMSRU/dJMcagjzyP2/Bx1QMVlCt9kigQNzZ6yCak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mMSRU/dJMcagjzyP2/Bx1QMVlCt9kigQNzZ6yCak/img.png&quot; data-alt=&quot;prometheus.yml 얼러팅이랑 룰파일 맞춰주기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mMSRU/dJMcagjzyP2/Bx1QMVlCt9kigQNzZ6yCak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmMSRU%2FdJMcagjzyP2%2FBx1QMVlCt9kigQNzZ6yCak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;380&quot; data-origin-width=&quot;1593&quot; data-origin-height=&quot;947&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;prometheus.yml 얼러팅이랑 룰파일 맞춰주기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;alert 보낼 규칙을 지정하고 prometheus.yml에도 지정해줌 아까 본 700MiB 기준 메모리 사용량을 임의로 지정해줌&lt;/p&gt;
&lt;pre id=&quot;code_1763226781321&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# vi /etc/prometheus/alert-test.yml
groups:
- name: memory_alerts
  rules:
  - alert: HostMemoryUsageCritical
    expr: node_memory_Active_bytes{job=&quot;wordpress-lemp&quot;} &amp;gt; 700000000
    for: 1m
    labels:
      severity: 'critical'
    annotations:
      summary: 'Host memory usage is critical on {{ $labels.instance }}'
      description: 'Active memory is {{ $value }}bytes. (Limit 700MB)'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이것도 재시작&lt;/p&gt;
&lt;pre id=&quot;code_1763227031585&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# systemctl restart prometheus&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 브라우저로 들어가 프로메테우스에서 alert 연결이 된지 확인, 사용한 쿼리문이 그대로 뜨고 초록색으로 ok임&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1801&quot; data-origin-height=&quot;715&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d70XPa/dJMb99ShMBc/2WP5ybOaErLEvS7POgtQq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d70XPa/dJMb99ShMBc/2WP5ybOaErLEvS7POgtQq0/img.png&quot; data-alt=&quot;얼러트 연결&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d70XPa/dJMb99ShMBc/2WP5ybOaErLEvS7POgtQq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd70XPa%2FdJMb99ShMBc%2F2WP5ybOaErLEvS7POgtQq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;254&quot; data-origin-width=&quot;1801&quot; data-origin-height=&quot;715&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;얼러트 연결&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 슬랙을 켜고 아까 만든 메모리 하마 스크립트를 실행시키고 기다리면?&lt;/p&gt;
&lt;pre id=&quot;code_1763227091625&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@Alma ~]# python3 main.py&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;913&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MqJos/dJMcaajmfya/QfjBmnKrrkbQphDzVWMK0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MqJos/dJMcaajmfya/QfjBmnKrrkbQphDzVWMK0K/img.png&quot; data-alt=&quot;여기 메시지가 올 것&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MqJos/dJMcaajmfya/QfjBmnKrrkbQphDzVWMK0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMqJos%2FdJMcaajmfya%2FQfjBmnKrrkbQphDzVWMK0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;416&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;913&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;여기 메시지가 올 것&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기는 메모리 부하 유도할 때 프로메테우스에서 빨갛게 불타는 게 보임&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1841&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkhNLb/dJMcahCMCOT/XeBGvKzPk880i2l1D0bQZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkhNLb/dJMcahCMCOT/XeBGvKzPk880i2l1D0bQZ0/img.png&quot; data-alt=&quot;불타는 알림&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkhNLb/dJMcahCMCOT/XeBGvKzPk880i2l1D0bQZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkhNLb%2FdJMcahCMCOT%2FXeBGvKzPk880i2l1D0bQZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;252&quot; data-origin-width=&quot;1841&quot; data-origin-height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;불타는 알림&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1341&quot; data-origin-height=&quot;853&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qvgDO/dJMcabo1Z4A/KjpF8y01EXJrQvsjBs13HK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qvgDO/dJMcabo1Z4A/KjpF8y01EXJrQvsjBs13HK/img.png&quot; data-alt=&quot;알림 성공적&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qvgDO/dJMcabo1Z4A/KjpF8y01EXJrQvsjBs13HK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqvgDO%2FdJMcabo1Z4A%2FKjpF8y01EXJrQvsjBs13HK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;407&quot; data-origin-width=&quot;1341&quot; data-origin-height=&quot;853&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;알림 성공적&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종적으로는 이렇게 알림이 보내진 게 확인이 된다!&lt;/p&gt;</description>
      <category>리눅스/실습</category>
      <category>alertmanager</category>
      <category>prometheus</category>
      <category>promql</category>
      <author>dbswjdahr</author>
      <guid isPermaLink="true">https://dbswjdahr.tistory.com/29</guid>
      <comments>https://dbswjdahr.tistory.com/29#entry29comment</comments>
      <pubDate>Sun, 16 Nov 2025 04:33:55 +0900</pubDate>
    </item>
    <item>
      <title>모니터링 서버 구축해보기-3</title>
      <link>https://dbswjdahr.tistory.com/28</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 제공되는 대시보드와 거기에 맞춰 미리 적용된 쿼리문들이 있어 웬만하면 이것들로 대략적인 모니터링이 가능한데,&lt;br /&gt;거기서 더 나아가서 직접 쿼리문을 작성해서 필요한 정보들만 뽑아낼 수도 있다. &lt;br /&gt;Prometheus에서 사용하는 쿼리라 PromQL이라고 부르는데 SQL이랑은 사용법이 꽤나 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 사용하면 메트릭 데이터를 기준으로 이상치를 탐지하거나 뭔가 이상한 게 생기면 감지해서 알림 전송이 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 Alertmanager라는 게 있는데 이게 그 기능을 하게 해줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리문은 선택자{job=&quot;&amp;lt;잡이름&amp;gt;&quot;} 이런 식으로 쓰이고 함수 안에 넣을 수도 있음 &lt;br /&gt;sum, avg, rate, min 등 판다스나 엑셀에서 친숙하게 보이는 그런 것들이 사용 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이드바에 있는 Explore를 타고 들어오면 저렇게 쿼리, 그래프, raw data가 구분되어 있고 쿼리에 크게 메트릭, 레이블 필터가 보임&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;996&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5EfkF/dJMcagw6Fwz/ny7Sdrn4HdriHD7KjtEbQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5EfkF/dJMcagw6Fwz/ny7Sdrn4HdriHD7KjtEbQ1/img.png&quot; data-alt=&quot;promql 써보는 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5EfkF/dJMcagw6Fwz/ny7Sdrn4HdriHD7KjtEbQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5EfkF%2FdJMcagw6Fwz%2Fny7Sdrn4HdriHD7KjtEbQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;332&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;996&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;promql 써보는 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메트릭 종류도 매우매우 많고 레이블 필터도 아주 많아 이걸 직접 SQL DML 쓰듯이 쓰기 꽤나 번거로운걸 아는지 친절하게 드랍다운으로 고를 수 있게 나옴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 오른쪽 빌더랑 코드가 있는데 코드를 누르면 직접 쿼리를 칠 수도 있음 자동완성을 지원해주긴 함&lt;br /&gt;일단 PromQL의 감을 익히기 위해 빌더말고 코드를 직접 입력해보기로 함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 간단하게 전체 노드의 메모리 사용량을 조회해볼 수 있음&lt;br /&gt;메트릭 이름은 외워서 쓰긴 쉽지 않지만 읽기에는 무척 직관적이라 본다면 뭔지 대략 알 수 있다&lt;br /&gt;아래는 노드 전체의 사용되는 메모리 바이트를 보여줌 이건 node exporter가 돌아가서 측정이 됨&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1451&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBKhL1/dJMcafkFfO7/6stL7HyCIl5vMvNylIHujK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBKhL1/dJMcafkFfO7/6stL7HyCIl5vMvNylIHujK/img.png&quot; data-alt=&quot;노드 메모리 사용량&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBKhL1/dJMcafkFfO7/6stL7HyCIl5vMvNylIHujK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBKhL1%2FdJMcafkFfO7%2F6stL7HyCIl5vMvNylIHujK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;315&quot; data-origin-width=&quot;1451&quot; data-origin-height=&quot;714&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;노드 메모리 사용량&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리를 축내는 코드를 작성하고 실행시켜보고 다시 확인해보도록 함&lt;br /&gt;Alma에 파이썬이 내장되어 있으니 간단하게 작성, 실행 가능한 파이썬으로 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트를 두고 계속 쌓아서 메모리 용량을 잡아먹게 해봄&lt;/p&gt;
&lt;pre id=&quot;code_1763223029933&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@Alma ~]# vi main.py
import time

string = &quot;안녕?&quot;
arr = []

def loop(string):
    arr.append(string)
    print(len(arr))

def main():

    while True:
        loop(string)

        if len(arr) % 1000000 == 0 :
            time.sleep(0.1)

if __name__ == &quot;__main__&quot;:
    main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자가 미치도록 치솟는다. &quot;안녕?&quot; 문자열이 해당 숫자만큼 반복한 리스트가 있는 상태&lt;/p&gt;
&lt;pre id=&quot;code_1763223804903&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@Alma ~]# python3 main.py
...
12144416
12144417
12144418
12144419
12144420
12144421
12144422
12144423
12144424
12144425
12144426
12144427
12144428
12144429
12144430
12144431
12144432
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼마 지나지 않아 갑자기 치솟은 게 확인 됨&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1454&quot; data-origin-height=&quot;769&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GPtBx/dJMcacO0CAe/xKDt92kQQ1GJ3cBs4sInNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GPtBx/dJMcacO0CAe/xKDt92kQQ1GJ3cBs4sInNK/img.png&quot; data-alt=&quot;노드 메모리 사용량 확인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GPtBx/dJMcacO0CAe/xKDt92kQQ1GJ3cBs4sInNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGPtBx%2FdJMcacO0CAe%2FxKDt92kQQ1GJ3cBs4sInNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;338&quot; data-origin-width=&quot;1454&quot; data-origin-height=&quot;769&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;노드 메모리 사용량 확인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이걸 가지고 평균 메모리 사용량이랑 비교해보면 이렇게 나옴 1분 기준으로 비교한 값과 전체 평균&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1317&quot; data-origin-height=&quot;745&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdqw8X/dJMcahpfsyz/Feu8WijB6GVrK8zjrzcr2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdqw8X/dJMcahpfsyz/Feu8WijB6GVrK8zjrzcr2k/img.png&quot; data-alt=&quot;1분 당 평균 사용량 (초록선) 전체 평균 사용량 (노란선)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdqw8X/dJMcahpfsyz/Feu8WijB6GVrK8zjrzcr2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbdqw8X%2FdJMcahpfsyz%2FFeu8WijB6GVrK8zjrzcr2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;362&quot; data-origin-width=&quot;1317&quot; data-origin-height=&quot;745&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1분 당 평균 사용량 (초록선) 전체 평균 사용량 (노란선)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 1분을 기준으로 잡은 부분이 파이썬으로 메모리를 잡아버렸기 때문에 더 높게 잡혀 약 700MiB가 넘은 게 2번 정도 보임&lt;br /&gt;이걸 기준으로 알림을 발생시켜보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 말한 Alertmanager라는 걸 설치하고 설정해주면 됨본적으로 제공되는 대시보드와 거기에 맞춰 미리 적용된 쿼리문들이 있어 웬만하면 이것들로 대략적인 모니터링이 가능한데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거기서 더 나아가서 직접 쿼리문을 작성해서 필요한 정보들만 뽑아낼 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Prometheus에서 사용하는 쿼리라 PromQL이라고 부르는데 SQL이랑은 사용법이 꽤나 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 사용하면 메트릭 데이터를 기준으로 이상치를 탐지하거나 뭔가 이상한 게 생기면 감지해서 알림 전송이 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 Alertmanager라는 게 있는데 이게 그 기능을 하게 해줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리문은 선택자{job=&quot;&amp;lt;잡이름&amp;gt;&quot;} 이런 식으로 쓰이고 함수 안에 넣을 수도 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sum, avg, rate, min 등 판다스나 엑셀에서 친숙하게 보이는 그런 것들이 사용 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이드바에 있는 Explore를 타고 들어오면 저렇게 쿼리, 그래프, raw data가 구분되어 있고 쿼리에 크게 메트릭, 레이블 필터가 보임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;￼&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;promql 써보는 페이지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메트릭 종류도 매우매우 많고 레이블 필터도 아주 많아 이걸 직접 SQL DML 쓰듯이 쓰기 꽤나 번거로운걸 아는지 친절하게 드랍다운으로 고를 수 있게 나옴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 오른쪽 빌더랑 코드가 있는데 코드를 누르면 직접 쿼리를 칠 수도 있음 자동완성을 지원해주긴 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 PromQL의 감을 익히기 위해 빌더말고 코드를 직접 입력해보기로 함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 간단하게 전체 노드의 메모리 사용량을 조회해볼 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메트릭 이름은 외워서 쓰긴 쉽지 않지만 읽기에는 무척 직관적이라 본다면 뭔지 대략 알 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 노드 전체의 사용되는 메모리 바이트를 보여줌 이건 node exporter가 돌아가서 측정이 됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;￼&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 메모리 사용량&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리를 축내는 코드를 작성하고 실행시켜보고 다시 확인해보도록 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Alma에 파이썬이 내장되어 있으니 간단하게 작성, 실행 가능한 파이썬으로 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트를 두고 계속 쌓아서 메모리 용량을 잡아먹게 해봄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[root@Alma ~]# vi main.py&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;import time&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;string = &quot;안녕?&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;arr = []&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;def loop(string):&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; arr.append(string)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; print(len(arr))&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;def main():&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; while True:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; loop(string)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if len(arr) % 1000000 == 0 :&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; time.sleep(0.1)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if __name__ == &quot;__main__&quot;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; main()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자가 미치도록 치솟는다. &quot;안녕?&quot; 문자열이 해당 숫자만큼 반복한 리스트가 있는 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[root@Alma ~]# python3 main.py&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144416&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144417&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144418&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144419&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144420&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144421&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144422&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144423&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144424&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144425&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144426&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144427&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144428&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144429&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144430&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144431&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12144432&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼마 지나지 않아 갑자기 치솟은 게 확인 됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;￼&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 메모리 사용량 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이걸 가지고 평균 메모리 사용량이랑 비교해보면 이렇게 나옴 1분 기준으로 비교한 값과 전체 평균&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;￼&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1분 당 평균 사용량 (초록선) 전체 평균 사용량 (노란선)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 1분을 기준으로 잡은 부분이 파이썬으로 메모리를 잡아버렸기 때문에 더 높게 잡혀 약 700MiB가 넘은 게 2번 정도 보임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 기준으로 알림을 발생시켜보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 말한 Alertmanager라는 걸 설치하고 설정해주면 됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://prometheus.io/download/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://prometheus.io/download/&lt;/a&gt; 프로메테우스 받았던 여기서 찾기 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;prometheus 깔았던 것처럼 비슷하게 해줌 &lt;br /&gt;설정 파일이 있으니 /etc 밑에 디렉터리 만들어 지정해주고 사용자 만들어서 지정해주고 등등&lt;/p&gt;
&lt;pre id=&quot;code_1763225166671&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# wget https://github.com/prometheus/alertmanager/releases/download/v0.29.0/alertmanager-0.29.0.linux-amd64.tar.gz
[root@monitoring ~]# tar zvxf alertmanager-0.29.0.linux-amd64.tar.gz
[root@monitoring alertmanager-0.29.0.linux-amd64]# ll
total 65976
-rw-r--r--. 1 mysqld_exporter mysqld_exporter    11357 Nov  4 22:23 LICENSE
-rw-r--r--. 1 mysqld_exporter mysqld_exporter      311 Nov  4 22:23 NOTICE
-rwxr-xr-x. 1 mysqld_exporter mysqld_exporter 38405202 Nov  4 22:09 alertmanager
-rw-r--r--. 1 mysqld_exporter mysqld_exporter      356 Nov  4 22:23 alertmanager.yml
-rwxr-xr-x. 1 mysqld_exporter mysqld_exporter 29126915 Nov  4 22:09 amtool

[root@monitoring alertmanager-0.29.0.linux-amd64]# mv alertmanager amtool /usr/local/bin/
[root@monitoring alertmanager-0.29.0.linux-amd64]# mkdir -p /var/lib/alertmanager
[root@monitoring alertmanager-0.29.0.linux-amd64]# mkdir -p /etc/alertmanager
[root@monitoring alertmanager-0.29.0.linux-amd64]# mv alertmanager.yml /etc/alertmanager/

[root@monitoring alertmanager-0.29.0.linux-amd64]# chown -R alertmanager:alertmanager /etc/alertmanager/
[root@monitoring alertmanager-0.29.0.linux-amd64]# chown -R alertmanager:alertmanager /var/lib/alertmanager/
[root@monitoring alertmanager-0.29.0.linux-amd64]# chown -R alertmanager:alertmanager /usr/local/bin/alertmanager  /usr/local/bin/amtool&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템 만드는 것도 동일, 잔여 파일 삭제들도 마찬가지, 시스템 대몬 재시작 및 활성화까&lt;/p&gt;
&lt;pre id=&quot;code_1763225429156&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# vi /etc/systemd/system/alertmanager.service
[Unit]
Description=Alertmanager
Wants=network-online.target
After=network-online.target

[Service]
User=alertmanager
Group=alertmanager
Type=simple
ExecStart=/usr/local/bin/alertmanager \
  --config.file /etc/alertmanager/alertmanager.yml \
  --storage.path /var/lib/alertmanager/

[Install]
WantedBy=multi-user.target
[root@monitoring ~]# rm alertmanager-0.29.0.linux-amd64* -rf

[root@monitoring ~]# systemctl daemon-reload
[root@monitoring ~]# systemctl enable --now alertmanager
Created symlink /etc/systemd/system/multi-user.target.wants/alertmanager.service &amp;rarr; /etc/systemd/system/alertmanager.service.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근 허용까지 해주면 얼러트매니저 설정도 끝, 얘는 대시보드가 9093번이다&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1763225601637&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# chcon -t bin_t /usr/local/bin/alertmanager
[root@monitoring ~]# chcon -t bin_t /usr/local/bin/amtool
[root@monitoring ~]# ss -tlnup | grep al
Netid State  Recv-Q Send-Q Local Address:Port  Peer Address:PortProcess                                                                                     
udp   UNCONN 0      0                  *:9094             *:*    users:((&quot;alertmanager&quot;,pid=11420,fd=6))                                                    
tcp   LISTEN 0      4096               *:9094             *:*    users:((&quot;alertmanager&quot;,pid=11420,fd=3))                                                    
tcp   LISTEN 0      4096               *:9093             *:*    users:((&quot;alertmanager&quot;,pid=11420,fd=7))                                                    
[root@monitoring ~]# firewall-cmd --add-port 9093/tcp --permanent
success
[root@monitoring ~]# firewall-cmd --reload
success&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얘도 브라우저에서 정상적으로 붙었나 확인이 가능 잘 된 듯&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1456&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mxUss/dJMcahCMCyt/urwl9p7VFiZRmy5VD8uxWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mxUss/dJMcahCMCyt/urwl9p7VFiZRmy5VD8uxWk/img.png&quot; data-alt=&quot;얼러트매니저 확인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mxUss/dJMcahCMCyt/urwl9p7VFiZRmy5VD8uxWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmxUss%2FdJMcahCMCyt%2Furwl9p7VFiZRmy5VD8uxWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;320&quot; data-origin-width=&quot;1456&quot; data-origin-height=&quot;728&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;얼러트매니저 확인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>리눅스/실습</category>
      <category>alertmanager</category>
      <category>grafana</category>
      <category>prometheus</category>
      <category>promql</category>
      <author>dbswjdahr</author>
      <guid isPermaLink="true">https://dbswjdahr.tistory.com/28</guid>
      <comments>https://dbswjdahr.tistory.com/28#entry28comment</comments>
      <pubDate>Sun, 16 Nov 2025 01:58:31 +0900</pubDate>
    </item>
    <item>
      <title>모니터링 서버 구축해보기-2</title>
      <link>https://dbswjdahr.tistory.com/27</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이전 DB 대시보드를 추가해봤으니 이번엔 VM 자체를 관리할 수 있는 노드 대시보드도 추가해봄&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1371&quot; data-origin-height=&quot;878&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmJ9b8/dJMcaaRbpza/Bgy8iOsjNWUGqCA98UYL90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmJ9b8/dJMcaaRbpza/Bgy8iOsjNWUGqCA98UYL90/img.png&quot; data-alt=&quot;노드 대시보드 추가&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmJ9b8/dJMcaaRbpza/Bgy8iOsjNWUGqCA98UYL90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmJ9b8%2FdJMcaaRbpza%2FBgy8iOsjNWUGqCA98UYL90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;410&quot; data-origin-width=&quot;1371&quot; data-origin-height=&quot;878&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;노드 대시보드 추가&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 탬플릿 번호가 1860으로 불러오면 된다. 해당 VM 전체 리소스를 확인이 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1467&quot; data-origin-height=&quot;787&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wgm5Y/dJMcacg9198/jUDKaf9Wf7hFzdusOewTeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wgm5Y/dJMcacg9198/jUDKaf9Wf7hFzdusOewTeK/img.png&quot; data-alt=&quot;노드 대시보드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wgm5Y/dJMcacg9198/jUDKaf9Wf7hFzdusOewTeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwgm5Y%2FdJMcacg9198%2FjUDKaf9Wf7hFzdusOewTeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;343&quot; data-origin-width=&quot;1467&quot; data-origin-height=&quot;787&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;노드 대시보드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이렇게 총 2개의 대시보드가 추가된 걸 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1847&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfNQC7/dJMcagjyT3p/VbHK7MCkjy0c4BA9flHqt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfNQC7/dJMcagjyT3p/VbHK7MCkjy0c4BA9flHqt0/img.png&quot; data-alt=&quot;대시보드 목록&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfNQC7/dJMcagjyT3p/VbHK7MCkjy0c4BA9flHqt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfNQC7%2FdJMcagjyT3p%2FVbHK7MCkjy0c4BA9flHqt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;281&quot; data-origin-width=&quot;1847&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대시보드 목록&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 nginx 웹 서버 자체로 들어오는 요청들도 확인이 가능하다 nginx를 사용해서 nginx exporter를 추가해주면 되는데,&lt;br /&gt;이건 프로메테우스 다운로드 페이지에 없어서 깃헙에서 찾아서 가져옴&lt;/p&gt;
&lt;pre id=&quot;code_1763105751036&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@Alma ~]# wget https://github.com/nginx/nginx-prometheus-exporter/releases/download/v1.5.1/nginx-prometheus-exporter_1.5.1_linux_amd64.tar.gz
[root@Alma ~]# tar xzfv nginx-prometheus-exporter_1.5.1_linux_amd64.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열린 서버 443 부분에 이걸 추가한다. 그리곤 이전에 해줬던 거랑 비슷하게 설정해&lt;/p&gt;
&lt;pre id=&quot;code_1763106238805&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@Alma ~]# vi /etc/nginx/nginx.conf

        location /stub_status {
            stub_status;
            allow 127.0.0.1;
            deny all;
        }
[root@Alma ~]# mv nginx-prometheus-exporter /usr/local/bin/
[root@Alma ~]# useradd -M -s /sbin/nologin nginx_exporter
[root@Alma ~]# vi /etc/systemd/system/nginx-exporter.service
[Unit]
Description=Nginx Exporter
Wants=network-online.target
After=network-online.target

[Service]
User=nginx_exporter
Group=nginx_exporter
Type=simple
ExecStart=/usr/local/bin/nginx-prometheus-exporter \
  -nginx.scrape-uri http://127.0.0.1/stub_status

[Install]
WantedBy=multi-user.target
[root@Alma ~]# chcon -t bin_t /usr/local/bin/nginx-prometheus-exporter
[root@Alma ~]# systemctl daemon-reload
[root@Alma ~]# systemctl enable --now nginx-exporter
[root@Alma ~]# firewall-cmd --add-port=9113/tcp --permanent
success
[root@Alma ~]# firewall-cmd --reload
success&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기도&lt;/p&gt;
&lt;pre id=&quot;code_1763106556795&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# vi /etc/prometheus/prometheus.yml

  - job_name: &quot;wordpress-lemp&quot;
    static_configs:
      - targets: [&quot;wordpress:9100&quot;, &quot;wordpress:9104&quot;, &quot;wordpress:9113&quot;] ## -- 9113 추가
      
[root@monitoring ~]# systemctl restart prometheus&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nginx exporter 엔드포인트도 추가됨&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1860&quot; data-origin-height=&quot;858&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VkenY/dJMcahQi91w/SGwVbWHfifdOm4oVHr4Hrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VkenY/dJMcahQi91w/SGwVbWHfifdOm4oVHr4Hrk/img.png&quot; data-alt=&quot;9113 nginx까지 추가&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VkenY/dJMcahQi91w/SGwVbWHfifdOm4oVHr4Hrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVkenY%2FdJMcahQi91w%2FSGwVbWHfifdOm4oVHr4Hrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;295&quot; data-origin-width=&quot;1860&quot; data-origin-height=&quot;858&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;9113 nginx까지 추가&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nginx는 14900번이 대시보드 ID다. 동일하게 import 후 추가해주면? 아래처럼 뜬다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1838&quot; data-origin-height=&quot;822&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5m2yH/dJMcabo1idS/tYc2za9QsVfa0hHQtGkYS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5m2yH/dJMcabo1idS/tYc2za9QsVfa0hHQtGkYS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5m2yH/dJMcabo1idS/tYc2za9QsVfa0hHQtGkYS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5m2yH%2FdJMcabo1idS%2FtYc2za9QsVfa0hHQtGkYS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;286&quot; data-origin-width=&quot;1838&quot; data-origin-height=&quot;822&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭔가 잘 뜨긴 하는데 nginx가 먹는 CPU랑 메모리는 데이터가 뜨지 않는다. 이건 기본 쿼리문이 맞지 않아서 생기는 문제로&lt;br /&gt;이걸 튜닝해줘야 잘 뜨는데 좀 복잡하기 때문에 추후에 다루도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 대시보드에 보면 각각 박스 우측 상단에 마우스 포인터 갖다대면 점 3개가 뜨는데 그거 클릭하고 edit 누르면 편집창으로 들어감&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1463&quot; data-origin-height=&quot;794&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9vFGs/dJMcacuHjtI/xBGKyRn16M4cuiSQkDZfZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9vFGs/dJMcacuHjtI/xBGKyRn16M4cuiSQkDZfZ1/img.png&quot; data-alt=&quot;패널 편집창&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9vFGs/dJMcacuHjtI/xBGKyRn16M4cuiSQkDZfZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9vFGs%2FdJMcacuHjtI%2FxBGKyRn16M4cuiSQkDZfZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;347&quot; data-origin-width=&quot;1463&quot; data-origin-height=&quot;794&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;패널 편집창&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저기 아래 하이라이팅된 promql 구문이 보이는데 간단하게 sql이랑 비슷하게 퀴리로 데이터 조회할 때 사용하는 그런 용도로 사용된다고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌측 사이드바에 Explore에 직접 쿼리를 쳐서 확인도 가능 예를 들어 이런식으로 워드프레스 요청 수 확인 가능&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1827&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0KT6j/dJMcagYav1P/5JkymauXARg8oa6AvLOhy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0KT6j/dJMcagYav1P/5JkymauXARg8oa6AvLOhy1/img.png&quot; data-alt=&quot;간단한 promql 테스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0KT6j/dJMcagYav1P/5JkymauXARg8oa6AvLOhy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0KT6j%2FdJMcagYav1P%2F5JkymauXARg8oa6AvLOhy1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;308&quot; data-origin-width=&quot;1827&quot; data-origin-height=&quot;880&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;간단한 promql 테스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 생각하기에 PromQL은 자유분방?하여 매우 다양하게 조회가 가능해서 SQL처럼 어느정도의 문법을 외우기 쉽지 않은 듯&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 워드프레스 브라우저에 띄우고 새로고침 반복한 다음 파란색 리프레쉬 버튼을 누르니 저렇게 그래프에 반영된 게 보임&lt;/p&gt;</description>
      <category>리눅스/실습</category>
      <category>grafana</category>
      <category>nginx</category>
      <category>prometheus</category>
      <author>dbswjdahr</author>
      <guid isPermaLink="true">https://dbswjdahr.tistory.com/27</guid>
      <comments>https://dbswjdahr.tistory.com/27#entry27comment</comments>
      <pubDate>Fri, 14 Nov 2025 17:44:08 +0900</pubDate>
    </item>
    <item>
      <title>모니터링 서버 구축해보기-1</title>
      <link>https://dbswjdahr.tistory.com/26</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;웹서버의 트래픽을 보기 위해 PG 스택으로 모니터링 서버를 구축해보기로 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번에 https 적용까지 한 워드프레스 LEMP 서버가 대상으로 같은 가상머신 네트워크 상 1대에 모니터링 VM 구축이 목표&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dbswjdahr.tistory.com/19&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.11.08 - [리눅스/실습] - 웹서버에 TLS 적용하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1763098384333&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;웹서버에 TLS 적용하기&quot; data-og-description=&quot;워드프레스가 제대로 붙었으니 이제 http를 https로 만들어 볼 생각이다. 간단하게 테스트 환경에서 적용할 수 있는 openssl이랑 실제 인증서를 받아서 적용 가능한 let's encrypt가 있는데,let's encrypt를 &quot; data-og-host=&quot;dbswjdahr.tistory.com&quot; data-og-source-url=&quot;https://dbswjdahr.tistory.com/19&quot; data-og-url=&quot;https://dbswjdahr.tistory.com/19&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b0lAB1/hyZMuOtFkg/zYTTfNJKw9BAAuCkGD8oCK/img.png?width=800&amp;amp;height=526&amp;amp;face=0_0_800_526,https://scrap.kakaocdn.net/dn/tQ8rH/hyZNvmktS7/KYgk2W9ND1U4JNQuC32VxK/img.png?width=800&amp;amp;height=526&amp;amp;face=0_0_800_526,https://scrap.kakaocdn.net/dn/bpmDVW/hyZMEcw14X/OyNNAKRGWC6jzC1RA6obk1/img.png?width=1111&amp;amp;height=826&amp;amp;face=0_0_1111_826&quot;&gt;&lt;a href=&quot;https://dbswjdahr.tistory.com/19&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dbswjdahr.tistory.com/19&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b0lAB1/hyZMuOtFkg/zYTTfNJKw9BAAuCkGD8oCK/img.png?width=800&amp;amp;height=526&amp;amp;face=0_0_800_526,https://scrap.kakaocdn.net/dn/tQ8rH/hyZNvmktS7/KYgk2W9ND1U4JNQuC32VxK/img.png?width=800&amp;amp;height=526&amp;amp;face=0_0_800_526,https://scrap.kakaocdn.net/dn/bpmDVW/hyZMEcw14X/OyNNAKRGWC6jzC1RA6obk1/img.png?width=1111&amp;amp;height=826&amp;amp;face=0_0_1111_826');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;웹서버에 TLS 적용하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;워드프레스가 제대로 붙었으니 이제 http를 https로 만들어 볼 생각이다. 간단하게 테스트 환경에서 적용할 수 있는 openssl이랑 실제 인증서를 받아서 적용 가능한 let's encrypt가 있는데,let's encrypt를&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dbswjdahr.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;elk는 여기서 내 노트북이 감당 못하기 때문에 가벼운 prometheus랑 grafana로 깔기로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 &lt;a href=&quot;https://prometheus.io/download/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://prometheus.io/download/&lt;/a&gt; 여기에서 프로메테우스를 Alma에 다운받아야 하고,&lt;br /&gt;&lt;a href=&quot;https://grafana.com/grafana/download?pg=oss-graf&amp;amp;plcmt=hero-btn-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://grafana.com/grafana/download?pg=oss-graf&amp;amp;plcmt=hero-btn-1&lt;/a&gt; 여기에서 그라파나를 마찬가지로 받는다. OSS로&lt;/p&gt;
&lt;pre id=&quot;code_1763099687521&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# https://github.com/prometheus/prometheus/releases/download/v3.7.3/prometheus-3.7.3.linux-amd64.tar.gz
[root@monitoring ~]# install -y https://dl.grafana.com/grafana/release/12.2.1/grafana_12.2.1_18655849634_linux_amd64.rpm
[root@monitoring ~]# tar xvzf prometheus-3.7.3.linux-amd64.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그라파나는 grafana-server로 시스템 대몬이 추가되고 실행시키면 기본 포트가 3000이다. 방화벽을 뚫어줌&lt;/p&gt;
&lt;pre id=&quot;code_1763100378096&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# systemctl enable --now grafana-server
Created symlink '/etc/systemd/system/multi-user.target.wants/grafana-server.service' &amp;rarr; '/usr/lib/systemd/system/grafana-server.service'.
[root@monitoring ~]# ss -tlnp | grep grafana
LISTEN 0      4096               *:3000             *:*    users:((&quot;grafana&quot;,pid=29647,fd=15))
[root@monitoring ~]# firewall-cmd --add-port 3000/tcp --permanent
success
[root@monitoring ~]# firewall-cmd --reload
success&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 웹 브라우저에서 3000번으로 접근이 됨 기본 ID 비번은 admin/admin이고 이걸 치면 새 비번을 지정하라고 뜸&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로 만들어주고 대시보드로 들어가면 됨&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1580&quot; data-origin-height=&quot;888&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUMXlK/dJMb995Ohok/olqs86D57zGZK7piayRiwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUMXlK/dJMb995Ohok/olqs86D57zGZK7piayRiwK/img.png&quot; data-alt=&quot;그라파나 접속&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUMXlK/dJMb995Ohok/olqs86D57zGZK7piayRiwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUMXlK%2FdJMb995Ohok%2Folqs86D57zGZK7piayRiwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;360&quot; data-origin-width=&quot;1580&quot; data-origin-height=&quot;888&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그라파나 접속&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1829&quot; data-origin-height=&quot;868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6CHrL/dJMcahJxzf9/dnUcnyByazWaflSUxbD0Z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6CHrL/dJMcahJxzf9/dnUcnyByazWaflSUxbD0Z1/img.png&quot; data-alt=&quot;로그인하고 대시보드로 들어가기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6CHrL/dJMcahJxzf9/dnUcnyByazWaflSUxbD0Z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6CHrL%2FdJMcahJxzf9%2FdnUcnyByazWaflSUxbD0Z1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;304&quot; data-origin-width=&quot;1829&quot; data-origin-height=&quot;868&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;로그인하고 대시보드로 들어가기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 아직 프로메테우스랑 그라파나랑 연결을 안 해서 빈 깡통과 같은 상태다. 프로메테우스도 활성화하고 연결시켜줘야 함&lt;/p&gt;
&lt;pre id=&quot;code_1763100930305&quot; class=&quot;css&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;[root@monitoring ~]# ls
anaconda-ks.cfg
prometheus-3.7.3.linux-amd64
prometheus-3.7.3.linux-amd64.tar.gz
[root@monitoring ~]# cd prometheus-3.7.3.linux-amd64
[root@monitoring prometheus-3.7.3.linux-amd64]# ls
LICENSE  NOTICE  prometheus  prometheus.yml  promtool&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로메테우스도 다운받아 압축을 풀었는데 라이선스랑 노티스는 무시하고 3개의 파일이 있는 게 보인다 yml은 딱 봐도 설정파일이고 나머지 2개는 실행파일로 보인다. 이걸 각각 옮겨줘야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바이너리 실행 파일 2개는 인식할 수 있게 옮겨주고, 설정파일도 따로 디렉터리를 추가해서 둬준 다음 깔끔하게 남은 파일들 지&lt;/p&gt;
&lt;pre id=&quot;code_1763100925606&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring prometheus-3.7.3.linux-amd64]# mv prometheus promtool /usr/local/bin/
[root@monitoring prometheus-3.7.3.linux-amd64]# mkdir -p /etc/prometheus
[root@monitoring prometheus-3.7.3.linux-amd64]# mv prometheus.yml /etc/prometheus/
[root@monitoring prometheus-3.7.3.linux-amd64]# cd ..
[root@monitoring ~]# rm -rf prom*&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 프로메테우스 전용 사용자를 만들어 놓음&lt;/p&gt;
&lt;pre id=&quot;code_1763101122509&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# useradd -M -s /sbin/nologin prometheus
[root@monitoring ~]# chown -R prometheus:prometheus /etc/prometheus
[root@monitoring ~]# chown prometheus:prometheus /usr/local/bin/prometheus&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로메테우스가 수집하는 데이터가 있고 이게 저장되어야 하니 이 경로도 만들어줘야 함&lt;/p&gt;
&lt;pre id=&quot;code_1763101366246&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# mkdir -p /var/lib/prometheus
[root@monitoring ~]# chown -R prometheus:prometheus /var/l
ib/prometheus/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로메테우스는 그라파나처럼 시스템 대몬이 없으니 직접 만들어주면 됨&lt;/p&gt;
&lt;pre id=&quot;code_1763101436310&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target

[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus \
    --config.file /etc/prometheus/prometheus.yml \
    --storage.tsdb.path /var/lib/prometheus/ \
    --web.console.templates=/etc/prometheus/consoles \
    --web.console.libraries=/etc/prometheus/console_libraries

[Install]
WantedBy=multi-user.target&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러고 대몬을 재시작하고 활성화 시켜주면 된다. 기본적으로 SE리눅스가 막으니까 허용해줘야 함.&lt;br /&gt;프로메테우스는 9090포트를 쓴다. 마찬가지로 허용&lt;/p&gt;
&lt;pre id=&quot;code_1763101791955&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# chcon -t bin_t /usr/local/bin/prom*
[root@monitoring ~]# systemctl daemon-reload
[root@monitoring ~]# systemctl enable --now prometheus
[root@monitoring ~]# ss -tupln | grep prom
tcp   LISTEN 0      4096               *:9090             *:*    users:((&quot;prometheus&quot;,pid=38440,fd=6))
[root@monitoring ~]# firewall-cmd --add-port 9090/tcp --permanent
success
[root@monitoring ~]# firewall-cmd --reload
success&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 프로메테우스랑 그라파나가 활성화됐으니 둘이 연결하면 된다.&lt;br /&gt;대시보드에서 Connections 들어가 검색창에 프로메테우스 검색해주고 데이터 소스에서 찾아 클릭하면 됨&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;814&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ce3k9l/dJMcahpePjV/6awZM6EjlChMSlc5gFVvr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ce3k9l/dJMcahpePjV/6awZM6EjlChMSlc5gFVvr1/img.png&quot; data-alt=&quot;프로메테우스를 연결하기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ce3k9l/dJMcahpePjV/6awZM6EjlChMSlc5gFVvr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fce3k9l%2FdJMcahpePjV%2F6awZM6EjlChMSlc5gFVvr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;283&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;814&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;프로메테우스를 연결하기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;들어가면 우측 상단 파란 버튼으로 추가 버튼이 있는데 누르면 아래처럼 Settings가 나옴 여기 뭐가 많은데 일단 필요없고&lt;br /&gt;URL에 프로메테우스 주소를 입력해주면 된다. 그라파나 서버 기준으로 찾는 거라 로컬호스트:9090 하면 됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 그라파나랑 프로메테우스가 떨어져있다면 프로메테우스 IP:9090으로 하면 됨&lt;br /&gt;이후 맨 아래로 내려 Save &amp;amp; test 버튼 눌러서 초록색으로 API 질의 성공 표시 뜨면 끝&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1845&quot; data-origin-height=&quot;858&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0lvmM/dJMcahQi8dD/FsrIigQXkdEhhLdwu66UuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0lvmM/dJMcahQi8dD/FsrIigQXkdEhhLdwu66UuK/img.png&quot; data-alt=&quot;여기서 연결하기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0lvmM/dJMcahQi8dD/FsrIigQXkdEhhLdwu66UuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0lvmM%2FdJMcahQi8dD%2FFsrIigQXkdEhhLdwu66UuK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;298&quot; data-origin-width=&quot;1845&quot; data-origin-height=&quot;858&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;여기서 연결하기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 연결은 됐는데 프로메테우스가 어디서 데이터를 추출할지 안 정해져있으므로 아직도 깡통임 그래서 웹 연결해줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결하려면 프로메테우스 사이트에 있는 exporter가 필요한데 종류가 엄청 많다. 근데 여기선 node랑 mysqld exporter만 있으면 충분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;exporter는 말그대로 수출업자? 같은 거라 웹서버에 설치되면 여기서 수출해서 prometheus.yml보고 여기서 데이터를 받아옴&lt;/p&gt;
&lt;pre id=&quot;code_1763103091963&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@Alma ~]# wget https://github.com/prometheus/mysqld_exporter/releases/download/v0.18.0/mysqld_exporter-0.18.0.linux-amd64.tar.gz
[root@Alma ~]# wget https://github.com/prometheus/node_exporter/releases/download/v1.10.2/node_exporter-1.10.2.linux-amd64.tar.gz
[root@Alma ~]# ls -l
total 20832
-rw-------. 1 root root      839 Nov  1 21:17 anaconda-ks.cfg
-rw-r--r--. 1 root root  9634286 Sep 29 17:53 mysqld_exporter-0.18.0.linux-amd64.tar.gz
-rw-r--r--. 1 root root 11686705 Oct 26 05:10 node_exporter-1.10.2.linux-amd64.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 tar로 압축까지 풀어준다&lt;/p&gt;
&lt;pre id=&quot;code_1763103147519&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@Alma ~]# tar xzfv node_exporter-1.10.2.linux-amd64.tar.gz
node_exporter-1.10.2.linux-amd64/
node_exporter-1.10.2.linux-amd64/node_exporter
node_exporter-1.10.2.linux-amd64/LICENSE
node_exporter-1.10.2.linux-amd64/NOTICE
[root@Alma ~]# tar xzfv mysqld_exporter-0.18.0.linux-amd64.tar.gz
mysqld_exporter-0.18.0.linux-amd64/
mysqld_exporter-0.18.0.linux-amd64/LICENSE
mysqld_exporter-0.18.0.linux-amd64/mysqld_exporter
mysqld_exporter-0.18.0.linux-amd64/NOTICE&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 동일&lt;/p&gt;
&lt;pre id=&quot;code_1763103315027&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@Alma ~]# mv mysqld_exporter-0.18.0.linux-amd64/mysqld_exporter /usr/local/bin/
[root@Alma ~]# mv node_exporter-1.10.2.linux-amd64/node_exporter /usr/local/bin/
[root@Alma ~]# rm -rf node* mysql*
[root@Alma ~]# useradd -M -s /sbin/nologin node_exporter
[root@Alma ~]# useradd -M -s /sbin/nologin mysqld_exporter
[root@Alma ~]# vi /etc/systemd/system/node-exporter.service
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target

[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter

[Install]
WantedBy=multi-user.target&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mysqld 익스포터는 DB에 사용자를 만들어줘야 됨&lt;/p&gt;
&lt;pre id=&quot;code_1763103552907&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@Alma ~]# mariadb
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 13
Server version: 10.5.29-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]&amp;gt; CREATE USER 'mysqld_exporter'@'localhost' IDENTIFIED BY '1234';
Query OK, 0 rows affected (0.012 sec)

MariaDB [(none)]&amp;gt; GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'mysqld_exporter'@'localhost';
Query OK, 0 rows affected (0.006 sec)

MariaDB [(none)]&amp;gt; FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.001 sec)

MariaDB [(none)]&amp;gt; exit
Bye&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이거에 대한 설정 파일도 하나 만들어줘서 DB를 사용할 수 있게끔 해줌.&lt;br /&gt;보안을 위해 숨김 파일로 만들고 전용 사용자 말곤 못 쓰게 해줌&lt;/p&gt;
&lt;pre id=&quot;code_1763103612269&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@Alma ~]# vi /etc/.mysqld_exporter.cnf
[client]
user=mysqld_exporter
password=1234
[root@Alma ~]# chown mysqld_exporter:mysqld_exporter /etc/.mysqld_exporter.cnf
[root@Alma ~]# chmod 600 /etc/.mysqld_exporter.cnf&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1763103785254&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@Alma ~]# vi /etc/systemd/system/mysqld-exporter.service
[Unit]
Description=MySQLd Exporter
Wants=network-online.target
After=network-online.target

[Service]
User=mysqld_exporter
Group=mysqld_exporter
Type=simple
ExecStart=/usr/local/bin/mysqld_exporter \
  --config.my-cnf /etc/.mysqld_exporter.cnf \
  --collect.global_status \
  --collect.info_schema.innodb_metrics \
  --collect.global_variables \
  --collect.info_schema.processlist \
  --collect.info_schema.tables \
  --collect.info_schema.userstats

[Install]
WantedBy=multi-user.target&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것도 SE리눅스에 막히니까 보안 컨텍스트 바꿔 실행을 허용해주고 대몬 재시작 후 활성화&lt;/p&gt;
&lt;pre id=&quot;code_1763103859271&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@Alma ~]# chcon -t bin_t /usr/local/bin/node_exporter
[root@Alma ~]# chcon -t bin_t /usr/local/bin/mysqld_exporter
[root@Alma ~]# systemctl daemon-reload
[root@Alma ~]# systemctl enable --now node-exporter
Created symlink /etc/systemd/system/multi-user.target.wants/node-exporter.service &amp;rarr; /etc/systemd/system/node-exporter.service.
[root@Alma ~]# systemctl enable --now mysqld-exporter
Created symlink /etc/systemd/system/multi-user.target.wants/mysqld-exporter.service &amp;rarr; /etc/systemd/system/mysqld-exporter.service.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얘들은 포트가 9100 9104로 나옴 이것도 똑같이 허용&lt;/p&gt;
&lt;pre id=&quot;code_1763103934533&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@Alma ~]# ss -tunlp | grep exporter
tcp   LISTEN 0      4096               *:9104             *:*    users:((&quot;mysqld_exporter&quot;,pid=7320,fd=3))                                                                                                                          
tcp   LISTEN 0      4096               *:9100             *:*    users:((&quot;node_exporter&quot;,pid=7289,fd=3))
[root@Alma ~]# firewall-cmd --add-port 9100/tcp --permanent
success
[root@Alma ~]# firewall-cmd --add-port 9104/tcp --permanent
success
[root@Alma ~]# firewall-cmd --reload
success&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 드디어 하나만 남았다. 모니터링 VM에서 얘를 볼 수 있어야 하기에 아까 넣어둔 설정 파일을 맞춰주면 됨&lt;br /&gt;일단 /etc/hosts에 웹서버 도메인을 추가해줌&lt;/p&gt;
&lt;pre id=&quot;code_1763104320101&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# sed -i '$a\172.27.193.11 wordpress' /etc/hosts&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 여기에 설정하고, 프로메테우스 재시작해서 설정 읽게 하면 됨&lt;/p&gt;
&lt;pre id=&quot;code_1763104412678&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@monitoring ~]# vi /etc/prometheus/prometheus.yml
# my global config
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
    - static_configs:
        - targets:
          # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - &quot;first_rules.yml&quot;
  # - &quot;second_rules.yml&quot;

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=&amp;lt;job_name&amp;gt;` to any timeseries scraped from this config.
  - job_name: &quot;prometheus&quot;

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: [&quot;localhost:9090&quot;]

### ===== 여기 추가 ===== ###
  - job_name: &quot;wordpress-lemp&quot;
    static_configs:
      - targets: [&quot;wordpress:9100&quot;, &quot;wordpress:9104&quot;]
### ===== 여기 추가 ===== ###

       # The label name is added as a label `label_name=&amp;lt;label_value&amp;gt;` to any timeseries scraped from this config.
        labels:
          app: &quot;prometheus&quot;
[root@monitoring ~]# systemctl restart prometheus&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 그라파나 말고 프로메테우스 쪽에서 연결 상태를 직접 확인하게 :9090으로 들어가 상단 메뉴바에 status 눌러서 확인하면 됨&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;805&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvzOr6/dJMcagqksW8/mJJm1Zwlhp9dAQdHEK03hK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvzOr6/dJMcagqksW8/mJJm1Zwlhp9dAQdHEK03hK/img.png&quot; data-alt=&quot;프로메테우스 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvzOr6/dJMcagqksW8/mJJm1Zwlhp9dAQdHEK03hK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvzOr6%2FdJMcagqksW8%2FmJJm1Zwlhp9dAQdHEK03hK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;278&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;805&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;프로메테우스 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초록색으로 정상적으로 엔드포인트가 연동되었다고 확인되면 그라파나 대시보드에 이제 시각화 할 수 있게 됨&lt;br /&gt;Dashboards로 가 우측 상단 드랍다운에 import를 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1858&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOJ8t3/dJMcabvMUWz/Z8URDpMLLQTIqnQKfYRkf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOJ8t3/dJMcabvMUWz/Z8URDpMLLQTIqnQKfYRkf0/img.png&quot; data-alt=&quot;시각화를 위해 데이터를 가져오면 됨&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOJ8t3/dJMcabvMUWz/Z8URDpMLLQTIqnQKfYRkf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOJ8t3%2FdJMcabvMUWz%2FZ8URDpMLLQTIqnQKfYRkf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;251&quot; data-origin-width=&quot;1858&quot; data-origin-height=&quot;728&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;시각화를 위해 데이터를 가져오면 됨&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 많은 고수들이 만들어놓은 시각화 대시보드 템플릿들이 있어서 그거 가져다 썼다.&lt;br /&gt;자세한 내용은 공식 대시보드 페이지에 많이 있음&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;795&quot; data-origin-height=&quot;834&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VbB21/dJMcah3Ql7P/1z39YWip27vHs2uhkZbfkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VbB21/dJMcah3Ql7P/1z39YWip27vHs2uhkZbfkk/img.png&quot; data-alt=&quot;대시보드 가져오기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VbB21/dJMcah3Ql7P/1z39YWip27vHs2uhkZbfkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVbB21%2FdJMcah3Ql7P%2F1z39YWip27vHs2uhkZbfkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;504&quot; data-origin-width=&quot;795&quot; data-origin-height=&quot;834&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대시보드 가져오기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1437&quot; data-origin-height=&quot;872&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFHqRK/dJMb995OiVc/fmiK4otvSadZs79kuJ8Chk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFHqRK/dJMb995OiVc/fmiK4otvSadZs79kuJ8Chk/img.png&quot; data-alt=&quot;대시보드 구축까지 완료&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFHqRK/dJMb995OiVc/fmiK4otvSadZs79kuJ8Chk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFHqRK%2FdJMb995OiVc%2FfmiK4otvSadZs79kuJ8Chk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;388&quot; data-origin-width=&quot;1437&quot; data-origin-height=&quot;872&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대시보드 구축까지 완료&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 DB에 대한 정보를 시각화하여 볼 수 있다&lt;/p&gt;</description>
      <category>리눅스/실습</category>
      <category>grafana</category>
      <category>prometheus</category>
      <author>dbswjdahr</author>
      <guid isPermaLink="true">https://dbswjdahr.tistory.com/26</guid>
      <comments>https://dbswjdahr.tistory.com/26#entry26comment</comments>
      <pubDate>Fri, 14 Nov 2025 16:27:08 +0900</pubDate>
    </item>
    <item>
      <title>ansible로 쿠버네티스 클러스터 구성하기</title>
      <link>https://dbswjdahr.tistory.com/25</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Opentofu로 프로비저닝도 완료하고 형상 관리 내부 저장소 구축도 토푸와 앤서블로 했으니 쿠버네티스 클러스터 구성만 남았음&lt;br /&gt;다시 ansible 작업 폴더로 들어가서 CRI-O 런타임이랑 쿠버네티스 저장소를 추가하고 설치하는 yaml파일을 작성해줌&lt;br /&gt;쿠버네티스 클러스터가 작동하기 위해서는 br_netfilter 커널 모듈이 활성화되고 ip포워딩 커널 파라미터가 활성화되어야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;swap 영역도 없애고 쿠버네티스는 열어둬야 하는 각종 포트가 많아서 여기선 방화벽이랑 se리눅스를 편리하게 꺼두도록 함&lt;/p&gt;
&lt;pre id=&quot;code_1762788344523&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ansible]# vi k8s-install.yaml 
- name: Kubeadm, Kubelet, Kubectl 설치 및 설정
  hosts: k8s_cluster, haproxy
  become: yes
  vars:
    kubernetes_version: &quot;1.32&quot; 
    crio_version: &quot;1.32&quot;

  tasks:
    - name: SWAP 비활성화 및 영구 설정 
      ansible.builtin.shell: swapoff -a &amp;amp;&amp;amp; sed -i '/ swap / s/^/#/' /etc/fstab
      changed_when: true
      
    - name: sysctl을 통해 IP 포워딩 활성화 및 파일 생성
      ansible.builtin.copy:
        content: |
          net.ipv4.ip_forward=1
        dest: /etc/sysctl.d/01-ip_forward.conf
        mode: '0644'
        
    - name: br_netfilter 모듈 로드 설정
      ansible.builtin.copy:
        content: |
          br_netfilter
        dest: /etc/modules-load.d/01-br_netfilter.conf
        mode: '0644'

    - name: br_netfilter 모듈 로드 및 sysctl 적용
      ansible.builtin.command: &quot;{{ item }}&quot;
      loop:
        - modprobe br_netfilter
        - sysctl -w net.ipv4.ip_forward=1
      changed_when: true

    - name: SELinux 비활성화 
      ansible.posix.selinux:
        state: disabled
        
    - name: Firewalld 비활성화 및 중지
      ansible.builtin.service:
        name: firewalld
        state: stopped
        enabled: false
        
    - name: 쿠버 저장소 추가하기
      ansible.builtin.copy:
        content: |
          [kubernetes]
          name=Kubernetes
          baseurl=https://pkgs.k8s.io/core:/stable:/v{{ kubernetes_version }}/rpm/
          enabled=1
          gpgcheck=1
          gpgkey=https://pkgs.k8s.io/core:/stable:/v{{ kubernetes_version }}/rpm/repodata/repomd.xml.key
        dest: /etc/yum.repos.d/kubernetes.repo


    - name: Control Plane 및 Worker 노드에 Kubelet/Kubeadm 설치
      ansible.builtin.dnf:
        name:
          - kubelet
          - kubeadm
        state: present
        disable_excludes: kubernetes
      when: inventory_hostname in groups['control'] or inventory_hostname in groups['worker']

    - name: control 이랑 haproxy에 Kubectl 설치 (관리용)
      ansible.builtin.dnf:
        name:
          - kubectl
        state: present
        disable_excludes: kubernetes
      when: inventory_hostname in groups['control'] or inventory_hostname in groups['haproxy']

    - name: Kubelet 서비스 활성화 (Worker 랑 Control 노드만)
      ansible.builtin.service:
        name: kubelet
        state: started
        enabled: yes
      when: inventory_hostname in groups['control'] or inventory_hostname in groups['worker']

    - name: CRIO 저장소 추가
      ansible.builtin.copy:
        content: |
          [crio]
          name=CRI-O
          baseurl=https://pkgs.k8s.io/addons:/cri-o:/stable:/v{{ crio_version }}/rpm/
          enabled=1
          gpgcheck=1
          gpgkey=https://pkgs.k8s.io/addons:/cri-o:/stable:/v{{ crio_version }}/rpm/repodata/repomd.xml.key
        dest: /etc/yum.repos.d/crio.repo
      when: inventory_hostname in groups['control'] or inventory_hostname in groups['worker']

    - name: CRIO 설치
      ansible.builtin.dnf:
        name: cri-o
        state: present
      when: inventory_hostname in groups['control'] or inventory_hostname in groups['worker']
        
    - name: CRIO 실행 중인지 확인
      ansible.builtin.service:
        name: crio
        state: started
        enabled: yes
      when: inventory_hostname in groups['control'] or inventory_hostname in groups['worker']&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터를 구성하기 위해 임의로 컨트롤 플레인 3대 워커 5대로 HA 클러스터를 목표로 구성하도록 함&lt;br /&gt;컨트롤 플레인의 로드밸런싱을 위해서 앞 단에 haproxy를 사용하도록 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 전에 haproxy가 설치되면 /etc/haproxy/haproxy.cfg 이 파일을 보고 처리되니 jinja2 템플릿 파일을 미리 작성해줌&lt;br /&gt;진자 템플릿 형식이라 .j2로 저장해줌&lt;/p&gt;
&lt;pre id=&quot;code_1762838108033&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ansible]# vi haproxy.cfg.j2 
global
  log 127.0.0.1 local2
  chroot /var/lib/haproxy
  pidfile /var/run/haproxy.pid
  maxconn 4000
  user haproxy
  group haproxy
  daemon

defaults
  mode tcp
  log global
  timeout connect 5000
  timeout client 50000
  timeout server 50000

listen kube-apiserver
  bind {{ control_plane_ip }}:6443
  mode tcp
  option tcplog
  balance roundrobin

  {% for ip in control_node_ips %}
  server control{{ loop.index }} {{ ip }}:6443 check
  {% endfor %}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 실제 클러스터 구성을 자동화 해주는 최종 yaml파일을 작성하고 적용해주면 된다.&lt;br /&gt;먼저 hostname을 보는데, 이게 맞지 않으면 경고 문구를 띄우기 때문에 IaC 노드에 정의된 호스트네임으로 각각 맞춰준다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 haproxy 노드를 빼서 따로 설치와 .j2 템플릿에 맞춰 컨트롤 플레인 노드들을 설정 파일에 추가하고 재실행(활성화 시켜놓음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 쓰일 변수로 flannel CNI의 기본 CIDR와 로드밸런서으 6443번을 지정해놓고 시작&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;컨트롤 플레인 중 하나인 1번에서 초기화를 진행시키고 컨트롤과 워커 노드들을 컨트롤 1번에서 생성한 토큰과 인증서를 기반으로 붙여 클러스터 구성을 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 haproxy 쪽에서 kubectl로 클러스터 관리를 할 수 있게 con1 -&amp;gt; haproxy로 admin.conf를 복사해서 넘겨주도록 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨트롤 노드에서 초기화를 진행할 때 엔드포인트를 HAproxy쪽으로 지정해서 외부에서 트래픽이 들어오면 이쪽으로 감&lt;br /&gt;HAproxy는 6443번으로 들어오면 컨트롤 3대 중 하나로 보내게 되어 로드밸런싱이 되게 됨&lt;br /&gt;또, 클러스터 내 pod 네트워크를 지정해주는 게 있는데 CNI라고 정해줘야 서로 통신이 돼서 이걸 지정해준 게 Flannel 네트워크다.&lt;/p&gt;
&lt;pre id=&quot;code_1762837467183&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ansible]# vi k8s-clustering.yaml 
- name: 클러스터 노드 호스트 이름 설정
  hosts: all
  become: yes
  tasks:
    - name: 호스트 이름 변경
      ansible.builtin.hostname:
        name: &quot;{{ inventory_hostname }}&quot;

- name: HAProxy 설정 및 k8s 클러스터 초기화 준비
  hosts: haproxy
  become: yes
  vars:
    control_plane_ip: &quot;{{ hostvars[inventory_hostname]['ansible_host'] }}&quot;
    control_node_ips: &quot;{{ groups['control'] | map('extract', hostvars, 'ansible_host') | list }}&quot;

  tasks:
    - name: HAProxy 설치
      ansible.builtin.dnf:
        name: haproxy
        state: present

    - name: HAProxy 설정 파일 (haproxy.cfg) 생성
      ansible.builtin.template:
        src: haproxy.cfg.j2
        dest: /etc/haproxy/haproxy.cfg
      notify:
        - Restart haproxy service

    - name: HAProxy 서비스 시작 및 활성화
      ansible.builtin.service:
        name: haproxy
        state: started
        enabled: yes

  handlers:
    - name: Restart haproxy service
      ansible.builtin.service:
        name: haproxy
        state: restarted


- name: 컨트롤 플레인 초기화 및 조인
  hosts: control
  become: yes
  vars:
    load_balancer_dns: &quot;{{ hostvars['proxy']['ansible_host'] }}:6443&quot;
    pod_cidr: &quot;10.244.0.0/16&quot;


  tasks:
    - name: 클러스터 초기화 (control1)
      ansible.builtin.shell: |
        kubeadm init \
          --control-plane-endpoint &quot;{{ load_balancer_dns }}&quot; \
          --upload-certs \
          --pod-network-cidr &quot;{{ pod_cidr }}&quot; \
          --cri-socket unix:///var/run/crio/crio.sock \
      register: kubeadm_init_result
      when: inventory_hostname == 'control1'

    - name: Worker Join Command 추출 및 변수 설정
      ansible.builtin.shell: |
        kubeadm token create --print-join-command 
      register: worker_join_cmd_raw
      when: inventory_hostname == 'control1'

    - name: Worker Join Command 변수 설정
      ansible.builtin.set_fact:
        join_command_worker: &quot;{{ worker_join_cmd_raw.stdout | replace('\n', '') }}&quot;
      when: inventory_hostname == 'control1'

    - name: Control Plane 인증서 키 추출 (Control Plane Joine Command 재구성용)
      ansible.builtin.shell: |
        kubeadm init phase upload-certs --upload-certs | tail -n 1
      register: cert_key_raw
      when: inventory_hostname == 'control1'

    - name: Control Plane Join Command 변수 설정
      ansible.builtin.set_fact:
        join_command_cp: &quot;{{ hostvars['control1']['join_command_worker'] | trim }} --control-plane --certificate-key {{ cert_key_raw.stdout | trim }} --ignore-preflight-errors=FileAvailable--etc-kubernetes-kubelet.conf,Port-10250&quot;
      when: inventory_hostname == 'control1'

    - name: 나머지 Control Plane 노드 조인 (control2, control3)
      ansible.builtin.shell: &quot;{{ hostvars['control1']['join_command_cp'] }} --cri-socket unix:///var/run/crio/crio.sock&quot;
      when: 
        - inventory_hostname != 'control1'
        - hostvars['control1']['join_command_cp'] is defined
        - hostvars['control1']['join_command_cp'] | length &amp;gt; 0

    - name: admin.conf 파일을 HAProxy 노드로 복사
      ansible.builtin.fetch:
        src: /etc/kubernetes/admin.conf
        dest: &quot;{{ inventory_dir }}/fetched_config/{{ inventory_hostname }}/admin.conf&quot;
        flat: yes
      when: inventory_hostname == &quot;control1&quot;

    - name: 복사된 admin.conf를 HAProxy 노드의 /root/.kube/config로 이동
      ansible.builtin.copy:
        src: &quot;{{ inventory_dir }}/fetched_config/control1/admin.conf&quot;
        dest: /root/.kube/config
        remote_src: no
        owner: root
        group: root
        mode: '0600'
      run_once: true
      delegate_to: haproxy


- name: 워커 노드 조인
  hosts: worker
  become: yes
  tasks:
    - name: 워커 노드 조인 실행
      ansible.builtin.shell: &quot;{{ hostvars['control1']['join_command_worker'] }} --cri-socket unix:///var/run/crio/crio.sock --ignore-preflight-errors=FileAvailable--etc-kubernetes-kubelet.conf,Port-10250,FileAvailable--etc-kubernetes-pki-ca.crt&quot;


- name: Flannel CNI 설치
  hosts: control1
  become: yes
  tasks:
    - name: Flannel CNI 설치 전 대기 (Control Plane 안정화)
      ansible.builtin.pause:
        seconds: 15
        prompt: &quot;Waiting for Control Plane to be fully ready before installing CNI...&quot;
    
    - name: Flannel CNI 적용
      ansible.builtin.command: kubectl apply --kubeconfig /etc/kubernetes/admin.conf -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
      delegate_to: control1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이렇게 2개 파일로 나눠 작성됐는데 실행은 간단하게 그냥 하면 됨&lt;br /&gt;자동화 코드를 작성하는 게 좀 복잡해서 그렇지 다 맞게 되면 실행 자체는 매우 간단&lt;/p&gt;
&lt;pre id=&quot;code_1762839501409&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ansible]# ansible-playbook -i hosts k8s-install.yaml 
[root@IaC ansible]# ansible-playbook -i hosts k8s-clustering.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1235&quot; data-origin-height=&quot;715&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clMtCx/dJMcabvLC3f/doLZiLvNfZcvGlynX2oncK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clMtCx/dJMcabvLC3f/doLZiLvNfZcvGlynX2oncK/img.png&quot; data-alt=&quot;성공하면 이런 식으로 뜸&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clMtCx/dJMcabvLC3f/doLZiLvNfZcvGlynX2oncK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclMtCx%2FdJMcabvLC3f%2FdoLZiLvNfZcvGlynX2oncK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;371&quot; data-origin-width=&quot;1235&quot; data-origin-height=&quot;715&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;성공하면 이런 식으로 뜸&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CNI까지 잘 붙었나 확인하기 위해 테스트 웹서버 1개를 배포해서 외부에서 웹콘솔로 확인해보면 됨.&lt;br /&gt;실행된 pod의 IP가 아까 설정한 Flannel의 디폴트 네트워크에 잘 안착한 게 확인이 됨 상태도 문제없이 Running&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1282&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4ib74/dJMcaeeXq0g/iOzWoWdyWC3sVWHDEvaqa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4ib74/dJMcaeeXq0g/iOzWoWdyWC3sVWHDEvaqa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4ib74/dJMcaeeXq0g/iOzWoWdyWC3sVWHDEvaqa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4ib74%2FdJMcaeeXq0g%2FiOzWoWdyWC3sVWHDEvaqa0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;248&quot; data-origin-width=&quot;1282&quot; data-origin-height=&quot;496&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 자세한 정보는 이런 식으로 확인이 가능&lt;/p&gt;
&lt;pre id=&quot;code_1762840115054&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@proxy ~]# kubectl get nodes
NAME       STATUS   ROLES           AGE   VERSION
control1   Ready    control-plane   42m   v1.32.9
control2   Ready    control-plane   42m   v1.32.9
control3   Ready    control-plane   42m   v1.32.9
worker1    Ready    &amp;lt;none&amp;gt;          42m   v1.32.9
worker2    Ready    &amp;lt;none&amp;gt;          42m   v1.32.9
worker3    Ready    &amp;lt;none&amp;gt;          42m   v1.32.9
worker4    Ready    &amp;lt;none&amp;gt;          42m   v1.32.9
worker5    Ready    &amp;lt;none&amp;gt;          42m   v1.32.9
[root@proxy ~]# kubectl create deployment nginx-test --image nginx:latest
deployment.apps/nginx-test created
[root@proxy ~]# kubectl expose deployment nginx-test --type NodePort --port 80
service/nginx-test exposed
[root@proxy ~]# kubectl get service
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1       &amp;lt;none&amp;gt;        443/TCP        44m
nginx-test   NodePort    10.106.135.99   &amp;lt;none&amp;gt;        80:31270/TCP   8s
[root@proxy ~]# kubectl get pods -o wide
NAME                          READY   STATUS    RESTARTS   AGE    IP           NODE      NOMINATED NODE   READINESS GATES
nginx-test-6bff9d5d95-d8lqb   1/1     Running   0          4m8s   10.244.5.2   worker1   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
[root@proxy ~]# kubectl get nodes -o wide
NAME       STATUS   ROLES           AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                      KERNEL-VERSION                 CONTAINER-RUNTIME
control1   Ready    control-plane   50m   v1.32.9   10.0.4.241    &amp;lt;none&amp;gt;        Rocky Linux 9.6 (Blue Onyx)   5.14.0-570.18.1.el9_6.x86_64   cri-o://1.32.1
control2   Ready    control-plane   50m   v1.32.9   10.0.5.22     &amp;lt;none&amp;gt;        Rocky Linux 9.6 (Blue Onyx)   5.14.0-570.18.1.el9_6.x86_64   cri-o://1.32.1
control3   Ready    control-plane   50m   v1.32.9   10.0.2.133    &amp;lt;none&amp;gt;        Rocky Linux 9.6 (Blue Onyx)   5.14.0-570.18.1.el9_6.x86_64   cri-o://1.32.1
worker1    Ready    &amp;lt;none&amp;gt;          50m   v1.32.9   10.0.3.249    &amp;lt;none&amp;gt;        Rocky Linux 9.6 (Blue Onyx)   5.14.0-570.18.1.el9_6.x86_64   cri-o://1.32.1
worker2    Ready    &amp;lt;none&amp;gt;          50m   v1.32.9   10.0.5.69     &amp;lt;none&amp;gt;        Rocky Linux 9.6 (Blue Onyx)   5.14.0-570.18.1.el9_6.x86_64   cri-o://1.32.1
worker3    Ready    &amp;lt;none&amp;gt;          50m   v1.32.9   10.0.3.165    &amp;lt;none&amp;gt;        Rocky Linux 9.6 (Blue Onyx)   5.14.0-570.18.1.el9_6.x86_64   cri-o://1.32.1
worker4    Ready    &amp;lt;none&amp;gt;          50m   v1.32.9   10.0.3.6      &amp;lt;none&amp;gt;        Rocky Linux 9.6 (Blue Onyx)   5.14.0-570.18.1.el9_6.x86_64   cri-o://1.32.1
worker5    Ready    &amp;lt;none&amp;gt;          50m   v1.32.9   10.0.5.126    &amp;lt;none&amp;gt;        Rocky Linux 9.6 (Blue Onyx)   5.14.0-570.18.1.el9_6.x86_64   cri-o://1.32.1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터널 IP는 오픈스택의 내부망 네트워크고 서비스의 클러스터 IP는 가상 IP로 pod로 접근하기 위한 중간 지점, pod의 IP는 pod 간 통신을 위한 네트워크로 CNI를 통해 구성된 네트워크다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 pod가 worker1 노드에서 실행된 것으로 보이지만 오픈스택 내 네트워크에서는 k8s 클러스터 8개 중 아무 노드에 접근해도 접근이 가능&lt;br /&gt;그렇지만 그냥은 아니고 노드포트로 서비스를 뚫어놔서 여기선 31270쪽으로 접근해야 확인이 가능 &lt;br /&gt;kube-proxy라는 쿠버네티스 시스템에서 알아서 감지하고 실제 pod가 실행되는 쪽으로 보내서 처리하기 때문&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xO0U0/dJMcafStirw/EYAXKZicoyuUAJOIPwIYy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xO0U0/dJMcafStirw/EYAXKZicoyuUAJOIPwIYy0/img.png&quot; data-alt=&quot;성공적인 클러스터 구축 완료&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xO0U0/dJMcafStirw/EYAXKZicoyuUAJOIPwIYy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxO0U0%2FdJMcafStirw%2FEYAXKZicoyuUAJOIPwIYy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;274&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;성공적인 클러스터 구축 완료&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 중인 워커1이 아닌 워커3으로 접근을 했지만 클러스터 자체에서 31270으로 뚫어 놨으니 접근이 가능하다. &lt;br /&gt;컨트롤 플레인으로도 접근이 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로써 Opentofu와 Ansible을 이용해 vm 생성부터 클러스터 구축까지 완료했다!&lt;/p&gt;</description>
      <category>리눅스/실습</category>
      <category>ansible</category>
      <category>crio</category>
      <category>HAProxy</category>
      <category>Kubernetes</category>
      <author>dbswjdahr</author>
      <guid isPermaLink="true">https://dbswjdahr.tistory.com/25</guid>
      <comments>https://dbswjdahr.tistory.com/25#entry25comment</comments>
      <pubDate>Tue, 11 Nov 2025 15:17:25 +0900</pubDate>
    </item>
    <item>
      <title>내부 저장소 구축과 연동 - 2</title>
      <link>https://dbswjdahr.tistory.com/24</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이전 minIO로 오픈토푸 백엔드 설정하고 상태를 버전으로 관리할 수 있게 해놨으니 이번엔 Gitea로 전체 IaC 코드 관리를 함&lt;br /&gt;Gitea는 포트가 3000으로 웹콘솔에 들어가면 초기 구성이 보임 &lt;br /&gt;SQLite로 하면 바로 가능하지만 너무 간단하니 Postgresql로 붙여보려고 함&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-10 160346.png&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;751&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMy4Kf/dJMcaezfRAY/KnqMLpixuD4pwUt7HWnPgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMy4Kf/dJMcaezfRAY/KnqMLpixuD4pwUt7HWnPgK/img.png&quot; data-alt=&quot;gitea 초기 구성 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMy4Kf/dJMcaezfRAY/KnqMLpixuD4pwUt7HWnPgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMy4Kf%2FdJMcaezfRAY%2FKnqMLpixuD4pwUt7HWnPgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;387&quot; data-filename=&quot;스크린샷 2025-11-10 160346.png&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;751&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;gitea 초기 구성 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 저장소 노드에서 podman으로 gitea 컨테이너가 하나 띄워져있는 상태, sqlite는 걍 하면 되는데 db는 따로 DB용 노드 추가해서 서버 띄우든 로컬에서 db 띄워서 연결하든 컨테이너 띄워서 연결하든 동작하는데 상관은 없다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만 podman을 사용 중이니까 gitea 컨테이너, db컨테이너 하나씩 묶어서 pod로 관리하게 했음&lt;br /&gt;일단 다시 pod를 만들고 2개 컨테이너를 묶기 위해 지금 실행중인 gitea 컨테이너 지우고 다시 함&lt;/p&gt;
&lt;pre id=&quot;code_1762758640731&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC tofu-backend]# ssh repository
root@repository's password: 
Last login: Mon Nov 10 01:26:43 2025 from 10.0.5.105
[root@repository ~]# podman ps
CONTAINER ID  IMAGE                              COMMAND               CREATED       STATUS       PORTS                                         NAMES
5da5bb73cae8  quay.io/minio/minio:latest         server /data --ad...  15 hours ago  Up 15 hours  0.0.0.0:9000-9001-&amp;gt;9000-9001/tcp              minio
9d88017f85a3  docker.io/library/registry:latest  /etc/distribution...  15 hours ago  Up 15 hours  0.0.0.0:5000-&amp;gt;5000/tcp                        registry
6c60c79eb1a9  docker.io/gitea/gitea:latest       /usr/bin/s6-svsca...  15 hours ago  Up 15 hours  0.0.0.0:2222-&amp;gt;22/tcp, 0.0.0.0:3000-&amp;gt;3000/tcp  gitea
[root@repository ~]# podman stop gitea
gitea
[root@repository ~]# podman rm gitea
gitea&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 pod를 만들어야 하는데, podman의 기본 인프라 컨테이너가 k8s 표준을 따르지 않기 때문에 나중을 위해 k8s에 호환되게 맞춰줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에는 k8s.gcr.io를 썼는데 어떠한 이유로 registry,k8s.io으로 이미지가 권고되므로 이걸 사용 &lt;br /&gt;태그 확인 후 설정 파일에 인프라 이미지를 최신 버전으로 명시해줌&lt;/p&gt;
&lt;pre id=&quot;code_1762760010039&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@repository ~]# podman search registry.k8s.io/pause --list-tags
NAME                   TAG
registry.k8s.io/pause  0.8.0
registry.k8s.io/pause  1.0
registry.k8s.io/pause  2.0
registry.k8s.io/pause  3.0
registry.k8s.io/pause  3.1
registry.k8s.io/pause  3.10
registry.k8s.io/pause  3.10.1
registry.k8s.io/pause  3.2
registry.k8s.io/pause  3.3
registry.k8s.io/pause  3.4.1
registry.k8s.io/pause  3.5
registry.k8s.io/pause  3.6
registry.k8s.io/pause  3.7
registry.k8s.io/pause  3.8
registry.k8s.io/pause  3.9
registry.k8s.io/pause  go
registry.k8s.io/pause  latest
registry.k8s.io/pause  sha256-278fb9dbcca9518083ad1e11276933a2e96f23de604a3a08cc3c80002767d24c.sig
registry.k8s.io/pause  sha256-3d33315f585d65b89f70cba238c3e4f66b96d576b3f40af801ceb1b3c7bfb5b9.sig
registry.k8s.io/pause  sha256-7031c1b283388d2c2e09b57badb803c05ebed362dc88d84b480cc47f72a21097.sig
registry.k8s.io/pause  sha256-81cdb107cabe9d8a8f69ee82ff0f1293ad85e62735937cf25eb14a229bb3ef7b.sig
registry.k8s.io/pause  sha256-8c2f62341a79ce86b566dfb474c87aaf05b916b82a5be44c3a269992a4a31c42.sig
registry.k8s.io/pause  sha256-9001185023633d17a2f98ff69b6ff2615b8ea02a825adffa40422f51dfdcde9d.sig
registry.k8s.io/pause  sha256-9c58577f23aaccd9593f2e47ce2096afbd7781984bd83c496b1a1e7e5276b1bc.sig
registry.k8s.io/pause  sha256-abce690161824d5950c0064ed836f397c6316a833d1abca92b79017d19949482.sig

[root@repository ~]# vi /usr/share/containers/containers.conf
infra_image = &quot;registry.k8s.io/pause:3.10&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 pod를 생성하면 자동으로 인프라 컨테이너 이미지가 땡겨옴&lt;/p&gt;
&lt;pre id=&quot;code_1762760312764&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@repository ~]# podman pod create --name gitea-postgresql -p 3000:3000 -p 5432:5432
2af7c38b51371673743a82623b9bd6867e1d2d9e6f109f96de3769cf189666db
[root@repository ~]# podman images
REPOSITORY                  TAG         IMAGE ID      CREATED        SIZE
docker.io/gitea/gitea       latest      dbb4b148024b  5 days ago     182 MB
quay.io/minio/minio         latest      69b2ec208575  2 months ago   176 MB
docker.io/library/registry  latest      e4e570676819  7 months ago   58.3 MB
registry.k8s.io/pause       3.10        873ed7510279  17 months ago  742 kB
[root@repository ~]# podman pod ps
POD ID        NAME              STATUS      CREATED         INFRA ID      # OF CONTAINERS
2af7c38b5137  gitea-postgresql  Created     24 seconds ago  19af3d3e0f16  1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 각각 Gitea랑 Postgresql DB 컨테이너를 pod에 붙여 실행시킴&lt;/p&gt;
&lt;pre id=&quot;code_1762760596721&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@repository ~]# podman run -d --pod gitea-postgresql --name postgresql -e POSTGRES_USER=gitea -e POSTGRES_PASSWORD=1234 -e POSTGRES_DB=gitea postgres:latest
679ac18291c561142960287c24873ee7076ea3d9afd58e41d198a67481956c6a

[root@repository ~]# podman run -d --pod gitea-postgresql --name gitea -v /data/gitea/:/data:Z gitea/gitea:latest
87baa7da2f82290b72fc2fdfda880b19d05174749e321f0504a74193831e2a60&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러고 다시 웹 콘솔로 접근한다. 아까랑 보이는 차이는 없지만 내부적으로 postgresql DB가 연결을 기다리고? 있음&lt;br /&gt;호스트 주소는 저장소로 해주고 컨테이너 실행 시 설정한 변수로 로그인을 하면 됨. 워드프레스 할 때랑 거의 비슷 &lt;br /&gt;DB 연결 후에 ID와 비번 등록도 이와 동일&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1138&quot; data-origin-height=&quot;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/peFNX/dJMcadNSIB9/Owki6v10fvnV0KyqeQtLm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/peFNX/dJMcadNSIB9/Owki6v10fvnV0KyqeQtLm1/img.png&quot; data-alt=&quot;DB컨테이너랑 Gitea컨테이너랑 연결&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/peFNX/dJMcadNSIB9/Owki6v10fvnV0KyqeQtLm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpeFNX%2FdJMcadNSIB9%2FOwki6v10fvnV0KyqeQtLm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;394&quot; data-origin-width=&quot;1138&quot; data-origin-height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DB컨테이너랑 Gitea컨테이너랑 연결&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1249&quot; data-origin-height=&quot;761&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EzsVi/dJMcadAlyUK/H5oAsKWUhtyzkoCUQSAPYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EzsVi/dJMcadAlyUK/H5oAsKWUhtyzkoCUQSAPYK/img.png&quot; data-alt=&quot;DB가 붙으면 여기로 넘어옴 (repo 거부돼서 giteauser로 함)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EzsVi/dJMcadAlyUK/H5oAsKWUhtyzkoCUQSAPYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEzsVi%2FdJMcadAlyUK%2FH5oAsKWUhtyzkoCUQSAPYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;560&quot; height=&quot;341&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1249&quot; data-origin-height=&quot;761&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DB가 붙으면 여기로 넘어옴 (repo 거부돼서 giteauser로 함)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용법은 github와 비슷하므로 git으로 커밋하기 전에 저장소부터 하나 만듦&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;748&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bW9uYp/dJMcag4UqE5/LhgFU5r1XJzaGwsKIZTvQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bW9uYp/dJMcag4UqE5/LhgFU5r1XJzaGwsKIZTvQ1/img.png&quot; data-alt=&quot;저장소는 깃헙에서 만들 때랑 거의 똑같&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bW9uYp/dJMcag4UqE5/LhgFU5r1XJzaGwsKIZTvQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbW9uYp%2FdJMcag4UqE5%2FLhgFU5r1XJzaGwsKIZTvQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;380&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;저장소는 깃헙에서 만들 때랑 거의 똑같&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 깃 초기화 작업 디렉터리 안 파일 확인하고 쓸데 없는 파일 안 들어가게 .gitignore 만들어줌&lt;/p&gt;
&lt;pre id=&quot;code_1762762585352&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ~]# ls
ansible opentofu  tofu-backend
[root@IaC ~]# vi .gitignore
.*&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 초기화하고 푸시하면 끝&lt;/p&gt;
&lt;pre id=&quot;code_1762764392561&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ~]# git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint:   git config --global init.defaultBranch &amp;lt;name&amp;gt;
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint:   git branch -m &amp;lt;name&amp;gt;
Initialized empty Git repository in /root/.git/
[root@IaC ~]# git add .
[root@IaC ~]# git commit -m &quot;깃티&quot;
[master (root-commit) ecc55e0] 깃티
 Committer: root &amp;lt;root@IaC.lab.io&amp;gt;
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly. Run the
following command and follow the instructions in your editor to edit
your configuration file:

    git config --global --edit

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

 24 files changed, 536 insertions(+)
 create mode 100644 ansible/deploy-cons.yaml
 create mode 100644 ansible/disk-setup.yaml
 create mode 100755 ansible/hosts
 create mode 100644 opentofu/hosts.tf
 create mode 100644 opentofu/instances.tf
 create mode 100644 opentofu/inventory.tf
 create mode 100644 opentofu/inventory.tpl
 create mode 100644 opentofu/keypair.tf
 create mode 100644 opentofu/network.tf
 create mode 100644 opentofu/opentofu.tfstate.backup
 create mode 100644 opentofu/output.tf
 create mode 100644 opentofu/provider.tf
 create mode 100644 opentofu/segroup.tf
 create mode 100644 opentofu/terraform.tfstate
 create mode 100644 opentofu/terraform.tfstate.backup
 create mode 100644 opentofu/tfplan-251109221916
 create mode 100644 opentofu/tfplan-251109221916.json
 create mode 100644 opentofu/variables.tf
 create mode 100644 tofu-backend/inventory.tf
 create mode 100644 tofu-backend/output.tf
 create mode 100644 tofu-backend/provider.tf
 create mode 100644 tofu-backend/repo-instance.tf
 create mode 100644 tofu-backend/terraform.tfstate
 create mode 100644 tofu-backend/terraform.tfstate.backup
[root@IaC ~]# git remote add origin http://repository:3000/gituser/IaC-lab.git
[root@IaC ~]# git branch -M main
[root@IaC ~]# git push -u origin main
Username for 'http://repository:3000': gituser
Password for 'http://gituser@repository:3000': 
Enumerating objects: 28, done.
Counting objects: 100% (28/28), done.
Delta compression using up to 8 threads
Compressing objects: 100% (27/27), done.
Writing objects: 100% (28/28), 22.70 KiB | 1.13 MiB/s, done.
Total 28 (delta 4), reused 0 (delta 0), pack-reused 0 (from 0)
remote: . Processing 1 references
remote: Processed 1 references in total
To http://repository:3000/gituser/IaC-lab.git
 * [new branch]      main -&amp;gt; main
branch 'main' set up to track 'origin/main'.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;658&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TE51J/dJMcahJv0ud/ikUURXtTOMHbzVSGXReYsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TE51J/dJMcahJv0ud/ikUURXtTOMHbzVSGXReYsK/img.png&quot; data-alt=&quot;깃티에 코드 등록 완료&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TE51J/dJMcahJv0ud/ikUURXtTOMHbzVSGXReYsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTE51J%2FdJMcahJv0ud%2FikUURXtTOMHbzVSGXReYsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;340&quot; data-origin-width=&quot;1238&quot; data-origin-height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;깃티에 코드 등록 완료&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 minIO랑 Gitea로 버전 관리 파이프라인 구축도 완료했다!&lt;/p&gt;</description>
      <category>리눅스/실습</category>
      <category>gitea</category>
      <category>podman</category>
      <author>dbswjdahr</author>
      <guid isPermaLink="true">https://dbswjdahr.tistory.com/24</guid>
      <comments>https://dbswjdahr.tistory.com/24#entry24comment</comments>
      <pubDate>Mon, 10 Nov 2025 17:49:29 +0900</pubDate>
    </item>
    <item>
      <title>내부 저장소 구축과 연동 - 1</title>
      <link>https://dbswjdahr.tistory.com/23</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이제 3개의 디스크 파티션에 각각 컨테이너 데이터가 저장될 디렉터리를 마운트하고 열어줬으니 이걸 이용해서 형상 관리를 진행할 수 있게 됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;minIO는 토푸의 상태 관리, Gitea는 전체 작업 디렉터리를 기록하기 위함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 minIO와 통신하기 위해 IaC에서 민아이오 클라이언트를 다운받음 - &lt;a href=&quot;https://github.com/minio/mc&quot;&gt;https://github.com/minio/mc&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1762754997623&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - minio/mc: Unix like utilities for object store&quot; data-og-description=&quot;Unix like utilities for object store. Contribute to minio/mc development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/minio/mc&quot; data-og-url=&quot;https://github.com/minio/mc&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cy5KHk/hyZMGOBfs2/FksbwxTsHQILefqnGczONk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/f4zOt/hyZMvfeehx/jyZXyjgK4YEDRmgHO0WBJk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/minio/mc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/minio/mc&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cy5KHk/hyZMGOBfs2/FksbwxTsHQILefqnGczONk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/f4zOt/hyZMvfeehx/jyZXyjgK4YEDRmgHO0WBJk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - minio/mc: Unix like utilities for object store&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Unix like utilities for object store. Contribute to minio/mc development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 dnf 기본 패키지 저장소엔 없지만 오픈소스라 가져와서 사용 가능. 빌드된 실행파일이라 /usr/local/bin에 실행 권한 붙여서 옮김&lt;/p&gt;
&lt;pre id=&quot;code_1762754967166&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ~]# wget https://dl.min.io/client/mc/release/linux-amd64/mc
[root@IaC ~]# chmod +x mc
[root@IaC ~]# mv mc /usr/local/bin/
[root@IaC ~]# mc --help
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── (q)uit/esc
NAME:                                                                                                                                                                               
  mc - MinIO Client for object storage and filesystems.                                                                                                                             
                                                                                                                                                                                    
USAGE:                                                                                                                                                                              
  mc [FLAGS] COMMAND [COMMAND FLAGS | -h] [ARGUMENTS...]                                                                                                                            
                                                                                                                                                                                    
COMMANDS:                                                                                                                                                                           
  alias      manage server credentials in configuration file                                                                                                                        
  admin      manage MinIO servers                             
  ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앤서블로 구성한 minIO 컨테이너에 인증해서 API를 연동부터 함&lt;/p&gt;
&lt;pre id=&quot;code_1762755373870&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ~]# mc alias set repo http://repository:9000 minioadmin minioadminpass
Added `repo` successfully.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 연결한 저장소에 백엔드로 쓰일 버킷을 생성해준다. 생성해주고 등록된 저장소를 보면 빈 버킷이 생김&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1255&quot; data-origin-height=&quot;777&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XNrbs/dJMcacIcTbQ/jJklNM3V1UXgvkqklnvZhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XNrbs/dJMcacIcTbQ/jJklNM3V1UXgvkqklnvZhK/img.png&quot; data-alt=&quot;mc로 원격 버킷 생성 성공함&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XNrbs/dJMcacIcTbQ/jJklNM3V1UXgvkqklnvZhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXNrbs%2FdJMcacIcTbQ%2FjJklNM3V1UXgvkqklnvZhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;396&quot; data-origin-width=&quot;1255&quot; data-origin-height=&quot;777&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;mc로 원격 버킷 생성 성공함&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1762755762521&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ~]# mc mb repo/tofu-state
Bucket created successfully `repo/tofu-state`.
[root@IaC ~]# mc ls repo
[2025-11-10 15:19:09 KST]     0B tofu-backend/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백엔드 지정할 디렉터리로 가서 프로바이더 부분에 백엔드를 추가해줌&lt;/p&gt;
&lt;pre id=&quot;code_1762755943354&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ~]# cd tofu-backend
[root@IaC tofu-backend]# vi provider.tf 
terraform {
  required_providers {
    openstack = {
      source  = &quot;terraform-provider-openstack/openstack&quot;
      version = &quot;~&amp;gt; 1.50.0&quot;
    }
  }

  backend &quot;s3&quot; {
    bucket                      = &quot;tofu-state&quot;
    key                         = &quot;tofu-backend/terraform.tfstate&quot;
    endpoint                    = &quot;http://repository:9000&quot;
    region                      = &quot;us-east-1&quot;
    access_key                  = &quot;minioadmin&quot;
    secret_key                  = &quot;minioadminpass&quot;
    skip_credentials_validation = true
    skip_region_validation      = true
    force_path_style            = true
    skip_metadata_api_check     = true
  }
}

provider &quot;openstack&quot; {
  insecure = true
}
~&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 다시 초기화를 해주면서 재구성해주면 로컬 -&amp;gt; s3로 백엔드가 변경되고 버킷 확인해보면 안에 저장된 게 보임&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;595&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s1zza/dJMcagDP338/MdkoNviNfnirtWPPa9Kfyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s1zza/dJMcagDP338/MdkoNviNfnirtWPPa9Kfyk/img.png&quot; data-alt=&quot;백엔드 변경&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s1zza/dJMcagDP338/MdkoNviNfnirtWPPa9Kfyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs1zza%2FdJMcagDP338%2FMdkoNviNfnirtWPPa9Kfyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;359&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;595&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;백엔드 변경&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1762756466173&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC tofu-backend]# mc ls -r repo
[2025-11-10 15:30:33 KST] 3.9KiB STANDARD tofu-state/tofu-backend/terraform.tfstate&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lYsOM/dJMcafx99Ni/NCQoH5KDZ7zH3gBR6YBkK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lYsOM/dJMcafx99Ni/NCQoH5KDZ7zH3gBR6YBkK1/img.png&quot; data-alt=&quot;여기 상태 저장&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lYsOM/dJMcafx99Ni/NCQoH5KDZ7zH3gBR6YBkK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlYsOM%2FdJMcafx99Ni%2FNCQoH5KDZ7zH3gBR6YBkK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;286&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;295&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;여기 상태 저장&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기가 잘 됐으니 이제 다시 메인 쿠버 클러스터 노드들 상태도 저장시킴. 마찬가지로 테라폼 블럭 안에 백엔드 지정 추가&lt;/p&gt;
&lt;pre id=&quot;code_1762756681633&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC tofu-backend]# cd ../opentofu/
[root@IaC opentofu]# vi provider.tf 
...
backend &quot;s3&quot; {
    bucket                      = &quot;tofu-state&quot;           
    key                         = &quot;main/terraform.tfstate&quot; 
    endpoint                    = &quot;http://repository:9000&quot;
    region                      = &quot;us-east-1&quot;
    access_key                  = &quot;minioadmin&quot;
    secret_key                  = &quot;minioadminpass&quot;
    use_path_style              = true             
    skip_credentials_validation = true
    skip_region_validation      = true
    skip_metadata_api_check     = true
  }
[root@IaC opentofu]# tofu init --reconfigure
[root@IaC opentofu]# mc ls -r  repo
[2025-11-10 15:39:07 KST]  26KiB STANDARD tofu-state/main/terraform.tfstate
[2025-11-10 15:30:33 KST] 3.9KiB STANDARD tofu-state/tofu-backend/terraform.tfstate&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;똑같이 상태가 저장됨. 근데 지금은 상태가 가장 마지막에 바뀐 것만 확인하고 이전 상태들은 확인 불가&lt;br /&gt;버전관리가 안 되는 상태라 이것도 활성화 시켜주면 됨 mc로 버킷 버전관리 활성화 가능&lt;/p&gt;
&lt;pre id=&quot;code_1762757127402&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# mc version enable repo/tofu-state
repo/tofu-state versioning is enabled&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 버전관리가 잘 되는지 확인하기 위해 저장소 작업 디렉터리 들어가 인스턴스에 태그만 추가하고 차이가 생겼는지 확인 하면 됨.&lt;/p&gt;
&lt;pre id=&quot;code_1762757462927&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# cd ../tofu-backend/
[root@IaC tofu-backend]# vi repo-instance.tf
data &quot;openstack_images_image_v2&quot; &quot;image&quot; {
  name = &quot;lab-rocky-9&quot;
}

data &quot;openstack_compute_flavor_v2&quot; &quot;backend_flavor&quot; {
  name = &quot;m1.medium&quot;
}

resource &quot;openstack_compute_instance_v2&quot; &quot;backend_server&quot; {
  name            = &quot;repository&quot;
  flavor_id       = data.openstack_compute_flavor_v2.backend_flavor.id
  image_id        = data.openstack_images_image_v2.image.id
  key_pair        = &quot;k8s-keypair&quot;
  security_groups = [&quot;lab&quot;]
## ---- 이거 추가 ---- ##
tags = [
    &quot;repo&quot;,
    &quot;minio-version-test&quot;,
  ]
## ---- 이거 추가 ---- ##

  network {
    name = &quot;net-infra&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 상태가 저장된 곳의 버전을 확인하면 기존 상태(v1) 외 하나가 더 추가된 게 보인다.&lt;/p&gt;
&lt;pre id=&quot;code_1762757714258&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC tofu-backend]# mc ls --versions repo/tofu-state/tofu-backend/terraform.tfstate
[2025-11-10 15:53:23 KST] 3.9KiB STANDARD 3d1b0e0e-2c5a-47f1-9486-67da074a8a3c v2 PUT terraform.tfstate
[2025-11-10 15:30:33 KST] 3.9KiB STANDARD null v1 PUT terraform.tfstate&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 오픈토푸 백엔드 설정과 상태 버전 관리는 완료함&lt;/p&gt;</description>
      <category>리눅스/실습</category>
      <category>IAC</category>
      <category>MinIO</category>
      <category>opentofu</category>
      <author>dbswjdahr</author>
      <guid isPermaLink="true">https://dbswjdahr.tistory.com/23</guid>
      <comments>https://dbswjdahr.tistory.com/23#entry23comment</comments>
      <pubDate>Mon, 10 Nov 2025 16:04:49 +0900</pubDate>
    </item>
    <item>
      <title>IaC 실습하기-3</title>
      <link>https://dbswjdahr.tistory.com/22</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 저장소용 인스턴스 생성과 ssh 연결 테스트까지 했으니 이번에는 디스크를 추가해준다.&lt;br /&gt;miniO, Gitea, Docker registry 컨테이너 이미지를 Podman으로 3개를 띄울 거기 때문에 블록 스토리지 3개를 추가해줌.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈토푸로 블록 스토리지 생성과 붙이기까지 가능하긴 하지만 엔드포인트를 찾을 수 없다는 에러가 떠서 이건 직접 붙여주기로 함.&lt;br /&gt;대시보드에서 생성하고 붙여줌&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-10 001401.png&quot; data-origin-width=&quot;1139&quot; data-origin-height=&quot;507&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqmbFJ/dJMcahvYybJ/teeMULL7IKArDYAlEbjYm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqmbFJ/dJMcahvYybJ/teeMULL7IKArDYAlEbjYm0/img.png&quot; data-alt=&quot;볼륨 붙이기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqmbFJ/dJMcahvYybJ/teeMULL7IKArDYAlEbjYm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqmbFJ%2FdJMcahvYybJ%2FteeMULL7IKArDYAlEbjYm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;285&quot; data-filename=&quot;스크린샷 2025-11-10 001401.png&quot; data-origin-width=&quot;1139&quot; data-origin-height=&quot;507&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;볼륨 붙이기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 들어가서 확인해보면 잘 붙은 게 보인다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;151&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCTv7m/dJMcafSsLWE/1MM969rZu8E6NmdzrdOKS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCTv7m/dJMcafSsLWE/1MM969rZu8E6NmdzrdOKS0/img.png&quot; data-alt=&quot;볼륨 붙임&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCTv7m/dJMcafSsLWE/1MM969rZu8E6NmdzrdOKS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCTv7m%2FdJMcafSsLWE%2F1MM969rZu8E6NmdzrdOKS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;484&quot; height=&quot;151&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;151&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;볼륨 붙임&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 IaC 노드로 돌아가서 저장소용으로 생성된 인스턴스에 디스크 파티션이랑 포맷해주고 Podman 설치하고 컨테이너 띄워주면 됨&lt;br /&gt;일단 디스크 파티션/포맷 하나, podman 설치 및 실행 하나로 yaml 파일 만들어 나눠줌&lt;/p&gt;
&lt;pre id=&quot;code_1762702956012&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ansible]# vi disk-setup.yaml 
- name: 디스크 파티션 및 포맷/마운트 설정
  hosts: repository
  become: yes
  tasks:

    - name: 필요한 패키지 설치 (parted)
      ansible.builtin.dnf:
        name: parted
        state: present

    - name: MinIO용 디스크 파티션 작업 하기
      community.general.parted:
        device: /dev/vdb
        number: 1
        state: present
        fs_type: xfs
        part_end: 100%
    - name: MinIO 포맷 작업 하기
      ansible.builtin.filesystem:
        fstype: xfs
        dev: /dev/vdb1
    - name: MinIO 마운트 지점 만들기 (/data/minio)
      ansible.builtin.file:
        path: /data/minio  
        state: directory
        mode: &quot;0755&quot;
    - name: MinIO 마운트 하기
      ansible.posix.mount:
        path: /data/minio
        src: /dev/vdb1
        fstype: xfs
        state: mounted
        opts: defaults,nofail

    - name: 깃티  디스크 파티션 하기
      community.general.parted:
        device: /dev/vdc
        number: 1
        state: present
        fs_type: xfs
        part_end: 100%
    - name: 깃티  포맷 작업 하기
      ansible.builtin.filesystem:
        fstype: xfs
        dev: /dev/vdc1
    - name: 깃티 마운트 지점 만들기 (/data/gitea)
      ansible.builtin.file:
        path: /data/gitea
        state: directory
        mode: '0755'
    - name: 깃티 마운트 하기
      ansible.posix.mount:
        path: /data/gitea
        src: /dev/vdc1
        fstype: xfs
        state: mounted
        opts: defaults,nofail

    - name: 도커 레지 디스크 파티션 하기
      community.general.parted:
        device: /dev/vdd
        number: 1
        state: present
        fs_type: xfs
        part_end: 100%
    - name: 도커 레지 포맷 작업 하기
      ansible.builtin.filesystem:
        fstype: xfs
        dev: /dev/vdd1
    - name: 도커 레지 마운트 지점 만들기 (/data/registry)
      ansible.builtin.file:
        path: /data/registry  
        state: directory
        mode: '0755'
    - name: 깃티 마운트 하기
      ansible.posix.mount:
        path: /data/registry
        src: /dev/vdd1
        fstype: xfs
        state: mounted
        opts: defaults,nofail&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1762703026905&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- name: 포드맨 컨테이너로 다 띄우기
  hosts: repository
  become: yes
  vars:
    MINIO_ACCESS_KEY: &quot;minioadmin&quot;
    MINIO_SECRET_KEY: &quot;minioadminpass&quot;  # 임의로 설정함
    GITEA_SSH_PORT: 2222
    REGISTRY_PORT: 5000
  tasks:
    - name: 포드맨 설치하기
      ansible.builtin.dnf:
        name: podman
        state: present

    - name: 미니오 컨테이너 실행
      containers.podman.podman_container:
        name: minio
        image: quay.io/minio/minio
        state: started
        restart_policy: always
        ports:
          - &quot;9000:9000&quot; 
          - &quot;9001:9001&quot;
        env:
          MINIO_ROOT_USER: &quot;{{ MINIO_ACCESS_KEY }}&quot;
          MINIO_ROOT_PASSWORD: &quot;{{ MINIO_SECRET_KEY }}&quot;
        volume:
          - &quot;/data/minio:/data:Z&quot; 
        command: server /data --address :9000 --console-address :9001

    - name: 도커 레지 컨테이너 실행
      containers.podman.podman_container:
        name: registry
        image: registry:latest
        state: started
        restart_policy: always
        ports:
          - &quot;{{ REGISTRY_PORT }}:5000&quot;
        volume:
          - &quot;/data/registry:/var/lib/registry:Z&quot; 

    - name: 깃티 컨테이너 실행
      containers.podman.podman_container:
        name: gitea
        image: docker.io/gitea/gitea:latest
        state: started
        restart_policy: always
        ports:
          - &quot;3000:3000&quot;
          - &quot;{{ GITEA_SSH_PORT }}:22&quot; 
        volume:
          - &quot;/data/gitea:/data:Z&quot; 
        env:
          USER_UID: '1000'
          USER_GID: '1000'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 작성됐으면 그대로 실행해주면 끝&lt;/p&gt;
&lt;pre id=&quot;code_1762704690128&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ansible]# ansible-playbook -i hosts disk-setup.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-10 003437.png&quot; data-origin-width=&quot;929&quot; data-origin-height=&quot;735&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ue3T4/dJMcaiaz4VC/DZe4alYCn49E8cn7Q2GIG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ue3T4/dJMcaiaz4VC/DZe4alYCn49E8cn7Q2GIG0/img.png&quot; data-alt=&quot;디스크 셋업 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ue3T4/dJMcaiaz4VC/DZe4alYCn49E8cn7Q2GIG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUe3T4%2FdJMcaiaz4VC%2FDZe4alYCn49E8cn7Q2GIG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;560&quot; height=&quot;443&quot; data-filename=&quot;스크린샷 2025-11-10 003437.png&quot; data-origin-width=&quot;929&quot; data-origin-height=&quot;735&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;디스크 셋업 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 들어가서 확인해보면 파티션부터 마운트까지 잘 확인 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;883&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r8pNI/dJMcacOYfHx/nZdo1YboZkZBLdxe0hywmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r8pNI/dJMcacOYfHx/nZdo1YboZkZBLdxe0hywmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r8pNI/dJMcacOYfHx/nZdo1YboZkZBLdxe0hywmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr8pNI%2FdJMcacOYfHx%2FnZdo1YboZkZBLdxe0hywmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;333&quot; data-origin-width=&quot;883&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 podman 설치 후 컨테이너 실행까지 시키자. &lt;br /&gt;podman을 쓴 이유는 docker처럼 대몬이 아니라 바로 깔자마자 사용 가능하고 추후 k8s 연계 용이성 때문&lt;/p&gt;
&lt;pre id=&quot;code_1762704702957&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ansible]# ansible-playbook -i hosts deploy-cons.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;589&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7B9tM/dJMcadtzLz1/Fyha1t4fBEDudYD4aISqJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7B9tM/dJMcadtzLz1/Fyha1t4fBEDudYD4aISqJ1/img.png&quot; data-alt=&quot;컨테이너도 잘 열렸다 확인됨&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7B9tM/dJMcadtzLz1/Fyha1t4fBEDudYD4aISqJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7B9tM%2FdJMcadtzLz1%2FFyha1t4fBEDudYD4aISqJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;420&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;589&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;컨테이너도 잘 열렸다 확인됨&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;html 태그가 잘 보이면 이건 컨테이너가 띄워지고 접근도 잘 된 거다. 이렇게 opentofu, ansible을 이용해 저장소 구축까지 완료&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1323&quot; data-origin-height=&quot;842&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YgyUY/dJMcabP3V5c/aTJnvzdN8akfPs7dBaPvhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YgyUY/dJMcabP3V5c/aTJnvzdN8akfPs7dBaPvhK/img.png&quot; data-alt=&quot;미니오 접근도 잘 됨&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YgyUY/dJMcabP3V5c/aTJnvzdN8akfPs7dBaPvhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYgyUY%2FdJMcabP3V5c%2FaTJnvzdN8akfPs7dBaPvhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;407&quot; data-origin-width=&quot;1323&quot; data-origin-height=&quot;842&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;미니오 접근도 잘 됨&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 미니오를 opentofu 백엔드로 설정해주면 상태가 여기에 저장되고 볼 수 있게 됨.&lt;/p&gt;</description>
      <category>리눅스/실습</category>
      <category>ansible</category>
      <category>MinIO</category>
      <category>openstack</category>
      <category>opentofu</category>
      <category>podman</category>
      <author>dbswjdahr</author>
      <guid isPermaLink="true">https://dbswjdahr.tistory.com/22</guid>
      <comments>https://dbswjdahr.tistory.com/22#entry22comment</comments>
      <pubDate>Mon, 10 Nov 2025 01:35:16 +0900</pubDate>
    </item>
    <item>
      <title>IaC 실습하기-2</title>
      <link>https://dbswjdahr.tistory.com/21</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이제 먼저 앤서블 실행 시 필요한 인벤토리 파일을 만듦&lt;/p&gt;
&lt;pre id=&quot;code_1762697250802&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# vi inventory.tf
resource &quot;local_file&quot; &quot;ansible_inventory&quot; {
  filename = &quot;../ansible/hosts&quot; 
  content = templatefile(&quot;${path.module}/inventory.tpl&quot;, {
    haproxy_ip    = openstack_compute_instance_v2.haproxy_server.network[0].fixed_ip_v4
    control_ips   = openstack_compute_instance_v2.control_plane[*].network[0].fixed_ip_v4 
    worker_ips    = openstack_compute_instance_v2.worker_node[*].network[0].fixed_ip_v4
    
    all_nodes_ips = concat(
        openstack_compute_instance_v2.control_plane[*].network[0].fixed_ip_v4,
        openstack_compute_instance_v2.worker_node[*].network[0].fixed_ip_v4,
    )
  })
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1762697281446&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# vi inventory.tpl 
[all:vars]
ansible_user=rocky 
ansible_ssh_private_key_file=/root/.ssh/id_ed25519_k8s
ansible_python_interpreter=/usr/bin/python3
ansible_ssh_common_args='-o StrictHostKeyChecking=no'

[k8s_cluster:children]
control
worker
haproxy

[haproxy]
proxy ansible_host=${haproxy_ip}

[control]
%{ for ip in control_ips ~}
control${index(control_ips, ip) + 1} ansible_host=${ip}
%{ endfor ~}

[worker]
%{ for ip in worker_ips ~}
worker${index(worker_ips, ip) + 1} ansible_host=${ip}
%{ endfor ~}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1762697428321&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# vi hosts.tf 
locals {
  control_host_lines = [
    for i in range(3) :
    &quot;${openstack_compute_instance_v2.control_plane[i].network[0].fixed_ip_v4} control${i + 1}&quot;
  ]
  worker_host_lines = [
    for i in range(5) :
    &quot;${openstack_compute_instance_v2.worker_node[i].network[0].fixed_ip_v4} worker${i + 1}&quot;
  ]

  k8s_nodes_hosts = join(&quot;\n&quot;, concat(local.control_host_lines, local.worker_host_lines))

  haproxy_host = &quot;${openstack_compute_instance_v2.haproxy_server.network[0].fixed_ip_v4} proxy&quot;
}


resource &quot;null_resource&quot; &quot;update_hosts_file&quot; {
  depends_on = [
    openstack_compute_instance_v2.haproxy_server,
    openstack_compute_instance_v2.control_plane,
    openstack_compute_instance_v2.worker_node,
  ]

  provisioner &quot;local-exec&quot; {
    command = &amp;lt;&amp;lt;-EOT
      HOSTS_FILE=/etc/hosts

      sed -i '/# K8S NODES START/,/# K8S NODES END/d' $HOSTS_FILE

      HOSTS_ENTRY=&quot;${local.haproxy_host}\n${local.k8s_nodes_hosts}&quot;

      echo &quot;&quot; &amp;gt;&amp;gt; $HOSTS_FILE
      echo &quot;# K8S NODES START&quot; &amp;gt;&amp;gt; $HOSTS_FILE
      echo &quot;$HOSTS_ENTRY&quot; &amp;gt;&amp;gt; $HOSTS_FILE
      echo &quot;# K8S NODES END&quot; &amp;gt;&amp;gt; $HOSTS_FILE
    EOT
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 3개의 코드를 더 만들어 줌. IaC 노드의 /etc/hosts에 노드들 등록, 앤서블 인벤토리 탬플릿과 그걸로 생성하는 코드 하나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해서 tofu init --upgrade 후 다시 apply 적용해주면 앤서블 디렉터리 밑에 hosts파일이 생기고 /etc/hosts에도 등록이 됨&lt;/p&gt;
&lt;pre id=&quot;code_1762697784691&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# tofu apply
data.openstack_compute_flavor_v2.haproxy_flavor: Reading...
data.openstack_compute_flavor_v2.k8s_node_flavor: Reading...
data.openstack_compute_flavor_v2.k8s_node_flavor: Read complete after 0s [id=ee1b3749-219e-4665-afb3-6d25b00d2d97]
data.openstack_compute_flavor_v2.haproxy_flavor: Read complete after 0s [id=774c9136-d522-4466-8097-a907dd4b50a8]

OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

OpenTofu will perform the following actions:

  # local_file.ansible_inventory will be created
  + resource &quot;local_file&quot; &quot;ansible_inventory&quot; {
      + content              = (known after apply)
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
...

openstack_compute_instance_v2.worker_node[1]: Still creating... [40s elapsed]
openstack_compute_instance_v2.worker_node[3]: Creation complete after 43s [id=917c9374-a4c0-4c81-898b-a528b842d8ab]
openstack_compute_instance_v2.control_plane[1]: Creation complete after 43s [id=4ab644fe-4f58-4d17-abfa-765fe6770253]
openstack_compute_instance_v2.control_plane[0]: Creation complete after 42s [id=c275c046-0d1a-40de-877a-a5a228c332b4]
openstack_compute_instance_v2.worker_node[1]: Still creating... [50s elapsed]
openstack_compute_instance_v2.worker_node[1]: Creation complete after 53s [id=3911b782-8389-49c9-ba08-699bfb05c2e1]
null_resource.update_hosts_file: Creating...
null_resource.update_hosts_file: Provisioning with 'local-exec'...
null_resource.update_hosts_file (local-exec): Executing: [&quot;/bin/sh&quot; &quot;-c&quot; &quot;HOSTS_FILE=/etc/hosts\n      \nsed -i '/# K8S NODES START/,/# K8S NODES END/d' $HOSTS_FILE\n      \nHOSTS_ENTRY=\&quot;10.0.1.50 haproxy\\n10.0.4.241 control1\n10.0.5.22 control2\n10.0.2.133 control3\n10.0.3.249 worker1\n10.0.5.69 worker2\n10.0.3.165 worker3\n10.0.3.6 worker4\n10.0.5.126 worker5\&quot;\n      \necho \&quot;\&quot; &amp;gt;&amp;gt; $HOSTS_FILE\necho \&quot;# K8S NODES START\&quot; &amp;gt;&amp;gt; $HOSTS_FILE\necho \&quot;$HOSTS_ENTRY\&quot; &amp;gt;&amp;gt; $HOSTS_FILE\necho \&quot;# K8S NODES END\&quot; &amp;gt;&amp;gt; $HOSTS_FILE\n&quot;]
local_file.ansible_inventory: Creating...
null_resource.update_hosts_file: Creation complete after 0s [id=5926752306975499695]
local_file.ansible_inventory: Creation complete after 0s [id=55527eea0bdf8a0ce8d1c2b57f36909314b3ea1a]

Apply complete! Resources: 21 added, 0 changed, 0 destroyed.

Outputs:

all_nodes_ips = [
  &quot;10.0.4.241&quot;,
  &quot;10.0.5.22&quot;,
  &quot;10.0.2.133&quot;,
  &quot;10.0.3.249&quot;,
  &quot;10.0.5.69&quot;,
  &quot;10.0.3.165&quot;,
  &quot;10.0.3.6&quot;,
  &quot;10.0.5.126&quot;,
]
control_plane_ips = [
  &quot;10.0.4.241&quot;,
  &quot;10.0.5.22&quot;,
  &quot;10.0.2.133&quot;,
]
haproxy_internal_ip = &quot;10.0.1.50&quot;
kube_api_endpoint = &quot;121.254.163.236&quot;
worker_node_ips = [
  &quot;10.0.3.249&quot;,
  &quot;10.0.5.69&quot;,
  &quot;10.0.3.165&quot;,
  &quot;10.0.3.6&quot;,
  &quot;10.0.5.126&quot;,
]
[root@IaC opentofu]# cat /etc/hosts 
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6



# K8S NODES START
10.0.1.50 proxy
10.0.4.241 control1
10.0.5.22 control2
10.0.2.133 control3
10.0.3.249 worker1
10.0.5.69 worker2
10.0.3.165 worker3
10.0.3.6 worker4
10.0.5.126 worker5
# K8S NODES END&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 진짜 앤서블로 클러스터 구성이 가능한 사전 준비가 끝났지만 그 전에 형상관리를 위한 저장소를 구축하고자 함&lt;br /&gt;저장소 인스턴스 하나 만들고 podman 컨테이너로 도커 레지스트리, 깃티, 미니오를 띄워 내부망 저장소를 만듦&lt;/p&gt;
&lt;pre id=&quot;code_1762694987153&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# cd ..
[root@IaC ~]# ls
ansible  opentofu
[root@IaC ~]# mkdir tofu-backend
[root@IaC ~]# cd tofu-backend/
[root@IaC ~]# pwd
/root/tofu-backend&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 프로바이더 똑같이 설정하고 디스크 추가하고 인스턴스 생성 코드 만들고 인벤토리에 얘도 추가시켜 줌.&lt;br /&gt;보안 그룹은 귀찮으니 이전에 만들어놨던 거 모든 TCP 허용 그룹 하나 가져와서 쓴다.&lt;br /&gt;여기서 디스크를 각 컨테이너마다 하나씩 추가한 이유는 관리 용이하게 하기 위해서와 인스턴스가 죽어도 데이터는 건질 수 있어서 이렇게 함&lt;br /&gt;물론 한 디스크로 파티션을 나눠서 해도 되지만 이것도 그냥 이렇게 함&lt;/p&gt;
&lt;pre id=&quot;code_1762695224812&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC tofu-backend]# vi provider.tf
terraform {
  required_providers {
    openstack = {
      source  = &quot;terraform-provider-openstack/openstack&quot;
      version = &quot;~&amp;gt; 1.50.0&quot;
    }
  }
}

provider &quot;openstack&quot; {
  insecure = true
  region = &quot;RegionOne&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1762698067520&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC tofu-backend]# vi repo-instance.tf 
data &quot;openstack_images_image_v2&quot; &quot;image&quot; {
  name = &quot;lab-rocky-9&quot;
}

data &quot;openstack_compute_flavor_v2&quot; &quot;backend_flavor&quot; {
  name = &quot;m1.medium&quot;
}

resource &quot;openstack_compute_instance_v2&quot; &quot;backend_server&quot; {
  name            = &quot;repository&quot;
  flavor_id       = data.openstack_compute_flavor_v2.backend_flavor.id
  image_id        = data.openstack_images_image_v2.image.id
  key_pair        = &quot;k8s-keypair&quot;
  security_groups = [&quot;lab&quot;]

  network {
    name = &quot;net-infra&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1762698086966&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;resource &quot;null_resource&quot; &quot;ansible_host_update&quot; {

  triggers = {
    backend_ip = openstack_compute_instance_v2.backend_server.access_ip_v4
  }

  provisioner &quot;local-exec&quot; {
    command = &amp;lt;&amp;lt;EOT
      BACKEND_IP=&quot;${self.triggers.backend_ip}&quot;
      HOST_NAME=&quot;${openstack_compute_instance_v2.backend_server.name}&quot;

      HOSTS_FILE=&quot;/root/ansible/hosts&quot;


      sed -i &quot;/^$HOST_NAME/d&quot; $HOSTS_FILE

      if ! grep -q &quot;\\[repo\\]&quot; $HOSTS_FILE; then
        echo -e &quot;\n[repo]&quot; &amp;gt;&amp;gt; $HOSTS_FILE
      fi

      echo &quot;$HOST_NAME ansible_host=$BACKEND_IP&quot; &amp;gt;&amp;gt; $HOSTS_FILE

      echo &quot;--- Updated Ansible Hosts File ---&quot;
      cat $HOSTS_FILE
    EOT
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tofu apply 로 실행하면 맨 아래 저장소 노드도 추가됨 이걸로 컨테이너 저장소 배포 자동화까지 하면 됨&lt;/p&gt;
&lt;pre id=&quot;code_1762700613998&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC tofu-backend]# cat /root/ansible/hosts
[all:vars]
ansible_user=rocky 
ansible_ssh_private_key_file=/root/.ssh/id_ed25519_k8s
ansible_python_interpreter=/usr/bin/python3
ansible_ssh_common_args='-o StrictHostKeyChecking=no'

[k8s_cluster:children]
control
worker
haproxy

[haproxy]
proxy ansible_host=10.0.1.50

[control]
control1 ansible_host=10.0.4.241
control2 ansible_host=10.0.5.22
control3 ansible_host=10.0.2.133

[worker]
worker-1 ansible_host=10.0.3.249
worker-2 ansible_host=10.0.5.69
worker-3 ansible_host=10.0.3.165
worker-4 ansible_host=10.0.3.6
worker-5 ansible_host=10.0.5.126

[repo]
repo ansible_host=10.0.2.163&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 IaC 노드의 hosts에도 등록해줌. 이제 앤서블로 컨테이너 띄우면 됨&lt;/p&gt;
&lt;pre id=&quot;code_1762700736048&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC tofu-backend]# awk -F&quot;[ =]+&quot; 'END{ print $3, $1 }' /root/ansible/hosts &amp;gt;&amp;gt; /etc/hosts
[root@IaC tofu-backend]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

# K8S NODES START
10.0.1.50 proxy
10.0.4.241 control1
10.0.5.22 control2
10.0.2.133 control3
10.0.3.249 worker1
10.0.5.69 worker2
10.0.3.165 worker3
10.0.3.6 worker4
10.0.5.126 worker5
# K8S NODES END
10.0.2.163 repository&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 앤서블로 핑 테스트해서 석세스가 뜨면 생성이랑 연결은 잘 된 거&lt;/p&gt;
&lt;pre id=&quot;code_1762702732740&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;[root@IaC tofu-backend]# cd ../ansible
[root@IaC ansible]# ansible repository -i hosts -m ping
repository | SUCCESS =&amp;gt; {
    &quot;changed&quot;: false,
    &quot;ping&quot;: &quot;pong&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>리눅스/실습</category>
      <category>ansible</category>
      <category>IAC</category>
      <category>openstack</category>
      <category>opentofu</category>
      <author>dbswjdahr</author>
      <guid isPermaLink="true">https://dbswjdahr.tistory.com/21</guid>
      <comments>https://dbswjdahr.tistory.com/21#entry21comment</comments>
      <pubDate>Sun, 9 Nov 2025 21:57:32 +0900</pubDate>
    </item>
    <item>
      <title>IaC 실습하기-1</title>
      <link>https://dbswjdahr.tistory.com/20</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;노트북의 Hyper-V에서는 VM을 4대 이상 올리기가 버거워 환경을 옮겨서 다양한 작업을 해보기로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 클라우드 교육 과정을 들으면서 운이 좋게도 강사님께서 운영하시는 오픈스택 클라우드 서버 환경을 제공받아 사용할 수 있게 되었었다.&lt;br /&gt;교육이 끝났지만 너무 감사하게도 강사님께서 무료로 최대 20대 가량의 인스턴스를 올리고 여러 작업을 할 수 있는 환경을 계속해서 제공해주심. &lt;br /&gt;메모리도 매우 넉넉해 8GB씩 여러 대를 할당해도 충분한 IaaS 서비스를 이용할 수 있게 됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 자원도 넉넉하고 여러대 생성도 가능하니 IaC로 쿠버네티스 클러스터를 구축함 오픈토푸, 앤서블을 사용해 인스턴스를 만들고 컨트롤 3대 워커 5대로 구성할 예정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈토푸는 테라폼의 라이선스 정책 변화로 포크한 오픈소스로 mysql - mariadb와 같이 terraform - opentofu 이러한 관계로 볼 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IaC 커맨드 인스턴스를 하나 생성해주고 작업하기 쉽게 root로 들어가서 일단 앤서블과 토푸 디렉터리로 작업 디렉터리를 나눠줌&lt;/p&gt;
&lt;pre id=&quot;code_1762615381905&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ~]# mkdir ansible
[root@IaC ~]# mkdir opentofu
[root@IaC ~]# ls
ansible  opentofu&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 앤서블과 토푸를 설치부터 하면 됨. 토푸는 직접 웹에서 가져와야 함&lt;br /&gt;&lt;a href=&quot;https://opentofu.org/docs/intro/install/&quot;&gt;https://opentofu.org/docs/intro/install/&lt;/a&gt; &amp;nbsp;여기서 배포판에 맞게 wget이나 curl로 다운 어차피 명령어도 친절하게 다 나와있음&lt;br /&gt;앤서블은 그냥 받을 수 있음&lt;/p&gt;
&lt;pre id=&quot;code_1762615679225&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ~]# curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
chmod +x install-opentofu.sh
./install-opentofu.sh --install-method rpm
rm -f install-opentofu.sh
[root@IaC ~]# dnf install -y ansible&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테라폼이나 오픈토푸를 사용하려면 해당 환경이 돌아가는 클라우드 플랫폼 정보를 알아야 한다. 이걸로 인증해야 함&lt;br /&gt;오픈스택의 경우에는 계정 밑에 RC 파일이나 yaml 파일을 다운받아 사용할 수 있다. 이걸 터미널로 복사해오면 됨&lt;br /&gt;aws랑 azure 등도 이와 비슷&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 yaml파일을 사용해보겠다. 다운받은 인증 파일을 .config 디렉터리를 만들어서 옮겨 자동으로 인식하게 하고 변수 지정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;565&quot; data-origin-height=&quot;469&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7cOUm/dJMcake91YL/WPLZkHOvRK9xlbxj0zvqrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7cOUm/dJMcake91YL/WPLZkHOvRK9xlbxj0zvqrk/img.png&quot; data-alt=&quot;토푸 사용 전 필요한 인증 파일 다운&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7cOUm/dJMcake91YL/WPLZkHOvRK9xlbxj0zvqrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7cOUm%2FdJMcake91YL%2FWPLZkHOvRK9xlbxj0zvqrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;398&quot; data-origin-width=&quot;565&quot; data-origin-height=&quot;469&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;토푸 사용 전 필요한 인증 파일 다운&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1762616507338&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ~]# mkdir -p ~/.config/openstack
[root@IaC ~]# mv clouds.yaml ~/.config/openstack/
[root@IaC ~]# vi .bashrc 
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific environment
if ! [[ &quot;$PATH&quot; =~ &quot;$HOME/.local/bin:$HOME/bin:&quot; ]]
then
    PATH=&quot;$HOME/.local/bin:$HOME/bin:$PATH&quot;
fi
export PATH

# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
### ----- 이거 추가 -----
export OS_CLOUD=&quot;openstack&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 clouds.yaml 여기에 비밀번호 정보가 없어서 추가해줌&lt;/p&gt;
&lt;pre id=&quot;code_1762685493049&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC ~]# vi ~/.config/openstack/clouds.yaml 
-bash: ca: command not found
[root@IaC ~]# cat ~/.config/openstack/clouds.yaml 
# This is a clouds.yaml file, which can be used by OpenStack tools as a source
# of configuration on how to connect to a cloud. If this is your only cloud,
# just put this file in ~/.config/openstack/clouds.yaml and tools like
# python-openstackclient will just work with no further config. (You will need
# to add your password to the auth section)
# If you have more than one cloud account, add the cloud entry to the clouds
# section of your existing file and you can refer to them by name with
# OS_CLOUD=openstack or --os-cloud=openstack
clouds:
  openstack:
    auth:
      auth_url: &amp;lt;오픈스택 주소&amp;gt;
      username: &amp;lt;오픈스택 사용자 계정&amp;gt;
      password: &amp;lt;오픈스택 사용자 비번&amp;gt; ## &amp;lt;= 이 부분 추가함
      project_id: c4adf84505f5489089a**********
      project_name: &amp;lt;오픈스택 플젝 이름&amp;gt;
      user_domain_name: &amp;lt;오픈스택 도메인&amp;gt;
    region_name: RegionOne
    interface: public
    identity_api_version: 3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이제 생성할 리소스들을 정의해줘야 하고 그 전에 프로바이더를 지정해줘야 함.&lt;br /&gt;그래야 오픈토푸가 지금 어떤 클라우드 환경인지 이해하고 플러그인을 다운받음.&lt;br /&gt;provider.tf를 작성하고 tofu init으로 작업디렉터리 초기화를 하면 리소스 생성 준비 끝&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제부터는 자원들을 생성하고 지정하고 등등 해야 하는데 gemini한테 물어보면서 했음&lt;br /&gt;오픈스택 환경이 관리자가 아니므로 램, 메모리 등의 자원은 직접 생성할 수 없어 있는 걸로 맞춤&lt;/p&gt;
&lt;pre id=&quot;code_1762687501564&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# vi provider.tf
terraform {
  required_providers {
    openstack = {
      source  = &quot;terraform-provider-openstack/openstack&quot;
      version = &quot;~&amp;gt; 1.50.0&quot;
    }
    tls = {
      source  = &quot;hashicorp/tls&quot;
      version = &quot;~&amp;gt; 4.0.0&quot;
    }
    local = {
      source  = &quot;hashicorp/local&quot;
      version = &quot;~&amp;gt; 2.4.0&quot;
    }
  }
}


provider &quot;openstack&quot; {
  insecure = true
}
provider &quot;tls&quot; {}
provider &quot;local&quot; {}
[root@IaC opentofu]# tofu init&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음에 키페어랑 보안그룹, 네트워크, 등을 정해줌&lt;/p&gt;
&lt;pre id=&quot;code_1762689352144&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# vi keypair.tf 
# 키페어 만들기
resource &quot;tls_private_key&quot; &quot;k8s_ssh_key&quot; {
  algorithm = &quot;ED25519&quot;
}

# 오픈스택에다가 키 등록
resource &quot;openstack_compute_keypair_v2&quot; &quot;k8s_keypair&quot; {
  name       = &quot;k8s-keypair&quot;
  public_key = tls_private_key.k8s_ssh_key.public_key_openssh
}

# 생성된 프라이빗 키 저장 (Ansible 접속용)
resource &quot;local_file&quot; &quot;private_key_pem&quot; {
  content         = tls_private_key.k8s_ssh_key.private_key_pem
  filename        = &quot;/root/.ssh/id_ed25519_k8s&quot;
  file_permission = &quot;0400&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1762689420886&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# vi segroup.tf
# k8s 클러스터 보안 그룹 생성
resource &quot;openstack_networking_secgroup_v2&quot; &quot;k8s_security_group&quot; {
  name        = &quot;k8s-cluster-sg&quot;
  description = &quot;Security group for Kubernetes cluster nodes (HAProxy, Control, Worker).&quot;
}

# SSH 접속 허용 (모든 노드)
resource &quot;openstack_networking_secgroup_rule_v2&quot; &quot;ssh_ingress&quot; {
  direction         = &quot;ingress&quot;
  ethertype         = &quot;IPv4&quot;
  protocol          = &quot;tcp&quot;
  port_range_min    = 22
  port_range_max    = 22
  remote_ip_prefix  = &quot;0.0.0.0/0&quot;
  security_group_id = openstack_networking_secgroup_v2.k8s_security_group.id
}

# Kube API Server 외부 접근 허용 &amp;lt;-  HAproxy로 로드밸런싱
resource &quot;openstack_networking_secgroup_rule_v2&quot; &quot;kube_api_ingress&quot; {
  direction         = &quot;ingress&quot;
  ethertype         = &quot;IPv4&quot;
  protocol          = &quot;tcp&quot;
  port_range_min    = 6443
  port_range_max    = 6443
  remote_ip_prefix  = &quot;0.0.0.0/0&quot; 
  security_group_id = openstack_networking_secgroup_v2.k8s_security_group.id
}

# 노드포트 전부 열기
resource &quot;openstack_networking_secgroup_rule_v2&quot; &quot;nodeport_ingress&quot; {
  direction         = &quot;ingress&quot;
  ethertype         = &quot;IPv4&quot;
  protocol          = &quot;tcp&quot;
  port_range_min    = 30000
  port_range_max    = 32767
  remote_ip_prefix  = &quot;0.0.0.0/0&quot;
  security_group_id = openstack_networking_secgroup_v2.k8s_security_group.id
}

# 클러스터 내부 통신은 다 허용 
resource &quot;openstack_networking_secgroup_rule_v2&quot; &quot;k8s_internal_ingress_all&quot; {
  direction         = &quot;ingress&quot;
  ethertype         = &quot;IPv4&quot;
  protocol          = &quot;&quot;
  remote_group_id   = openstack_networking_secgroup_v2.k8s_security_group.id
  security_group_id = openstack_networking_secgroup_v2.k8s_security_group.id
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1762689640776&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# vi network.tf 
# 플로팅 IP 리소스 생성
resource &quot;openstack_networking_floatingip_v2&quot; &quot;haproxy_fip&quot; {
  pool = var.floating_ip_pool_name
}

# 플로팅 IP는 외부에서 트래픽을 받을 HAProxy한테 
resource &quot;openstack_compute_floatingip_associate_v2&quot; &quot;haproxy_fip_associate&quot; {
  floating_ip = openstack_networking_floatingip_v2.haproxy_fip.address
  instance_id = openstack_compute_instance_v2.haproxy_server.id
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 여기에서 생성된 자원들은 변수로 따로 지정해줌&lt;/p&gt;
&lt;pre id=&quot;code_1762689969851&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# vi variables.tf 
variable &quot;image_name&quot; {
  description = &quot;VM 생성 OS 이미지 이름&quot;
  type        = string
  default     = &quot;lab-rocky-9&quot;
}

variable &quot;key_pair_name&quot; {
  description = &quot;VM들 접속에 사용될 SSH 키 페어 이름&quot;
  type        = string
  default     = &quot;k8s-keypair&quot;
}

variable &quot;network_name&quot; {
  description = &quot;VM 네트워크 이름&quot;
  type        = string
  default     = &quot;net-infra&quot;
}

variable &quot;floating_ip_pool_name&quot; {
  description = &quot;플로팅 IP를 할당받을 외부망 (HAProxy한테)&quot;
  type        = string
  default     = &quot;net-external&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 마지막으로 인스턴스를 생성하면 됨&lt;/p&gt;
&lt;pre id=&quot;code_1762690071438&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# vi instances.tf 
# opentofu/instance.tf

# HAProxy 서버용 Flavor
data &quot;openstack_compute_flavor_v2&quot; &quot;haproxy_flavor&quot; {
  name  = &quot;m1.medium&quot;
}

# 컨트롤 노드 및 워커 노드용 Flavor
data &quot;openstack_compute_flavor_v2&quot; &quot;k8s_node_flavor&quot; {
  name  = &quot;t1.kubernetes&quot;
}

# HAProxy 인스턴스 1대 생성
resource &quot;openstack_compute_instance_v2&quot; &quot;haproxy_server&quot; {
  name            = &quot;haproxy&quot;
  flavor_id       = data.openstack_compute_flavor_v2.haproxy_flavor.id
  image_name      = var.image_name
  key_pair        = openstack_compute_keypair_v2.k8s_keypair.name
  security_groups = [openstack_networking_secgroup_v2.k8s_security_group.name]
  network {
    name = var.network_name
  }
}

# 컨트롤 노드 3대 생성
resource &quot;openstack_compute_instance_v2&quot; &quot;control_plane&quot; {
  count           = 3
  name            = &quot;control${count.index + 1}&quot;
  flavor_id       = data.openstack_compute_flavor_v2.k8s_node_flavor.id
  image_name      = var.image_name
  key_pair        = openstack_compute_keypair_v2.k8s_keypair.name
  security_groups = [openstack_networking_secgroup_v2.k8s_security_group.name]
  network {
    name = var.network_name
  }
}

# 워커 노드 5대 생성
resource &quot;openstack_compute_instance_v2&quot; &quot;worker_node&quot; {
  count           = 5
  name            = &quot;worker${count.index + 1}&quot;
  flavor_id       = data.openstack_compute_flavor_v2.k8s_node_flavor.id
  image_name      = var.image_name
  key_pair        = openstack_compute_keypair_v2.k8s_keypair.name
  security_groups = [openstack_networking_secgroup_v2.k8s_security_group.name]
  network {
    name = var.network_name
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 앤서블로 클러스터 구성까지 해야 하므로 아웃풋도 만들어 준다.&lt;/p&gt;
&lt;pre id=&quot;code_1762690220732&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# cat output.tf 
# HAProxy 서버의 내부 IP 주소
output &quot;haproxy_internal_ip&quot; {
  description = &quot;HAProxy Server의 내부(Fixed) IP 주소&quot;
  value       = openstack_compute_instance_v2.haproxy_server.network[0].fixed_ip_v4
}

# HAProxy 서버의 외부 IP 주소
output &quot;kube_api_endpoint&quot; {
  description = &quot;Kubernetes API Server 접속용 Floating IP&quot;
  value       = openstack_networking_floatingip_v2.haproxy_fip.address
}

# 컨트롤 노드들의 내부 IP 주소 목록
output &quot;control_plane_ips&quot; {
  description = &quot;컨트롤 노드들의 내부 IP 주소 목록&quot;
  value       = [for instance in openstack_compute_instance_v2.control_plane : instance.network[0].fixed_ip_v4]
}

# 워커 노드들의 내부 IP 주소 목록
output &quot;worker_node_ips&quot; {
  description = &quot;워커 노드들의 내부 IP 주소 목록&quot;
  value       = [for instance in openstack_compute_instance_v2.worker_node : instance.network[0].fixed_ip_v4]
}

# 모든 노드들의 내부 IP 주소 목록 (Ansible hosts 그룹 정의용)
output &quot;all_nodes_ips&quot; {
  description = &quot;모든 K8s 노드들의 내부 IP 주소 목록&quot;
  value       = concat(
    [for instance in openstack_compute_instance_v2.control_plane : instance.network[0].fixed_ip_v4],
    [for instance in openstack_compute_instance_v2.worker_node : instance.network[0].fixed_ip_v4],
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 문제 없는지 확인하고 apply로 실행 시키면 끝&lt;/p&gt;
&lt;pre id=&quot;code_1762690286447&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# tofu fmt
instances.tf
output.tf
provider.tf
segroup.tf
[root@IaC opentofu]# tofu validate
Success! The configuration is valid.
[root@IaC opentofu]# tofu apply --auto-approve
tls_private_key.k8s_ssh_key: Refreshing state... [id=25508cc8a3af110f4cd006bf296183a3deddb7a5]
local_file.private_key_pem: Refreshing state... [id=8b51f04f03fa0832b23c531268d74ec7b7d3e2ce]
data.openstack_compute_flavor_v2.haproxy_flavor: Reading...
openstack_networking_secgroup_v2.k8s_security_group: Refreshing state... [id=a0e24613-3c35-4c6f-81c2-cc5d25e66f99]
openstack_networking_floatingip_v2.haproxy_fip: Refreshing state... [id=93e907ef-76db-44d6-8da9-6d68bfd4c3b8]
data.openstack_compute_flavor_v2.k8s_node_flavor: Reading...
openstack_compute_keypair_v2.k8s_keypair: Refreshing state... [id=k8s-keypair]
openstack_networking_secgroup_rule_v2.nodeport_ingress: Refreshing state... [id=f63afd80-faa7-4dbf-be80-31d543da589d]
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 대시보드 가서 보면 잘 생성됨&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJocXr/dJMcafEVt7h/A34bXm5k7AKzKh7kK2fUC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJocXr/dJMcafEVt7h/A34bXm5k7AKzKh7kK2fUC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJocXr/dJMcafEVt7h/A34bXm5k7AKzKh7kK2fUC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJocXr%2FdJMcafEVt7h%2FA34bXm5k7AKzKh7kK2fUC1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;420&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;714&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1762690366421&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[root@IaC opentofu]# tofu output
all_nodes_ips = [
  &quot;10.0.1.60&quot;,
  &quot;10.0.4.53&quot;,
  &quot;10.0.4.37&quot;,
  &quot;10.0.3.211&quot;,
  &quot;10.0.3.75&quot;,
  &quot;10.0.1.12&quot;,
  &quot;10.0.5.110&quot;,
  &quot;10.0.4.38&quot;,
]
control_plane_ips = [
  &quot;10.0.1.60&quot;,
  &quot;10.0.4.53&quot;,
  &quot;10.0.4.37&quot;,
]
haproxy_internal_ip = &quot;10.0.2.7&quot;
kube_api_endpoint = &quot;121.254.163.235&quot;
worker_node_ips = [
  &quot;10.0.3.211&quot;,
  &quot;10.0.3.75&quot;,
  &quot;10.0.1.12&quot;,
  &quot;10.0.5.110&quot;,
  &quot;10.0.4.38&quot;,
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아웃풋을 따로 만들어서 출력해서 확인도 가능&lt;br /&gt;이제 앤서블로 클러스터 구성하면 됨&lt;/p&gt;</description>
      <category>리눅스/실습</category>
      <category>IAC</category>
      <category>openstack</category>
      <category>opentofu</category>
      <author>dbswjdahr</author>
      <guid isPermaLink="true">https://dbswjdahr.tistory.com/20</guid>
      <comments>https://dbswjdahr.tistory.com/20#entry20comment</comments>
      <pubDate>Sun, 9 Nov 2025 21:39:56 +0900</pubDate>
    </item>
  </channel>
</rss>