<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>19dasy.log</title>
        <link>https://velog.io/</link>
        <description>Let's study </description>
        <lastBuildDate>Fri, 07 Apr 2023 08:33:57 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. 19dasy.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/sophi_e" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Tableau] 태블로 BigQuery 커넥터 설정 (errorCode=170001)]]></title>
            <link>https://velog.io/@sophi_e/Tableau-%ED%83%9C%EB%B8%94%EB%A1%9C-BigQuery-%EC%BB%A4%EB%84%A5%ED%84%B0-%EC%84%A4%EC%A0%95-errorCode170001</link>
            <guid>https://velog.io/@sophi_e/Tableau-%ED%83%9C%EB%B8%94%EB%A1%9C-BigQuery-%EC%BB%A4%EB%84%A5%ED%84%B0-%EC%84%A4%EC%A0%95-errorCode170001</guid>
            <pubDate>Fri, 07 Apr 2023 08:33:57 GMT</pubDate>
            <description><![CDATA[<p>태블로 데이터 원본 연동 작업 과정 중, Google BigQuery 연동시 발생한 문제를 해결한 과정을 정리한 내용입니다. </p>
<h2 id="1-문제-상황-에러-코드">1. 문제 상황 (에러 코드)</h2>
<pre><code>Custom OAuth is not configured for this datasource. Learn more. (errorCode=170001)</code></pre><ul>
<li>결론적으로, BigQuery 커넥터에 구글 OAuth client ID로 태블로 서버에 구성이 필요함   (<a href="https://kb.tableau.com/articles/issue/custom-oauth-is-not-configured-for-this-datasource-lean-more-errorcode-170001?lang=en-gb">링크</a>)</li>
</ul>
<br>
---

<h2 id="2-해결-방법">2. 해결 방법</h2>
<ul>
<li>Step1. Google OAuth Client ID 및 Redirect URL 생성  </li>
<li>Step2. 태블로 서버에 생성한 Oauth Client ID와 Redirect URL 등록 </li>
</ul>
<br>


<h3 id="step1">[Step1]</h3>
<ul>
<li><p>구글 OAuth 설정을 위한 프로젝트 생성 ( [<a href="https://help.tableau.com/current/server/en-us/config_oauth_google.htm">Set up OAuth for Google</a>] </p>
<ul>
<li>APIs &amp; Services &gt; OAuth consent screen 클릭<ul>
<li>유저 타입을 설정하고 이후 작성 항목들에 대하여 입력</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>APIs &amp; Services &gt; Credentials (사용자 인증 정보) 등록 </p>
<ul>
<li>Create Credentials &gt; OAuth client ID 
  <img src="https://velog.velcdn.com/images/sophi_e/post/56126d66-29a9-4f6d-b68c-2f96cf6a04d9/image.png" alt=""></li>
</ul>
</li>
<li><p>Application type에 태블로의 어플리케이션 타입을 입력 → Web application</p>
<ul>
<li><p>권한이 승인된 자바스크립 원본 
→ https 나 http로 시작하는 태블로 웹 페이지 URL을 추가함</p>
</li>
<li><p>승인된 리디렉션 원본 → https 나 http로 시작하는 <code>웹페이지 URL</code> + <code>/auth/add_oauth_token</code> 을 추가</p>
<p><code>https://your_server_url/auth/add_oauth_token</code>
<img src="https://velog.velcdn.com/images/sophi_e/post/5c7a5555-1343-43f6-b03e-2325bffc174a/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<h3 id="step2">[Step2]</h3>
<ul>
<li><p>Redirect URL을 이용하여 로컬PC에서 태블로에 접근하여 Client ID와 비밀번호를 입력해서 등록</p>
</li>
<li><p><strong>Register the OAuth client ID and client secret!</strong></p>
<ul>
<li>관리자 권한 계정으로 태블로 웹페이지 서버로 들어가서 , 위에 설정한 정보들을 입력하여 등록<pre><code>   ![](https://velog.velcdn.com/images/sophi_e/post/b6aa64c8-288d-48f6-92c9-f3c9072b88ac/image.png)</code></pre></li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BigQuery] 절차적 언어1(Procedural language) (DECLARE/EXECUTE/SET/BEGIN)]]></title>
            <link>https://velog.io/@sophi_e/BigQuery-%EC%A0%88%EC%B0%A8%EC%A0%81-%EC%96%B8%EC%96%B41Procedural-language-DECLAREEXECUTESETBEGIN</link>
            <guid>https://velog.io/@sophi_e/BigQuery-%EC%A0%88%EC%B0%A8%EC%A0%81-%EC%96%B8%EC%96%B41Procedural-language-DECLAREEXECUTESETBEGIN</guid>
            <pubDate>Thu, 09 Mar 2023 11:48:01 GMT</pubDate>
            <description><![CDATA[<p>참고 : <a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language">https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language</a></p>
<h2 id="절차적-언어란">절차적 언어란?</h2>
<hr>
<ul>
<li>one query에서 다중 statement를 multi statements query로 실행할 수 있음</li>
<li>multiple statements 쿼리를 사용하여 다음을 수행<ul>
<li>순차적으로 multi statements를 수행함</li>
<li>테이블들을 생성/삭제와 같은 관리 작업을 자동화함</li>
<li><code>IF</code>와 <code>WHILE</code>과 같은 프로그래밍 구조를 사용하여 복잡한 로직을 실행함</li>
</ul>
</li>
</ul>
<br>

<h2 id="1-declare"><strong>1. DECLARE</strong></h2>
<pre><code class="language-sql">DECLARE variable_name[, ...] [variable_type] [DEFAULT expression];</code></pre>
<ul>
<li><p>variable_name은 타당한 구분자가 되어야만 하며, variable type은 GoogleSQL type 중 하나 (<a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types">링크</a>)</p>
</li>
<li><p><code>DECLARE</code> 변수명을 기재하는 구문</p>
</li>
<li><p><code>DEFAULT</code></p>
<ul>
<li>지정되면, 변수는 그 expression의 값으로 초기화 되지만, 만약 default값이 지정되지 않으면 변수는 null값으로 초기화됨</li>
<li>variable_type이 생략된다면, <code>DEFAULT</code>가 반드시 반드시 상세화되어야 함<ul>
<li>변수의 유형은 <code>DEFAULT</code>  expression으로 추론됨</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>주의점 및 특징</strong></p>
<ul>
<li>변수의 선언은 다른 절차적 선언문(procedural statuemnets)에서 전에 노출되어야만 함(혹은 BEGIN 블록의 시작점에서)</li>
<li>변수의 이름은 case-insensitive(대소문자 구분 없음 ↔ case-sensitive)</li>
<li>여러 개의 변수가 <code>DECLARE</code> 에서 선언될 수 있지만, 변수 유형이나 expression은 하나만 가능함</li>
<li>현재 블록 <strong>또는</strong> 포함 블럭에서 이전에 선언한 변수와 <strong>같은 이름을 가진 변수를 선언하는 것은 오류가 남</strong></li>
<li>다중 쿼리문의 실행동안 오류 메시지 등 정보를 체크하기 위한 <strong>system variable</strong>을 사용할 수 있음(<a href="https://cloud.google.com/bigquery/docs/reference/system-variables">링크</a>)</li>
</ul>
</li>
</ul>
<ul>
<li><strong>코드 예시</strong></li>
</ul>
<pre><code class="language-sql">DECLARE x INT64;
DECLARE d DATE DEFAULT CURRENT_DATE();
DECLARE x, y, z INT64 DEFAULT 0;

# 테이블 스키마로부터 item 변수의 유형을 추론하여 default expression과 type 적용  
DECLARE item DEFAULT (SELECT item FROM schema1.products LIMIT 1);</code></pre>
<br>

<h2 id="2-set">2. SET</h2>
<ul>
<li><p>선언한 변수에 대한 설정값</p>
<ul>
<li>값을 가질 수 있는 변수를 설정하고(디폴트 말고 초기값 셋팅임), 다중 표현식의 결과에 기반하여 다중 변수를 셋팅함</li>
</ul>
</li>
<li><p>코드 예시</p>
<pre><code class="language-sql">  # x변수는 5로 설정
  SET x = 5;

  # a = 4, b = &#39;foo&#39;, c = false 로 설정됨 
  SET (a, b, c) = (1 + 3, &#39;foo&#39;, false);</code></pre>
</li>
</ul>
<ul>
<li>다중 변수에 쿼리의 결과를 할당하는 예시<ol>
<li>두 변수를 선언 (target_word, corpus_count)</li>
<li><code>SELECT AS STRUCT</code> 쿼리의 결과로 선언한 두 변수에 할당함 <ul>
<li>쿼리의 결과는 두 필드를 가진 STRUCT의 단일값을 포함</li>
</ul>
</li>
<li>첫번째 요소는 첫번째 변수에, 두번째 요소는 두번째 변수에 할당함 </li>
</ol>
</li>
</ul>
<pre><code class="language-sql">DECLARE target_word STRING DEFAULT &#39;methinks&#39;;
DECLARE corpus_count, word_count INT64;

SET (corpus_count, word_count) = (
  SELECT AS STRUCT COUNT(DISTINCT corpus), SUM(word_count)
  FROM bigquery-public-data.samples.shakespeare
  WHERE LOWER(word) = target_word
);

SELECT
  FORMAT(&#39;Found %d occurrences of &quot;%s&quot; across %d Shakespeare works&#39;,
         word_count, target_word, corpus_count) AS result;</code></pre>
<ul>
<li><p>결과</p>
<ul>
<li><p>Found <strong>151</strong> occurrences of &quot;<strong>methinks</strong>&quot; across <strong>38</strong> Shakespeare works</p>
<br>


</li>
</ul>
</li>
</ul>
<h2 id="3-execute-immediate"><strong>3. EXECUTE IMMEDIATE</strong></h2>
<ul>
<li><p>동적 SQL문을 즉시 실행시킴</p>
</li>
<li><p>Syntax</p>
<pre><code class="language-sql">  EXECUTE IMMEDIATE sql_expression [ INTO variable[, ...] ] [ USING identifier[, ...] ];

  sql_expression:
    { &quot;query_statement&quot; | expression(&quot;query_statement&quot;) }

  identifier:
    { variable | value } [ AS alias ]</code></pre>
<ul>
<li><code>sql_expression</code> : 쿼리문 표현문. 단일 DDL or DML 구문.  <code>IF</code>와 같은 컨트롤 구문은 사용할 수 없음</li>
<li><code>expression</code> : 함수, 조건식 혹은 서브쿼리의 표현식임</li>
<li><code>query_statement</code><ul>
<li>실행하기 위한 standalone SQL 구문</li>
<li>만약 값을 리턴한다면, <code>INTO</code> 절은 반드시 같은 유형의 값을 포함해야함</li>
</ul>
</li>
<li><code>INTO</code><ul>
<li>SQL 표현식이 실행된 이후에,  한 개 또는 그 이상의 변수에서 결과를 저장할 수 있음</li>
</ul>
</li>
<li><code>USING</code><ul>
<li>SQL 표현식을 실행하기 전에,  <code>USING</code> 절의 한 개 또는 그 이상의 구분자를 쿼리로 전달할 수 있음</li>
<li>이 식별자는 쿼리 파라미터와 유사하게 작동하여 쿼리문에 노출됨</li>
<li>하나의 구분자는 <strong>variable</strong> 혹은 <strong>value</strong>가  될 수 있음</li>
</ul>
</li>
</ul>
</li>
<li><p>예제</p>
<ul>
<li><p><code>?</code> : palaceholder(자리표시자)로 USING 절에 인덱스로 구분자와 묶임</p>
<p>```sql</p>
</li>
<li><ul>
<li>y = 1 * (3 + 2) = 5
EXECUTE IMMEDIATE &quot;SELECT ? * (? + 2)&quot; INTO y USING 1, 3;<pre><code></code></pre></li>
</ul>
</li>
<li><p><code>@identifier</code>: USING절에 이름으로부터 구분자와 묶임</p>
<p>```sql</p>
</li>
<li><ul>
<li>y = 1 * (3 + 2) = 5
EXECUTE IMMEDIATE &quot;SELECT @a * (@b + 2)&quot; INTO y USING 1 as a, 3 as b;<pre><code></code></pre></li>
</ul>
</li>
</ul>
</li>
<li><p>예제2</p>
<pre><code class="language-sql">  -- create some variables
  DECLARE book_name STRING DEFAULT &#39;Ulysses&#39;;
  DECLARE book_year INT64 DEFAULT 1922;
  DECLARE first_date INT64;

  -- Create a temporary table called Books.
  EXECUTE IMMEDIATE
    &quot;CREATE TEMP TABLE Books (title STRING, publish_date INT64)&quot;;

  -- Add a row for Hamlet (less secure)
  EXECUTE IMMEDIATE
    &quot;INSERT INTO Books (title, publish_date) VALUES(&#39;Hamlet&#39;, 1599)&quot;;

  -- add a row for Ulysses, using the variables declared and the ? placeholder
  EXECUTE IMMEDIATE
    &quot;INSERT INTO Books (title, publish_date) VALUES(?, ?)&quot;
    USING book_name, book_year;

  -- add a row for Emma, using the identifier placeholder
  EXECUTE IMMEDIATE
    &quot;INSERT INTO Books (title, publish_date) VALUES(@name, @year)&quot;
    USING 1815 as year, &quot;Emma&quot; as name;

  -- add a row for Middlemarch, using an expression
  EXECUTE IMMEDIATE
    CONCAT(
      &quot;INSERT INTO Books (title, publish_date)&quot;, &quot;VALUES(&#39;Middlemarch&#39;, 1871)&quot;
    );

  -- save the publish date of the first book, Hamlet, to a variable called
  -- first_date
  EXECUTE IMMEDIATE &quot;SELECT publish_date FROM Books LIMIT 1&quot; INTO first_date;

  +------------------+------------------+
  | title            | publish_date     |
  +------------------+------------------+
  | Hamlet           | 1599             |
  | Ulysses          | 1922             |
  | Emma             | 1815             |
  | Middlemarch      | 1871             |
  +------------------+------------------+</code></pre>
</li>
</ul>
<br>

<h2 id="4-beginend"><strong>4. BEGIN...END</strong></h2>
<pre><code class="language-sql">BEGIN
  sql_statement_list
END;</code></pre>
<ul>
<li><p><code>BEGIN</code> : <code>END</code>가 나올 때까지만 선언된 변수가 존재하는 곳의 구문의 블록을 초기화한다.</p>
</li>
<li><p><code>sql_statement_list</code> : 0~그 이상의 <code>;</code> 으로 끝나는 SQL문의 리스트</p>
</li>
<li><p>선언된 변수</p>
<ul>
<li><p>변수 선언은 구문들 증 다른 유형의 변수 이전에 있는 블록의 시작점에서 나옴</p>
</li>
<li><p>블록 안에서 선언된 변수들은 그 블록과 포함되고 있는 블록 안에 참조될 수 있음</p>
<ul>
<li><p>즉 , <code>BEGIN…END</code> 구문 안에서 선언된 변수 이 안에서만 활용 가능하고, 구문 밖에서는 선언이 안됨 (하지만  같은 변수명으로 선언할 수 없음)</p>
</li>
<li><p>예시</p>
<pre><code class="language-sql">  BEGIN
    DECLARE y INT64;
    DECLARE x INT64 DEFAULT 10;
    SET y = x;
    SELECT y, x;
  END;
  SELECT x;</code></pre>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/127fb219-fb94-4d70-9a65-403888a26dcf/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code>- 같은 블록 혹은 다른 블록에서 선언된 변수와 같은 이름을 선언하는 것은 오류가 남</code></pre><ul>
<li>블록당 최대 50개 수준을 포함할 수 있고, <code>BEGIN/END</code>, <code>IF/ELSE/END/IF</code>,  <code>WHILE/END</code>와 같은 조건문이 있음</li>
<li><code>BEGIN/END</code> 는 포함된 요소들과 같이 동적으로 실행됨으로써 제한됨</li>
<li>Labels<ul>
<li><code>BEGINE…END</code> 구문에는 label을 생성 할 수 있음(<a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#labels">링크</a>)</li>
</ul>
</li>
</ul>
<pre><code>    ```sql
    label_name: BEGIN
      block_statement_list
    END [label_name];
    ```</code></pre><ul>
<li>예시</li>
</ul>
<pre><code>DECLARE x INT64 DEFAULT 10;
BEGIN
  DECLARE y INT64;
  SET y = x;
  SELECT y;
END;
SELECT x;</code></pre><br>

<h2 id="5-beginexceptionend"><strong>5. BEGIN...EXCEPTION...END</strong></h2>
<pre><code class="language-sql">BEGIN
  sql_statement_list
EXCEPTION WHEN ERROR THEN
  sql_statement_list
END;</code></pre>
<ul>
<li><code>BEGIN … EXCEPTION</code> : 블록안에 있는 구문들을 실행함<ul>
<li>블록 내 구문에서 에러가 발생한다면, 블록의 나머지 구문은 무시하고, <code>EXCEPTION</code>절이 실행됨</li>
</ul>
</li>
<li><code>EXCEPTION</code> 시스템 변수를 이용하여 에러에 대한 세부 정보를 확인할 수  있음</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/0c36d7c9-c5a4-403e-a891-7a39c022ea2d/image.png" alt=""></p>
<ul>
<li><h2 id="예제">예제</h2>
<pre><code class="language-sql">  BEGIN
    declare x string default &#39;exam&#39; ;
    declare y int64 default 12 ;
    select x + y ; # string + int 로 에러 상황 만들기 
  EXCEPTION WHEN ERROR THEN
    SELECT
      @@error.message,
      @@error.stack_trace,
      @@error.statement_text,
      @@error.formatted_stack_trace;
  END;</code></pre>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/91e43a57-b113-48a5-829d-db05611d12ff/image.png" alt=""></p>
<ul>
<li>첫 번째 결과 보기
<img src="https://velog.velcdn.com/images/sophi_e/post/59301e6b-b3e2-47bf-8c08-7b092503b38f/image.png" alt=""></li>
</ul>
<ul>
<li><p>두 번째 결과 보기</p>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/e960ec55-b0a5-498f-83f0-22e3bfe9e188/image.png" alt=""></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ [Docker] docker image란? 도커 이미지 만들기]]></title>
            <link>https://velog.io/@sophi_e/Docker-docker-image%EB%9E%80-%EB%8F%84%EC%BB%A4-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@sophi_e/Docker-docker-image%EB%9E%80-%EB%8F%84%EC%BB%A4-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Tue, 21 Feb 2023 12:08:58 GMT</pubDate>
            <description><![CDATA[<p>아래 내용은 인프런 강의 <strong>초보를 위한 도커 안내서</strong>를 정리한  내용입니다.</p>
<h2 id="1-도커-이미지란">1. 도커 이미지란?</h2>
<hr>
<ul>
<li><p>commit 으로 하는 방식과 build하는 방식으로 이미지를 생성할 수 있음</p>
</li>
<li><p>도커는 레이어드 파일 시스템 기반임</p>
<ul>
<li>레이어드 파일 시스템이란 ?</li>
</ul>
</li>
<li><p>이미지는 프로세스가 실행되는 파일의 집합(환경)</p>
<ul>
<li>리눅스라 하면 여러개의 파일이 있으면 이 파일이 전체 다 필요함(이걸 압축해놓은 것임)</li>
</ul>
</li>
<li><p>프로세스는 환경(파일)을 변경할 수 있음</p>
</li>
<li><p>이 환경을 저장해서 새로운 이미지를 만듬</p>
</li>
<li><p>이미지는 읽기 전용 VS 쓰기 전용 이 두가지로 나뉨</p>
<ul>
<li>읽기 전용<ul>
<li>수정할 수 없는 영역</li>
<li>예시로 우분투 이미지는 내가 수정할 수 없지만 새롭게 추가 수정 삭제할 수 있는 것임
<img src="https://velog.velcdn.com/images/sophi_e/post/d121eb06-145e-4357-8751-8fb8eba277d0/image.png" alt=""></li>
</ul>
</li>
</ul>
</li>
<li><p>베이스 이미지에 깃을 추가해서 새로운 커스텀 이미지를 만들 수 있음
  <img src="https://velog.velcdn.com/images/sophi_e/post/50d3582d-9e6e-4801-9ea0-a3ec0a24932e/image.png" alt=""></p>
</li>
</ul>
<ul>
<li><p>도커 이미지 네이밍 규칙</p>
<p>  <code>docker build -t mysname/ubuntu:airflow</code>
  <img src="https://velog.velcdn.com/images/sophi_e/post/797c43b2-2369-47e2-81af-25bad005c96d/image.png" alt=""></p>
</li>
</ul>
<ul>
<li><p>도커 우분투에 깃 이미지 설치하여 이미지 생성</p>
<pre><code class="language-bash">  docker run -it --name git ubuntu:latest bash 

  # apt-get update
  # apt-get install -y git
  # git --version

  docker images | grep ubuntu
  docker commit git ubuntu:git
  docker images | grep ubuntu</code></pre>
</li>
</ul>
<h2 id="2-dockerfile">2. Dockerfile</h2>
<hr>
<ul>
<li><p>서버에 직접 입력하는 과정을 하나의 파일로 관리</p>
<ul>
<li>최초부터 어떤 과정을 걸처 프로그램이 설치된 것인지 관리하기 편함</li>
</ul>
</li>
<li><p>build로 생성하는 도커 이미지를 만들기</p>
</li>
<li><p>도커파일 명령어</p>
</li>
</ul>
<pre><code>| FROM | 기본 이미지 |
| --- | --- |
| RUN | 쉘 명령어 실행 |
| CMD | 컨테이너 기본 실행 명령어(Entrypoint의 인자로 사용) |
| EXPOSE | 오픈되는 포트 정보 |
| ENV | 환경변수 설정 |
| ADD | 파일 또는 디렉토리 추가. URL/ZIP 사용가능 |
| COPY | 파일 또는 디렉토리 추가  |
| ENTRYPOINT | 컨테이너 기본 실행 명령어 |
| VOLUMNE | 외부 마운트 포인트 생성  |
| USER | RUN, CMD, ENTRYPOINT를 실행하는 사용자  |
| WORKDIR | 작업 디렉토리 설정 |
| ARGS | 빌드타임 환경변수 생성 |
| LABEL | key-value 데이터 |
| ONBUILD | 다른 빌드의 베이스로 사용될 떄 사용하는 명령어 |</code></pre> <br>

<h3 id="1-이미지-빌드하기">(1) 이미지 빌드하기</h3>
<pre><code class="language-bash"># docker build -t {이미지명:이미지태그} {빌드 컨텍스트}
docker build -t sample:1</code></pre>
<ul>
<li>현재 디렉토리의 Dockerfile로 빌드<ul>
<li><code>-f</code> &lt;Dockerfile 위치&gt; 옵션을 사용하여 다른 위치의 도커 파일 사용 가능</li>
<li><code>-t</code> 명령어로 도커 이미지 이름을 지정함</li>
<li>{네임스페이스}/{이미지명}:{태그} 형식</li>
</ul>
</li>
</ul>
<ul>
<li>마지막에는 빌드 컨텍스트 위치(경로)를 지정<ul>
<li>현재 디렉터리를 의미하는 곳을 주로 사용 → .</li>
<li>필요한 경우 다른 디렉터리를 지정할 수 있음</li>
</ul>
</li>
</ul>
<ul>
<li>[참고] .dockerignore<ul>
<li><code>.gitignore</code> 과 비슷한 역할</li>
<li>도커 빌드 컨텍스트에서 지정된 패턴의 파일을 무시함</li>
<li><code>.git</code>이나 민감한 정보를 제외하는 용도로 주로 사용</li>
<li><code>.git</code>이나 에셋 디렉터리만 제외시켜도 빌드 속도 개선</li>
<li>이미지 빌드 시에 사용하는 파일은 제외시키면 안 됨</li>
</ul>
</li>
</ul>
<h3 id="2-dockerfile-생성">(2) Dockerfile 생성</h3>
<pre><code class="language-bash">FROM ubuntu:latest # 이미지명을  
RUN apt-get update # 
RUN apt-get install -y git # </code></pre>
<h3 id="3-build-명령어를-이용한-이미지-빌드">(3) build 명령어를 이용한 이미지 빌드</h3>
<pre><code class="language-bash">docker build -t ubuntu:git-dockerfile .
docker images | grep ubuntu</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Docker] docker compose란(+ yaml은? )]]></title>
            <link>https://velog.io/@sophi_e/Docker-docker-compose%EB%9E%80-yaml%EC%9D%80</link>
            <guid>https://velog.io/@sophi_e/Docker-docker-compose%EB%9E%80-yaml%EC%9D%80</guid>
            <pubDate>Tue, 21 Feb 2023 11:58:24 GMT</pubDate>
            <description><![CDATA[<h2 id="1-docker-compose란">1. Docker Compose란?</h2>
<hr>
<ul>
<li>도커 컴포즈는 여러 컨테이너를 실행하고 정의하기위한 툴</li>
<li>어플리케이션 서비스를 구성하기 위한 YAML파일을 사용함</li>
<li>컴포즈는 모든 환경에서 작동한다<ul>
<li>제작</li>
<li>스테이징</li>
<li>개발</li>
<li>검증</li>
<li>CI workflow</li>
</ul>
</li>
</ul>
<ul>
<li>모든 앱의 생명주기를 관리하기위해서 명령어를 가지고 있음<ul>
<li>start, stop, rebuild 서비스<ul>
<li>서비스 = 컨테이너의 애플리케이션</li>
</ul>
</li>
<li>실행하고 있는 서비스의 상태를 봄</li>
<li>실행하고 있는 서비스들의 로그 결과를 스트리밍함<ul>
<li>로그를 이용하여 컨테이너별 로그를 확인하는 명령어를 수행할 필요가 없음</li>
</ul>
</li>
<li>하나의 서비스의 일회성(one-off) 명령어를 실행함<ul>
<li>여러 컨테이너로 묶어서 실행된다 하더라도 경우에 따라서는 단일 컨테이너에 명령을 내려야 하는 경우도 있는데, 이를 가능하게 함</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li>도커 컴포즈의 주요한 특징(장점)<ul>
<li>단일 호스트에서 여러 격리된 환경을 가짐</li>
<li>컨테이너 생성시 볼륨 데이터를 보존함</li>
<li>변화한 컨테이너만 재생성할 수 있음</li>
<li>환경 간에서 구성이 변화하는 것을 지원하고 변수를 지원함</li>
</ul>
</li>
</ul>
<ul>
<li><p>기본적으로 Docker for mac or window를 설치하면 기본적으로 docker compose가 설치됨</p>
</li>
<li><p>Linux의 경우는 docker-compose를 따로 설치해줘야 함</p>
<pre><code class="language-bash">  sudo curl -L &quot;https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)&quot;
  sudo chmod +x /usr/local/bin/docker-compose

  # or
  sudo curl -L &quot;https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)&quot;
  sudo curl -L &quot;https://github.com/docker/compose/releases/download/1.26.0/docker-compose-Linux-x86_64&quot;</code></pre>
</li>
</ul>
<ul>
<li><p>설치 확인하는 방법</p>
<pre><code class="language-python">  docker-compose version</code></pre>
</li>
</ul>
<p><br><br></p>
<h2 id="2-yaml이란">2. Yaml이란?</h2>
<hr>
<ul>
<li>구성 파일 작성에 자주 사용되는 데이터 직렬화 언어<ul>
<li>직렬화란?(or Serialization)<ul>
<li>Data Science의 데이터 스토리지 문맥에서 데이터 구조나 오브젝트 상태를 동일하거나 다른 컴퓨터 환경에 저장하고 나중에 재구성할 수 있는 포맷으로 변환하는 과정</li>
<li><strong>즉, 객체에 저장된 데이터를 스트림(데이터의 흐름)에 쓰기 위해 연속적인 데이터를 변환하는 것</strong><ul>
<li><strong>데이터 스트림이란 로드된 데이터를 의미함</strong></li>
<li>데이터 스트림은 외부(서버)에서 받아 온(로드된 또는 스트리밍 된)  데이터(이미지, 동영상 등의 멀티미디어)를 의미</li>
</ul>
</li>
<li>한 번의 읽기 또는 쓰기 동작으로 전송되는 정보</li>
<li>진짜 데이터가 열을 지어 차례대로 입력되는 것을 의미</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li><p><code>.yml</code> 또는 <code>.yaml</code> 이라는 확장자를 가짐</p>
</li>
<li><p>띄어쓰기를 가지고 데이터를 표현(탭 문자는 허용되지 않음)</p>
</li>
<li><p>YAML은 Yet Another Markup Language 혹은 YAML ain’t markup language(재귀 약어)</p>
<ul>
<li>후자의 경우 YAML은 문서가 아닌 데이터용임을 강조</li>
<li>사람이 읽을 수 있고 이해하기도 쉬어 프로그래밍 언어 중에 인기가 높음</li>
<li>다른 프로그래밍 언어와 함께 사용할 수 있음</li>
</ul>
</li>
</ul>
<p><br><br></p>
<h2 id="3-도커-컴포즈로-이미지-생성-및-실행하기">3. 도커 컴포즈로 이미지 생성 및 실행하기</h2>
<hr>
<ul>
<li>실무에서는 대부분 YAML파일로 작업해서 하는 편임</li>
<li>클라이언트를 기반으로 한땀한땀 명령어를 입력하고 다시 입력하고 이런 반복적인 작업을 표현하는 방식이 깔끔하지 못함 → <strong>Yaml파일 작성하여 docker-compose로 실행함</strong></li>
</ul>
<p>_* 아래 예시는 인프런 강의 예제를 참고함 
_
  **    [ 예시 ] **  </p>
<pre><code>1. Yaml파일 생성
    - Client로 한땀한땀 입력한 코드를 한번에 key value형태로 작성

    ```bash
    version: &#39;2&#39;
    services:
      db: # name 
        image: mariadb:10.9 # docker 명령어 제일 마지막에 썼던 이미지와 태그
        volumes: # -v 옵션으로 주었던 데이터 유실을 방지하기 위한 옵션 
          - ./mysql:/var/lib/mysql
        restart: always # 컨테이너가 만약 죽게되면 도커가 자동으로 띄어주는 역할(항상 재시작) 
        environment: # -e 로 지정했던 환경변수를 지정해줌 
          MYSQL_ROOT_PASSWORD: wordpress
          MYSQL_DATABASE: wordpress
          MYSQL_USER: wordpress
          MYSQL_PASSWORD: wordpress
      wordpress:
        image: wordpress:latest
        volumes:
          - ./wp:/var/www/html
        ports:
          - &quot;8000:80&quot;
        restart: always
        environment:
          WORDPRESS_DB_HOST: db:3306
          WORDPRESS_DB_USER: wordpress
          WORDPRESS_DB_PASSWORD: wordpress
    ```

2. `docker-compose`로 실행
    - 자동으로 docker-compose.yml 파일을 읽어서 실행함</code></pre><hr>
<p>[ 참고 자료 ]</p>
<ul>
<li><p><a href="https://docs.docker.com/compose/">overview - docker compose</a></p>
</li>
<li><p><a href="https://www.redhat.com/ko/topics/automation/what-is-yaml">YAML 개념, 기능, 특징: YAML 파일 및 포맷, 구문 예시, 사용법</a></p>
</li>
<li><p>인프런 강의 &#39;초보를 위한 도커 안내서&#39; </p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Airflow] docker-compose로 에어플로우 설치하기]]></title>
            <link>https://velog.io/@sophi_e/Airflow-docker-compose%EB%A1%9C-%EC%97%90%EC%96%B4%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@sophi_e/Airflow-docker-compose%EB%A1%9C-%EC%97%90%EC%96%B4%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 21 Feb 2023 11:42:09 GMT</pubDate>
            <description><![CDATA[<p>Apache-Airflow를 사용하기 위해서 도커를 이용하여 설치하는 방법을 정리한 내용입니다. </p>
<p>시작하기 앞서, 준비! </p>
<ul>
<li>Docker Commuitiy Edition 설치(최소 4GB memory 이상)</li>
<li>Docker compose v1.29.1 이상 혹은 최신 버전 설치 </li>
</ul>
<br>
<br>

<h2 id="1-docker-composeyaml-파일-다운로드">1. docker-compose.yaml 파일 다운로드</h2>
<hr>
<ul>
<li>Docker compose로 Airflow를 개발하기 위해서는 docker-compose.yaml파일을 설치해야함<ul>
<li>curl이라는 명령어는 프로토콜들을 이용해 URL 로 데이터를 전송하여 서버에 데이터를 보내거나 가져올때 사용하기 위한 명령줄 도구 및 라이브러리임 </li>
</ul>
</li>
</ul>
<pre><code class="language-bash">curl -LfO &#39;https://airflow.apache.org/docs/apache-airflow/2.5.1/docker-compose.yaml&#39;</code></pre>
<ul>
<li>설치가 완료되면 아래와 같이 docker-compose.yaml 파일이 생성됨 
<img src="https://velog.velcdn.com/images/sophi_e/post/3bebfbb6-6659-451b-b363-ad3d8371b249/image.png" alt=""></li>
</ul>
<ul>
<li><p>docker-compose.yaml 내 서비스</p>
<ul>
<li><p>airflow-scheduler : 모든 task와 DAG를 모니터링</p>
</li>
<li><p>airflow-webserver : 에어플로우 웹 서버. <a href="http://localhost:8080">http://localhost:8080</a></p>
</li>
<li><p>airflow-worker : 스케줄러로부터 부여된 테스크들을 실행하기 위한 워커</p>
</li>
<li><p>airflow-init : 서비스 이니셜라이제이션</p>
</li>
<li><p>postgres(DB) : 데이터 베이스</p>
</li>
<li><p>redis : 스케줄러에서 워커로 메시지를 보내는 브로커
<em>* 서비스는 Celery Executor로 실행됨</em></p>
<p>_(참고) JSON형태가 익숙하다면, YAML -&gt; JSON 포맷으로 변환하여 확인하면 좀 더 이해하기 쉬움 (<a href="https://onlineyamltools.com/convert-yaml-to-json">링크</a>) _</p>
</li>
</ul>
</li>
</ul>
<p><br> <br></p>
<h2 id="2-도커-컨테이너-띄우기">2. 도커 컨테이너 띄우기</h2>
<hr>
<ul>
<li><code>docker compose up</code>  코드로 멀티 컨테이너 서비스 띄우기</li>
</ul>
<pre><code>```bash
docker-compose up 
```

- `docker ps` 명령어로 현재 띄어진 서비스별 컨테이너를 확인할 수 있음 
![](https://velog.velcdn.com/images/sophi_e/post/d76d362c-95c9-4c31-8da6-c9bb37f93afb/image.png)</code></pre><ul>
<li><p>컨테이너의 폴더는 마운트됨 → 컴퓨터와 컨테이너간의 일치
(yaml파일 내 volume 항목 안에 각각의 directory를 매치해주면 됨) </p>
<ul>
<li>./dags : Dag file 디렉토리</li>
<li>./logs : task 실행 과 스케줄러의 로그 파일</li>
<li>./plugins : 커스텀 플러그인(<strong><a href="https://airflow.apache.org/docs/apache-airflow/stable/authoring-and-scheduling/plugins.html">링크</a></strong>)</li>
</ul>
</li>
<li><p>Option</p>
<ul>
<li><p>flower앱 컨테이너도 함께 사용하기 (--profile flower 추가)</p>
<ul>
<li><p>환경을 모니터링함</p>
</li>
<li><p><a href="http://localhost:5555">http://localhost:5555</a></p>
<pre><code class="language-bash">docker compose --profile flower up 
혹은 
docker compose up flower</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><br> <br> </p>
<h2 id="3-initializing-environment">3. Initializing Environment</h2>
<hr>
<ul>
<li>에어플로우 개발 전 환경 구성과 유저 권한을 셋팅해야함</li>
</ul>
<h3 id="1-에어플로우-유저-권한-셋팅">(1) 에어플로우 유저 권한 셋팅</h3>
<pre><code class="language-bash">mkdir -p ./dags ./logs ./plugins # mkdir -p 옵션 : 여러 하위 디렉토리를 생성시에 사용한다.
echo -e &quot;AIRFLOW_UID=$(id -u)&quot; &gt; .env

AIRFLOW_UID=50000</code></pre>
<ul>
<li>유저 권한 입력이 안될 시 이런 WARN이 뜸
<img src="https://velog.velcdn.com/images/sophi_e/post/da70e4bb-ccaf-4dbb-82f7-bac1442ec0bc/image.png" alt=""></li>
</ul>
<ul>
<li>(참고) <a href="https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html#docker-compose-env-variables">docker compose 지원 환경변수</a></li>
</ul>
<h3 id="2-에어플로우-db초기화">(2) 에어플로우 DB초기화</h3>
<h3 id=""></h3>
<pre><code class="language-bash">docker-compose up airflow-init</code></pre>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/28a953ee-2689-4270-bac4-7c09709e8749/image.png" alt=""></p>
<h3 id="3-cli-run">(3) CLI RUN</h3>
<ul>
<li>Airflow command를 실행시키기 위해서는 두가지 방법이 있음<ol>
<li>CLI에 <code>docker-compose run airflow-worker airflow info</code> 입력<pre><code class="language-bash">curl -LfO &#39;https://airflow.apache.org/docs/apache-airflow/2.5.1/airflow.sh&#39;
chmod +x airflow.sh</code></pre>
</li>
</ol>
</li>
</ul>
<ol start="2">
<li><p>Mac 또는 Linux의 경우에는 아래 코드 실행 후 sh파일로 실행시킴</p>
<pre><code class="language-bash">curl -LfO &#39;https://airflow.apache.org/docs/apache-airflow/2.5.1/airflow.sh&#39;
chmod +x airflow.sh</code></pre>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/5563b3ef-0e21-4a21-a6f2-6530566bc37f/image.png" alt=""></p>
<p><em>위 코드 실행시 airflow.sh 파일이 생성됨</em>
<img src="https://velog.velcdn.com/images/sophi_e/post/d27a6943-950f-4509-9d8e-5e1dd569c647/image.png" alt=""></p>
<pre><code class="language-bash">./airflow.sh airflow info</code></pre>
<ul>
<li>1, 2번 모두 실행시 아래와 같은 동일한 결과를 얻을 수 있음 
<img src="https://velog.velcdn.com/images/sophi_e/post/591c74f0-cded-4cb2-8b0f-d8c7d1c932b2/image.png" alt=""></li>
</ul>
</li>
</ol>
<h3 id="4-webserver-접속하기">(4) Webserver 접속하기</h3>
<ul>
<li>디폴트로 설정된 <a href="http://localhost:8080/">http://localhost:8080</a> 링크로 접속
<img src="https://velog.velcdn.com/images/sophi_e/post/517b0624-f06c-4b2c-b4bd-91e97e088750/image.png" alt=""></li>
</ul>
<ul>
<li>디폴트 계정과 비밀번호인 airflow로 접속함
  <img src="https://velog.velcdn.com/images/sophi_e/post/ddd894e7-b9a5-48c3-8eac-448b68b9ea89/image.png" alt=""></li>
</ul>
<ul>
<li>풀 목록 검색 요청 curl</li>
</ul>
<pre><code class="language-bash">ENDPOINT_URL=&quot;http://localhost:8080/&quot;
curl -X GET  \
    --user &quot;airflow:airflow&quot; \
    &quot;${ENDPOINT_URL}/api/v1/pools&quot;</code></pre>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/d39d7d50-b930-431c-8c5e-965522b870de/image.png" alt=""></p>
<ul>
<li>잘못된 정보를 입력했을 때 → Unauthorized로 에러 메시지를 보냄
<img src="https://velog.velcdn.com/images/sophi_e/post/52a17210-3eb0-4b1b-8bc3-216589353e6e/image.png" alt=""></li>
</ul>
<p><br><br></p>
<h2 id="4-컨테이너-stop-or-delete-image">4. 컨테이너 stop or delete image</h2>
<hr>
<pre><code class="language-bash">docker compose down --volumes --rmi all</code></pre>
<p><br><br></p>
<h2 id="5-yamldockerfile로-이미지-커스텀하는-방법">5. yaml&amp;Dockerfile로 이미지 커스텀하는 방법</h2>
<hr>
<ul>
<li>확장된 이미지를 사용할 때(새로운 파이썬 패키지 추가, airflow provider 최신 버전 업그레이드 등) 이미지를 커스텀할 수 있음</li>
<li>아래 예시는 에어플로우 개발을 위한 docker-compose.yaml 파일에 airflow-code-editor를 설치하기 위한 과정을 정리함 </li>
</ul>
<ol>
<li><p><code>docker-compose.yaml</code> 파일 내 <code>build : .</code> 명령어를 추가 </p>
<ul>
<li><p>기본적으로 ymal파일 내의 build 명령어는 주석처리가 되어있음 -&gt; 해제 </p>
<p> <img src="https://velog.velcdn.com/images/sophi_e/post/f7b18591-abd7-4f39-851a-f503bd8d3d3d/image.png" alt=""></p>
</li>
</ul>
</li>
</ol>
<pre><code>- 주석을 제거함

    ![](https://velog.velcdn.com/images/sophi_e/post/543c2bd5-ab30-431b-98be-149b3163ed26/image.png)


2. **Dockerfile**을 `docker-compose.yaml` 파일 위치에 추가 
    - airflow-code-editor 패키지를 설치하는 명령어를 `Dockerfile` 내에 기재 ([명령어 참고 문서](https://airflow.apache.org/docs/docker-stack/build.html))

    ```bash
    FROM apache/airflow:2.5.1-python3.8
    RUN pip install airflow-code-editor
    ```

3.  두 파일이 있는 위치에서 `docker-compose build`  명령어를 통해 이미지를 빌드 

   - 기존 에어플로우와 Dockerfile을 이용하여 airflow-code-editior 패키지를 설치하여 이미지를 생성

    ```bash
    docker-compose build
    ```
    ![](https://velog.velcdn.com/images/sophi_e/post/0294d893-4f99-4749-bec8-b90d830c46d2/image.png)

4. 빌드된 도커 이미지를 실행 

```bash
docker-compose up 
```
![](https://velog.velcdn.com/images/sophi_e/post/75fe4b5d-abb0-404c-8743-6f7f7095129c/image.png)


5. 결과 확인 

 - 기본 웹서버에 존재하지 않는 DAGs Code Editor 생성됨</code></pre><p> <img src="https://velog.velcdn.com/images/sophi_e/post/48a5047a-12cb-4bf0-a8b3-b43b617b95d2/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Docker] Docker란? ]]></title>
            <link>https://velog.io/@sophi_e/Docker-Docker%EB%9E%80</link>
            <guid>https://velog.io/@sophi_e/Docker-Docker%EB%9E%80</guid>
            <pubDate>Sun, 29 Jan 2023 12:28:55 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/sophi_e/post/b0073718-9f65-4df2-816f-4f197bcbeb5e/image.png" alt=""></p>
<h2 id="1-등장-배경">1. 등장 배경</h2>
<hr>
<ul>
<li>전가상이든  반가상이든 추가적인 OS를 설치하여 가상화하는 방법은 어쨋든 성능문제가 있었고 이를 개선하기 위해 <strong>프로세스를 격리하는 방식</strong>이 등장함</li>
</ul>
<ul>
<li>즉, 서버를 관리한다는 건 굉장히 까다로운 문제임<ul>
<li>하나의 서버에 여러개의 프로그램을 설치하는것 → 까다로움</li>
<li>사용하는 라이브러리의 버전이 다르거나 동일한 포트를 사용하는 경우, 설치가 굉장히 까다로움 → 차라리 다른 서버에 설치하는게 나았고, 조립 PC가 늘어나고 자원은 낭비됨</li>
</ul>
</li>
</ul>
<ul>
<li>DevOps의 등장으로 개발주기가 짧아지면서 배포는 자주 이루어지고 마이크로서비스 아키텍쳐가 유행하면서 프로그램은 더 잘 쪼개어져 관리는 더 복잡해짐<ul>
<li><strong><em>DevOps란?</em></strong><ul>
<li><strong>DevOps</strong> is a set of practices that combines <a href="https://en.wikipedia.org/wiki/Software_development">software development</a> (<em>Dev</em>) and <a href="https://en.wikipedia.org/wiki/IT_operations">IT operations</a> (<em>Ops</em>).</li>
<li>It aims to shorten the <a href="https://en.wikipedia.org/wiki/Systems_development_life_cycle">systems development life cycle</a> and provide <a href="https://en.wikipedia.org/wiki/Continuous_delivery">continuous delivery</a> with high <a href="https://en.wikipedia.org/wiki/Software_quality">software quality</a>.</li>
<li>DevOps is complementary with <a href="https://en.wikipedia.org/wiki/Agile_software_development">Agile software development</a>; several DevOps aspects came from the Agile methodology.</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><strong><em>→ 따라서, 새로운 툴은 계속 나오고 클라우드 발전으로 설치해야 할 서버가 수백, 수천대에 이르는 상황에서 도커가 등장하고 서버관리 방식은 완전히 바뀌게 됨</em></strong> </p>
<br>
<br>

<h2 id="2-도커란">2. 도커란?</h2>
<hr>
<ul>
<li><p>서버의 컨테이너도 흔히 아는 컨테이너와 비슷하게 다양한 프로그램, 실행환경을 컨테이너로 추상화하고 동일한 인터페이스를 제공하여 프로그램의 배포 및 관리를 단순하게 해줌</p>
</li>
<li><p>백엔드 프로그램, 데이터베이스 서버, 메시지 큐 등 어떤 프로그램도 추상화할 수 있음</p>
</li>
<li><p>서버에서 다양한 프로그램, 실행 환경을 컨테이너로 추상화하고 동일한 인터페이스를 제공하여 프로그램 배포 및 관리를 단순하게 해줌</p>
</li>
<li><p>백엔드 프로그램 데이터베이스 서버, 메시지 큐등 어떤 프로그램도 콘테이너로 추상화될도 있고 조립PC, AWS, Azure, Google cloud등 어디서든 실행할 수 있음</p>
</li>
</ul>
<br>
<br>

<h2 id="3-컨테이너란">3. 컨테이너란?</h2>
<hr>
<ul>
<li>격리된 공간에서 프로세스가 동작하는 기술임</li>
<li>기존 방식<ul>
<li>가상화 방식(주로 OS 가상화)</li>
<li>VMware나 Virtual Box 같은 가상머신은 <strong>호스트 OS위에 게스트 OS 전체를 가상화하여 사용하는 방식</strong><ul>
<li>이 방식은 여러가지 OS를 가상화 할 수 있고 비교적 사용법이 간단하지만, 무겁고 느려서 운영환경에선 사용할 수 없음</li>
</ul>
</li>
</ul>
</li>
<li>개선 방식<ul>
<li>CPU 가상화 기술(HVM)을 이용한 KVM(Kernel-based Virtual Machine)과 반가상화(Paravirtualization) 방식의 Xen이 등장</li>
<li>이런 방식은 게스트 OS가 필요하긴하지만 전체 OS를 가상화하는 방식이 아니였기 때문에 호스트형 가상화 방식에 비해 성능이 향상됨</li>
<li>이러한 기술들은 OpenStack이나 AWS, Rackspace같은 클라우드 서비스에서 가상 컴퓨팅 기술의 기반이 되었음</li>
</ul>
</li>
</ul>
<br>
<br>

<h2 id="4-이미지란">4. 이미지란?</h2>
<hr>
<ul>
<li>컨테이너를 실행하기 위한 모든 정보를 가지고 있음<ul>
<li>의존성 파일을 컴파일하고 이것저것 설치할 필요가 없음</li>
</ul>
</li>
</ul>
<ul>
<li>새로운 서버가 추가되면 미리 만들어 놓은 이미지를 다운받고 컨테이너를 생성하기만 하면 됨</li>
</ul>
<ul>
<li>한 서버에 여러개의 컨테이너를 실행할 수 있고 수십, 수백, 수천대의 서버도 문제없음</li>
</ul>
<ul>
<li>도커 이미지는 Docker Hub나 Docker Registry 저장소를 직접 만들어 관리할 수 있음</li>
</ul>
<p><br> <br></p>
<h2 id="5-도커가-핫한-이유">5. 도커가 핫한 이유?</h2>
<hr>
<blockquote>
<p>이미지 레이어 구조로 저장방식으로 도커가 관리하는 파일 시스템 영역에 이미지를 복사함</p>
</blockquote>
<ul>
<li>도커는 완전히 새로운 기술이 아니며 이미 존재하는 기술을 잘 포장함</li>
</ul>
<ul>
<li>도커의 이미지를 이용하여 <code>docker run</code>을 하면 도커는 도커가 관리하는 파일 시스템 영역에 이미지를 복사함<ul>
<li>복사후, 도커는 이미지의 최상단에 컨테이너 레이어라고 불리는 얇은 레이어를 추가하여 컨테이너를 생성함</li>
<li>그리고 사용자에게 유니온 파일 시스템을 이용하여 마치 이러한 여러개의 파일 시스템(Image Lager)로 구성되어 있는 이미지 스택 구조가 하나의 파일 시스템 처럼 보이도록 하게 함</li>
</ul>
</li>
</ul>
<ul>
<li>사용자가 컨테이너 안에서 읽고 쓰는 모든 작업들은 이 컨테이너 레이어에 기록되고 이미지 레이어에는 도지 않음<ul>
<li>Image layer는 변경 불가(Read only layer)</li>
<li>Container layer는 변경 가능(Readable/Writable layer)</li>
</ul>
</li>
</ul>
<ul>
<li>이미지 레이어는 삭제되지 않지만 컨테이너 레이어는 해당 컨테이너가 종료될 경우 같이 소멸됨<ul>
<li>사용자가 컨테이너 레이어에서 작업하던 내용을 이미지 레이어로 적용하고 싶을 경우, <code>docker commit</code> 을 통해 기존 Image layer들과 직접 작성한 컨테이너 레이어를 이용해 새로운 이미지를 생성할 수 있음</li>
</ul>
</li>
</ul>
<p><br> <br></p>
<h2 id="6-특징">6. 특징</h2>
<hr>
<blockquote>
<p>네트워크 성능이 중요한 프로그램의 경우 <strong>—net=host</strong> 옵션을 고려해야 함
참고로, 도커의 기본 네트워크 모드는 <strong>Bridge</strong> 모드로 약간의 성능 손실이 있음</p>
</blockquote>
<ul>
<li><p>하나의 서버에 여러개 컨테이너를 실행하면 <strong>서로 영향을 미치지 않고 독립적으로 실행되어 마치 가벼운 VM(Virtual Machine)을 사용하는 느낌</strong>을 줌</p>
</li>
<li><p>실행중인 컨테이너에 접속하여 명령어를 입력할 수 있고 <code>apt-get</code> 이나 <code>yum</code> 으로 패키지를 설치할 수 있음</p>
</li>
<li><p>사용자 추가하고 여러개의 프로세스를 백그라운드로 실행할 수 있음</p>
</li>
<li><p>CPU나 메모리 사용량을 제한할 수 있고 호스트의 특정 포트와 연결하거나 호스트의 특정 내부 디렉토리인 것처럼 사용할 수 있음</p>
</li>
<li><p>새로운 컨테이너를 만드는데 걸리는 시간은 겨우 1-2초로 가상머신과 비교할 수 없이 빠름</p>
</li>
</ul>
<p><br> <br></p>
<hr>
<h3 id="참고-자료">참고 자료</h3>
<ul>
<li>초보를 위한 도커 안내서 - 도커란 무엇인가? <ul>
<li><a href="https://subicura.com/2017/01/19/docker-guide-for-beginners-1.html">https://subicura.com/2017/01/19/docker-guide-for-beginners-1.html</a></li>
</ul>
</li>
<li>인프런 강의 - 초보를 위한 도커 안내서 <ul>
<li><a href="https://www.inflearn.com/course/%EB%8F%84%EC%BB%A4-%EC%9E%85%EB%AC%B8/dashboard">https://www.inflearn.com/course/%EB%8F%84%EC%BB%A4-%EC%9E%85%EB%AC%B8/dashboard</a></li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] pandas IF-Else 조건문 5가지 방법 ]]></title>
            <link>https://velog.io/@sophi_e/Python-pandas-IF-Else-%EC%A1%B0%EA%B1%B4%EB%AC%B8-5%EA%B0%80%EC%A7%80-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@sophi_e/Python-pandas-IF-Else-%EC%A1%B0%EA%B1%B4%EB%AC%B8-5%EA%B0%80%EC%A7%80-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sat, 21 Jan 2023 09:20:50 GMT</pubDate>
            <description><![CDATA[<p>조건문은 다양한 프로그래밍 언어에서 데이터를 전처리하는 방법 중에서 빠질 수 없는 구문입니다. </p>
<p>Python에서 조건에 따른 값 할당을 어떻게 하는지 크게 5가지 방법으로 나누어 정리하였습니다. </p>
<p>세부적으로 정리하자면, binary or multiple condition에 따라서 사용하는 방식을 나누어 보았습니다.  </p>
<ol>
<li>binary condition<ul>
<li>np.where() function</li>
<li>lambda 형식 </li>
</ul>
</li>
</ol>
<ol start="2">
<li>multiple condition<ul>
<li>np.select()</li>
<li>pd.apply()</li>
<li>df.loc()</li>
</ul>
</li>
</ol>
<br>

<p>** 예제 데이터는 아래와 같습니다.<br><img src="https://velog.velcdn.com/images/sophi_e/post/a82210b9-e929-4b09-88c9-4a4afdb45e99/image.png" alt=""></p>
<br>

<h2 id="1-numpywhere-함수">1. numpy.where() 함수</h2>
<hr>
<ul>
<li><p>‘True’ or ‘False’과 같은 이진 조건의 기반이 되는 새로운 컬럼을 추가할 때 유용한 함수임</p>
</li>
<li><p><code>np.where(condition, value if condition is true, value if condition is false)</code></p>
</li>
<li><p>예시 코드 </p>
<pre><code class="language-python">import pandas as pd
import numpy as np
dfTest[&#39;분기&#39;] = np.where(dfTest[&#39;월&#39;] &lt;= 6, &#39;상반기&#39;, &#39;하반기&#39;)</code></pre>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/be7f5188-5af0-439c-97bc-7f391f3a3c3c/image.png" alt=""></p>
<br>

<h2 id="2-lambda-형식">2. lambda 형식</h2>
<hr>
<ul>
<li>람다 함수 또한 <strong>이진 조건</strong>에 유용한 함수임<ul>
<li>(참고) 람다 표현식 : <a href="https://wikidocs.net/64">https://wikidocs.net/64</a></li>
</ul>
</li>
</ul>
<ul>
<li><code>df[&#39;new column name&#39;] = df[&#39;column name&#39;].apply(lambda x: &#39;value if condition is true&#39; if x condition else &#39;value if condition is false&#39;)</code></li>
</ul>
<ul>
<li>예제 코드 <pre><code class="language-python">  dfTest[&#39;분기&#39;] = dfTest[&#39;월&#39;].apply(lambda x: &#39;상반기&#39; if x &lt;= 6 else &#39;하반기&#39;)</code></pre>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/388c2c26-eff1-4221-b08e-7c91b1f6b2d2/image.png" alt=""></p>
<br>

<h2 id="3-numpyselect-function">3. numpy.select() function</h2>
<hr>
<ul>
<li><p>다양한 조건을 포함하는 카테고리 컬럼을 만들 때</p>
</li>
<li><p>condition 대한 리스트 생성 -&gt; 조건에 해당하는 value 리스트 생성 -&gt; np.select() 함수를 이용하여 적용 </p>
<ol>
<li><p>순서대로 조건을 명시하여 리스트를 생성하기 </p>
<pre><code class="language-python">#Create a python list to specify all the conditions
#Create a python list to specify all the conditions
conditions = [ 
   (dfTest[&#39;월&#39;] == 12) | (dfTest[&#39;월&#39;] &lt;= 2),
   (dfTest[&#39;월&#39;] &gt;= 3) &amp; (dfTest[&#39;월&#39;] &lt;= 5),
   (dfTest[&#39;월&#39;] &gt;= 6) &amp; (dfTest[&#39;월&#39;] &lt;= 8),
   (dfTest[&#39;월&#39;] &gt;= 9) &amp; (dfTest[&#39;월&#39;] &lt;= 11)
   ]
</code></pre>
</li>
<li><p>위 순서의 각 조건에 해당하는 값(’label’)을 할당하여 파이썬 리스트로 생성 </p>
<pre><code class="language-python">#create a python list of values to be assigned to the conditions
values = [&#39;겨울&#39;, &#39;봄&#39;, &#39;여름&#39;, &#39;가을&#39;]</code></pre>
</li>
<li><p>np.select() 함수를 사용하여 새로운 컬럼 생성 </p>
</li>
</ol>
<ul>
<li><p>생성한 두 개의 리스트들을 arguments로 사용하여 np.select를 이용하여 새로운 컬럼으로 생성</p>
<pre><code class="language-python"># use np.select() to create a new column
dfTest[&#39;계절&#39;] = np.select(conditions, values)</code></pre>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/13d805f0-61bb-47ff-b018-10d4ce45a6d1/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>(참고) 1,2,3을 한 번에 적용할 때 

```python
df[&#39;visits_category&#39;] = np.select([
    (df[&#39;visits_30days&#39;] == 0),
    (df[&#39;visits_30days&#39;] &gt; 0) &amp; (df[&#39;visits_30days&#39;] &lt;= 5),
    (df[&#39;visits_30days&#39;] &gt; 5) &amp; (df[&#39;visits_30days&#39;] &lt;= 10),
    (df[&#39;visits_30days&#39;] &gt; 10)
    ], [&#39;0 visits&#39;, &#39;1-5 visits&#39;, &#39;6-10 visits&#39;, &#39;&gt;10 visits&#39;])
```</code></pre><br>

<h2 id="4-pandas-apply-함수">4. pandas apply 함수</h2>
<ul>
<li><p>조건을 특정하는 함수를 생성한 후 → 컬럼에 적용</p>
<ol>
<li><p>함수 생성 </p>
<pre><code class="language-python">def conditions(row):
 if (row[&#39;월&#39;] == 12 ) | (row[&#39;월&#39;] &lt;= 2) :
     val = &#39;겨울&#39;
 elif (row[&#39;월&#39;] &gt;= 3) &amp; (row[&#39;월&#39;] &lt;= 5 ):
     val = &#39;봄&#39;
 elif (row[&#39;월&#39;] &gt;= 6) &amp; (row[&#39;월&#39;] &lt;= 8) :
     val = &#39;여름&#39;   
 elif (row[&#39;월&#39;] &gt;= 9) &amp; (row[&#39;월&#39;] &lt;= 11) :
     val = &#39;가을&#39;   
 else:
     val = &#39;NA&#39;
 return val</code></pre>
</li>
<li><p>컬럼에 함수 적용</p>
<pre><code class="language-python">
#Apply the function to each data point in the data frame
dfTest[&#39;계절2&#39;]= dfTest.apply(conditions, axis=1)</code></pre>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/220bc82f-a96a-4d5b-a808-e8579b57bbf1/image.png" alt=""></p>
</li>
</ol>
</li>
</ul>
<br>

<h2 id="5-datafame-loc-function-활용">5. DataFame loc function() 활용</h2>
<hr>
<ul>
<li>np.select와 비슷한 원리</li>
<li>데이터프레임의 loc함수를 통해 특정 조건의 row에 새로운 column을 부여하여 값을 할당하는 방식</li>
<li>df.loc[기존 행의 조건 입력, ‘새로운 열’] = ‘label’</li>
</ul>
<pre><code class="language-python">dfTest.loc[(dfTest[&#39;월&#39;] == 12) | (dfTest[&#39;월&#39;] &lt;= 2), &#39;계절3&#39;] = &#39;겨울&#39; 
dfTest.loc[(dfTest[&#39;월&#39;] &gt;= 3) &amp; (dfTest[&#39;월&#39;] &lt;= 5), &#39;계절3&#39;] = &#39;봄&#39; 
dfTest.loc[(dfTest[&#39;월&#39;] &gt;= 6) &amp; (dfTest[&#39;월&#39;] &lt;= 8), &#39;계절3&#39;] = &#39;여름&#39;  
dfTest.loc[(dfTest[&#39;월&#39;] &gt;= 9) &amp; (dfTest[&#39;월&#39;] &lt;= 11) , &#39;계절3&#39;] = &#39;가을&#39;</code></pre>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/3d131ad8-7526-425f-8858-5e0dac9a1594/image.png" alt=""></p>
<hr>
<p>[자료 링크] </p>
<ul>
<li><a href="https://towardsdatascience.com/5-ways-to-apply-if-else-conditional-statements-in-pandas-b9627e5f475b">5 Ways to Apply If-Else Conditional Statements in Pandas</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Airflow] 에어플로우 SIGTERM ERROR 해결 방법 (Error messege : sending the signal signals.sigterm)]]></title>
            <link>https://velog.io/@sophi_e/Airflow-SIGTERM-ERROR-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95-Error-messege-sending-the-signal-signals.sigterm</link>
            <guid>https://velog.io/@sophi_e/Airflow-SIGTERM-ERROR-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95-Error-messege-sending-the-signal-signals.sigterm</guid>
            <pubDate>Fri, 06 Jan 2023 08:20:26 GMT</pubDate>
            <description><![CDATA[<p>  에어플로우 SIGTERM Error로 Dag가 실행 중에 중단되었을때 해결하는 방법을 정리한 내용입니다.<br> 원인은 크게 4가지로 Dag run timeout, OOM, CPU usage, Mini scheduler로 나뉘며 각각에 대한 해결 방법을 정리하였습니다. </p>
<br>
<br>

<h2 id="원인1-dag-run-timeout">원인1. DAG run timeout</h2>
<hr>
<ul>
<li><strong>dagrun_timeout 값이 낮은 원인</strong></li>
<li>타임아웃이 나기 전에 Dag Run이 얼마나 오래 걸리는지에 대한 정의를 보통 함</li>
<li>따라서 타임아웃이 예정된 DagRun에 영향을 받는지  확인해봐야함</li>
<li><strong>해결 방법</strong><ul>
<li><strong>Airflow UI로 Failed DagRun duration 확인</strong>하여
<strong>Dag파일(.py)의 dagrun_timeout을 그 이상의 값으로 설정</strong>
<img src="https://velog.velcdn.com/images/sophi_e/post/8f200384-5a94-4f0a-ba25-efd9480c5a6c/image.png" alt=""><ul>
<li><strong>아래 dagrun_timeout 의 value 수정</strong><br><img src="https://velog.velcdn.com/images/sophi_e/post/2e3fe3d0-1ef2-42ea-9424-72d02186d103/image.png" alt=""></li>
</ul>
</li>
</ul>
</li>
</ul>
<br>
<br>

<h2 id="원인2-running-out-of-memory">원인2. Running out of memory</h2>
<hr>
<ul>
<li><strong>OOM(Out of memory) 현상으로 발생되는 원인</strong>일 수 있음</li>
<li>에어플로우의 개발 환경에서 메모리가 충분하지 않으면 발생할 수 있는 에러로 메모리 사용량을 높이는 요소 조정 </li>
<li><strong>해결 방법</strong><ul>
<li><em><code>max_active_tasks_per_dag</code></em> 의 value 조정</li>
<li><em><code>parallelism</code></em> 의 value 조정</li>
</ul>
</li>
</ul>
<br>
<br>

<h2 id="원인3-metadata-database-draining-the-cpu">원인3. Metadata Database draining the CPU</h2>
<hr>
<ul>
<li><p>메타데이터 데이터베이스의 CPU사용량이 100%인 경우</p>
</li>
<li><p><strong>해결 방법</strong></p>
<ul>
<li><p><em><code>job_heartbeat_sec</code></em> 의 값을 조정해야함</p>
</li>
<li><p>airflow.cfg의 job_heartbeat_sec  수정  (default : 5 seconds)</p>
<pre><code class="language-bash">vim airflow.cfg

# 아래 값 확인 후 변경 
[scheduler]
job_heartbeat_sec = 30 </code></pre>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/902c0a04-560b-4931-ae36-a9f35103652c/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<br>
<br>

<h2 id="원인4-disable-mini-scheduler">원인4. Disable “Mini Scheduler”</h2>
<hr>
<ul>
<li><p>기본적으로 <strong>퍼포먼스를 개선</strong>하기 위해서 task supervisor process가 <strong>&quot;미니 스케줄러&quot;를 수행하여 동일한 DAG의 더 많은 작업을 예약함</strong> </p>
</li>
<li><p>이 설정을 그대로 두면 동일한 DAG의 작업이 더 빨리 실행되지만 경우에 따라 다른 dag에 영향을 미침 </p>
</li>
<li><p><strong>해결방법</strong></p>
<ul>
<li><p>airflow.cfg의 <em><code>schedule_after_task_execution</code></em> 수정 (default : True)</p>
<pre><code class="language-bash">[scheduler]
schedule_after_task_execution = False</code></pre>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/fc9ee7df-349f-457a-b8e8-d6b0dfbc3357/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>참고 자료<ul>
<li><a href="https://towardsdatascience.com/sigterm-signal-fix-airflow-486ab704b126">How To Fix Task received SIGTERM signal In Airflow</a></li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Airflow] 에어플로우란? 기초 개념 및 장단점]]></title>
            <link>https://velog.io/@sophi_e/Airflow-%EA%B8%B0%EC%B4%88-%EA%B0%9C%EB%85%90-%EB%B0%8F-%EC%9E%A5%EB%8B%A8%EC%A0%90</link>
            <guid>https://velog.io/@sophi_e/Airflow-%EA%B8%B0%EC%B4%88-%EA%B0%9C%EB%85%90-%EB%B0%8F-%EC%9E%A5%EB%8B%A8%EC%A0%90</guid>
            <pubDate>Mon, 28 Nov 2022 14:39:14 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/sophi_e/post/2acdc6eb-5362-44e7-bdb4-b8d94cc417fb/image.png" alt=""></p>
<p><em>* 참고 : Apache Airflow 기반의 데이터 파이프라인 도서, Airflow documentation</em></p>
<Br>

<h2 id="1-airflow란">1. Airflow란?</h2>
<hr>
<ul>
<li><p>Apache Airflow는 초기 에어비엔비(Airfbnb) 엔지니어링 팀에서 개발한 워크플로우 오픈 소스 플랫폼
_    ** 워크플로우란? : 의존성으로 연결된 작업(Task)들의 집합_</p>
<pre><code>             (ex) ETL의 경우 Extractaction &gt; Transformation &gt; Loading 의 작업의 흐름 </code></pre></li>
<li><p>프로그래밍 방식으로 워크플로우를 작성, 예약 및 모니터링</p>
</li>
</ul>
<Br>

<h2 id="2-airflow-기본-구성-및-작동-원리">2. Airflow 기본 구성 및 작동 원리</h2>
<hr>
<h3 id="1-airflow-key-concept">(1) Airflow Key Concept</h3>
<h4 id="a--dag-directed-acyclic-graph">a.  DAG (Directed Acyclic Graph)</h4>
<ul>
<li>단어 뜻 그대로 순환하지 않는 그래프, DAG(대그)라고 부름 </li>
<li>반복이나 순환을 허용하지 않음 </li>
<li>순차적으로 작업(task)이 이루어지며, 순환 실행을 방지하기 때문에 <strong>매우 중요함</strong> 
  →  논리적 오류는 교착상태(deadlock)로 이어짐  </li>
</ul>
<p><img src="https://velog.velcdn.com/images/sophi_e/post/5e12d4c6-cd8b-47b7-b77f-053f77f75bc3/image.png" alt=""> </p>
<h4 id="b-operator">b. Operator</h4>
<ul>
<li><p>Operator(Task)를 정의하는데 사용</p>
</li>
<li><p>Operator Type </p>
<ul>
<li><strong>Action Operators</strong><ul>
<li>기능이나 명령을 실행하는 오퍼레이터</li>
<li>실제 연산을 수행, 데이터 추출 및 프로세싱</li>
<li>(참고) 내장 Operators는 BashOperator, PythonOperator, EmailOperator <ul>
<li>이외의 오퍼레이터는 공식 documnet 참고 (<a href="https://airflow.apache.org/docs/">링크</a>) </li>
</ul>
</li>
</ul>
</li>
<li><strong>Transfer Operater</strong><ul>
<li>하나의 시스템을 다른 시스템으로 옮김 (데이터를 Source에서 Destination으로 전송 등 )</li>
<li>예를 들어, Presto에서 MySQL로 데이터를 전송하는데에 사용 </li>
</ul>
</li>
<li><strong>Sensor Operators</strong><ul>
<li>조건이 만족할 때까지 기다렸다가, 조건이 충족되면 다음 Task를 실행시킴<h4 id="c-task--task-instance">c. Task &amp; Task Instance</h4>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Task</strong> : 데이터 파이프라인에 존재하는 Operator를 의미</p>
<ul>
<li>Operator를 실행하면 Task가 됨</li>
</ul>
</li>
<li><p><strong>Task Instance</strong></p>
<ul>
<li><p>데이터 파이프 라인이 Trigger되어 실행될 때 생성된 Task를 Task Instance라고 함</p>
</li>
<li><p>태스크 실행 순서 정의</p>
<ul>
<li><p>오른쪽 시프트 연산자(binary right shift operator), 즉 rshift(&gt;&gt;)를 사용하여 태스크의 의존성 정의함</p>
<pre><code>Task1 &gt;&gt; Task2 &gt;&gt; Task3 
[Task1, Task2] &gt;&gt; Task3 </code></pre></li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Task VS Operator</strong></p>
<ul>
<li>사용자 관점에서는 두 용어를 같은 의미지만 Task 는 작업의 올바른 실행을 보장하기 위한 Manager임</li>
<li><strong>사용자</strong>는 Operator를 사용해서 수행할 작업에 집중하며, <strong>Airflow</strong>는 태스크를 통해 작업을 올바르게 실행함</li>
</ul>
<p>→ 사용자는 각 환경별 작업이 잘 이루어지는지 확인하기 위해서 Operator내 코드를 구성하는데에 집중하고, Airflow는 각 Operator 내의 구성 요소들이 전부 잘 맞아야 작업이 이루어지는 형태의 차이로 보임 </p>
</li>
</ul>
<h3 id="2-airflow-component">(2) Airflow component</h3>
<ul>
<li><p>에어플로우는 웹서버, 스케줄러, metastore, Executor, Worker로 크게 5개의 기본 구성으로 이루어져 있음 </p>
<ul>
<li><strong>웹서버</strong> : 웹 대시보드 UI로 스케줄러에서 분석한 Dag를 시각화하고 DAG 실행과 결과를 확인할 수 있는 인터페이스를 제공함 </li>
<li><strong>스케줄러</strong> : DAG를 분석하고 현재 시점에서 Dag의 스케줄이 지난 경우 airflow worker에 DAG의 태스크를 예약함 </li>
<li><strong>Worker</strong> : 예약된 태스크를 실제로 실행시키는 것</li>
<li><strong>Metastore</strong> : 에어플로우에 있는 Dag, Task등의 메타데이터 관리 </li>
<li><strong>Executor</strong> : 태스크가 어떻게 실행되는지 정의</li>
</ul>
</li>
</ul>
<p>(출처 : Apache Airflow 기반의 데이터 파이프라인)
<img src="https://velog.velcdn.com/images/sophi_e/post/d4540857-e8a7-492e-a50c-4faf8205e247/image.png" alt=""></p>
<h3 id="3-airflow-기본-동작-원리">(3) Airflow 기본 동작 원리</h3>
<ol>
<li>유저가 새로운 Dag를 작성 → Dags Foolder 안에 py 파일 배치 </li>
<li>Web Server와 Scheuler가 파싱하여 읽어옴</li>
<li>Scheduler가 Metastore를 통해 DagRun 오브젝터를 생성함 <ol>
<li>DagRun은 사용자가 작성한 Dag의 인스턴스임
<code>DagRun Status : Running</code></li>
</ol>
</li>
<li>스케줄러는 Task Instance Object를 스케줄링함 <ol>
<li>Dag Run object의 인스턴스임 </li>
</ol>
</li>
<li>트리거가 상황이 맞으면 Scheduler가 Task Instance를 Executor로 보냄 </li>
<li>Exeutor는 Task Instance를 실행시킴 </li>
<li>완료 후 → MetaStore에 완료했다고 보고함 <ol>
<li>완료된 Task Instance는 Dag Run에 업데이트됨 </li>
<li>Scheduler는 Dag 실행이 완료되었는지 Metastore를 통해 확인 후에 Dag Run의 생태를 완료로 바꿈
<code>DagRun Status : Completed</code></li>
</ol>
</li>
<li>Metastore가 Webserver에 업데이트해서 사용자도 확인
<img src="https://velog.velcdn.com/images/sophi_e/post/552adc73-42d0-4dda-93ac-ccec89753891/image.png" alt=""></li>
</ol>
<br>

<h2 id="3-airflow-장단점">3. Airflow 장단점</h2>
<hr>
<h3 id="1-장점">(1) 장점</h3>
<ul>
<li>파이썬 코드를 이용하여 파이프라인을 구현하므로 파이썬 언어에서 구현할 수 있는 대부분의 방법을 사용하여 복잡한 커스텀 파이프라인을 만들 수 있음 <ul>
<li>확장성 -  파이썬 기반으로 쉽게 확장 가능하고 다양한 시스템과 통합이 가능<ul>
<li>다양한 유형의 DB, Cloud Service 등 통합 가능</li>
</ul>
</li>
</ul>
</li>
<li>데이터 인프라 관리, 데이터 웨어하우스 구축, 머신러닝/분석/실험에 데이터 환경 구성에 유용함</li>
<li>에어플로우의 스케줄링 기능으로 DAG에 정의된 특정 시점에 트리거할 수 있을 뿐만 아니라 최종 시점과 예상되는 다음 스케줄 주기를 상세하게 알려줌 </li>
<li>백필 기능을 사용하면 과거 데이터를 손쉽게 재처리할 수 있기에 코드를 변경후 재생성이 필요한 데이터 재처리가 가능함 </li>
</ul>
<h3 id="2-단점">(2) 단점</h3>
<ul>
<li>파이썬 경험이 없는 경우 DAG 구성의 어려움이 있을 수 있음</li>
<li>초기 설치는 간단해 보일지라도 작은 환경 변화에도 작동에 오류가 나는 경우가 있어 롤백하는 경우가 꽤 있음</li>
</ul>
<h3 id="3-주의-사항">(3) 주의 사항</h3>
<ul>
<li><strong>Data Streaming Solution</strong> 적용하기엔 적합하지 않음 <ul>
<li>초단위의(그 이하) 데이터 처리가 필요한 경우에 사용하기에는 부적절함</li>
<li>에어플로우는 반복적이거나 배치 태스크를 실행하는 기능에 초점이 맞춰져 있음</li>
</ul>
</li>
<li><strong>Data Processing Framework (like Flink, Spark, Hadoop, etc ..)</strong>로 사용하는 것은 부적절함 <ul>
<li>데이터 프로세싱 작업에 최적화 되어있지않아서 매우 느림</li>
<li>경우에 따라 메모리 부족으로 작업이 진행되지 않을 수도 있음
→ <code>SparkSubmitOperator</code>와 같은 Operator를 이용하여, 데이터 프로세싱은 Spark와 같은 외부 Framework로 처리</li>
</ul>
</li>
<li>파이프라인 규모가 커지면 파이썬 코드가 굉장히 복잡해질 수 있음 → 초기 사용 시점에 엄격한 관리를 해야함</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>