<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Milky's note</title>
    <link>https://milkyspace.tistory.com/</link>
    <description>https://github.com/busyppp</description>
    <language>ko</language>
    <pubDate>Fri, 10 Apr 2026 02:07:06 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>밀뿌</managingEditor>
    <image>
      <title>Milky's note</title>
      <url>https://tistory1.daumcdn.net/tistory/5053793/attach/f38f38bdc5db4f8290edb36e1f52f9c4</url>
      <link>https://milkyspace.tistory.com</link>
    </image>
    <item>
      <title>[LinkedIn Ads] Advertising API로 캠페인 그룹 호출하기 (version 수정)</title>
      <link>https://milkyspace.tistory.com/135</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;LinkedIn Ads의 Advertising API를 호출하던 중&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;header 필수 값인 version 때문에 오류가 자주 발생하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;맨 처음 코드는 version을 호출하는 시점에서 한 달을 빼주고 지난 달로 호출을 해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;하지만 LinkedIn Ads의 API 버전이 규칙적으로 반영되지는 않아서&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;어느 달에는 두 달전 혹은 세 달전 버전으로 호출하거나 해야하는 일이 빈번했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;&lt;b&gt;&amp;middot; 기존 코드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739965390596&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# version format :  '202502'

version = (datetime.now() - relativedelta(months=1)).strftime('%Y%m')

headers = {
    &quot;Authorization&quot;: access_token, 
    &quot;LinkedIn-Version&quot;: version,
    &quot;X-Restli-Protocol-Version&quot;: '2.0.0',
    &quot;Accept-Encoding&quot; : 'gzip, deflate, br'
}

campaigngroup_params = {
    'q': 'search', 
    'search': '(status:(values:List(ACTIVE)))'
}

campaigngroup_params = urllib.parse.urlencode(campaigngroup_params, safe='#\':()+=%,')

r = requests.get(url = campaigngroup_url, headers = headers, params= campaigngroup_params )

if r.status_code == 200:
    content = r.text
    content_json = json.loads(content)

    cg_df = pd.DataFrame(content_json['elements'])

else:
    raise requests.HTTPError(f&quot;something went wrong:  {r.status_code}, {r.text}&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위의 방식으로 호출하면 아래처럼 존재하지 않는 버전이라는 오류 메세지와 함께&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;426 status code가 떨어진다.&lt;/p&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;HTTPError: something went wrong:  426, {&quot;status&quot;:426,&quot;code&quot;:&quot;NONEXISTENT_VERSION&quot;,&quot;message&quot;:&quot;Requested version 20250401 is not active&quot;}&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;size18&quot;&gt;그래서!!! while을 사용해서 status code가 200으로 정상호출이 될 때까지 수정해주는 로직을 추가하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;우선 426 코드를 예외처리 해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt; &lt;b&gt;&amp;middot; 1차 수정 코드&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739966137045&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mm = 0
max_attempts = 12  # 최대 시도 횟수 

while mm &amp;lt; max_attempts:
    version = (datetime.now() - relativedelta(months=mm)).strftime('%Y%m')

    headers = {
        &quot;Authorization&quot;: access_token, 
        &quot;LinkedIn-Version&quot;: version,
        &quot;X-Restli-Protocol-Version&quot;: '2.0.0',
        &quot;Accept-Encoding&quot; : 'gzip, deflate, br'
    }

    # active되어 있는 campaigngroup 불러오기
    campaigngroup_params = {
        'q': 'search', 
        'search': '(status:(values:List(ACTIVE)))'
    }

    campaigngroup_params = urllib.parse.urlencode(campaigngroup_params, safe='#\':()+=%,')

    r = requests.get(url = campaigngroup_url, headers = headers, params = campaigngroup_params)

    if r.status_code == 200:
        content = r.text
        content_json = json.loads(content)

        cg_df = pd.DataFrame(content_json['elements'])

        return cg_df

    elif r.status_code == 426:
        print(f&quot;something went wrong version: {version}, {r.status_code}, {r.text}&quot;)
        mm += 1 #버전 오류가 발생하면 month를 더 과거로 조회

    else: #그 외는 raise로 오류 발생
        raise requests.HTTPError(f&quot;API Call Failed! Status Code: {r.status_code}, Response: {r.text}&quot;)

raise RuntimeError(&quot;Max retries!!&quot;) #최대 시도 횟수가 넘어가면 raise로 오류 발생&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;size18&quot;&gt;이렇게 수정하였더니 오류가 발생하지 않았다 !&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;challenge&quot; data-emoticon-name=&quot;008&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/challenge/large/008.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/challenge/large/008.png&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;하지만 오늘 .... (이 오류 때문에 짜증나서 바로 블로그 쓰는 중 ㅎ) 버전 오류가 또 발생하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;일단 LinkedIn Ads의 adversiting API의 202502 버전은 현재 존재하지 않는 상태이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그러면 당연히 202501로 버전을 낮춰서 API 호출을 해야하지만 안되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;왜냐면..... status code가 426이 아닌 아래처럼 404로 떨어졌다... ㅜ&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;왜인지는 진짜 모르겠다....&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;python&quot; style=&quot;color: #000000; text-align: left;&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;{&quot;message&quot;:&quot;No root resource defined for path '/partnerApiAdAccountsV20250201'&quot;,&quot;status&quot;:404}&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;size18&quot;&gt;그래서 예외처리 부분에 404 코드도 추가해주었다.. ㅜ&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;만약 버전 때문에 발생하는 404 코드가 아니라 정말 Not Found여도&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;12번 넘게 실패하면 오류를 발생시켜서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;ETL 작업을 Airflow에서 하고 있어서 Dag 중에서 캠페인 그룹 호출하는 task 코드를 첨부하였다.&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;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt; &lt;b&gt;&amp;middot; 최종 코드(Dag)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739967202255&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def campaigngroup_call(**kwargs):

    ti = kwargs['ti']
    # 이전 task에서 xcom에 저장한 access token 호출
    access_token = ti.xcom_pull(key='access_token', task_ids='token_headers')
    
    mm = 0
    max_attempts = 12  # 최대 시도 횟수 

    while mm &amp;lt; max_attempts:
        version = (datetime.now() - relativedelta(months=mm)).strftime('%Y%m')

        headers = {
            &quot;Authorization&quot;: access_token, 
            &quot;LinkedIn-Version&quot;: version,
            &quot;X-Restli-Protocol-Version&quot;: '2.0.0',
            &quot;Accept-Encoding&quot; : 'gzip, deflate, br',
        }

        # active되어 있는 campaigngroup 불러오기
        campaigngroup_params = {
            'q': 'search', 
            'search': '(status:(values:List(ACTIVE)))'
        }

        campaigngroup_params = urllib.parse.urlencode(campaigngroup_params, safe='#\':()+=%,')

        r = requests.get(url = campaigngroup_url, headers = headers, params = campaigngroup_params)

        if r.status_code == 200:
            content = r.text
            content_json = json.loads(content)

            cg_df = pd.DataFrame(content_json['elements'])

        # 뒤의 task에서도 사용해야 되어서 Xcom으로 push
            ti.xcom_push(key='cg_df', value=cg_df.to_json())
            ti.xcom_push(key='headers', value=headers)

        # token이나 version의 경우 airflow 내 variable에 저장하여 사용
            Variable.set('access_token', access_token)
            Variable.set('version', version)

            return

        elif (r.status_code == 426) | (r.status_code == 404):
            print(f&quot;something went wrong version: {version}, {r.status_code}, {r.text}&quot;)
            mm += 1
            
        else:
            raise requests.HTTPError(f&quot;API Call Failed! Status Code: {r.status_code}, Response: {r.text}&quot;)

    raise RuntimeError(&quot;Max retries!!&quot;)
    

campaigngroup_call_task = PythonOperator(
    task_id='campaigngroup_call',
    python_callable=campaigngroup_call,
)&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;※ 함수의 첫 줄에서 사용되는 변수 ti는 Task Instance의 약자이다.&lt;br /&gt;당연히 다른 변수를 사용해도 되긴 하지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Airflow에서 XCom (Cross Communication)을 사용해 task 간 데이터를 주고받을 때 &lt;b&gt;보통 ti 변수를 활용&lt;/b&gt;한다!!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;challenge&quot; data-emoticon-name=&quot;005&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/challenge/large/005.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/challenge/large/005.png&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>Python/API Connect</category>
      <category>airflow ti</category>
      <category>airflow xcom</category>
      <category>linkedin ads api</category>
      <category>linkedin ads api airflow</category>
      <category>linkedin api version</category>
      <category>링크드인 광고 api 버전</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/135</guid>
      <comments>https://milkyspace.tistory.com/135#entry135comment</comments>
      <pubDate>Wed, 19 Feb 2025 21:19:20 +0900</pubDate>
    </item>
    <item>
      <title>[Google Ads] API 버전 업그레이드</title>
      <link>https://milkyspace.tistory.com/134</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;프로젝트에서 Google Ads API를 호출하여 데이터를 전처리하는 부분이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;OAuth로 인증받고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1674&quot; data-origin-height=&quot;1129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Pakw9/btsMd1EPEOX/aBfwl5a7XZl60K70xEBGw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Pakw9/btsMd1EPEOX/aBfwl5a7XZl60K70xEBGw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Pakw9/btsMd1EPEOX/aBfwl5a7XZl60K70xEBGw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPakw9%2FbtsMd1EPEOX%2FaBfwl5a7XZl60K70xEBGw0%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;796&quot; height=&quot;537&quot; data-origin-width=&quot;1674&quot; data-origin-height=&quot;1129&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;niniz&quot; data-emoticon-name=&quot;020&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/020.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/020.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 Airflow에서 2월 5일이 되자마자 오류가 발생하였다.ㅠㅠ&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;v16이 지원이 중단 되었다고 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1739186100407&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;_SingleThreadedRendezvous of RPC that terminated with:
status = StatusCode.INVALID_ARGUMENT
details = &quot;Request contains an invalid argument.&quot;
debug_error_string = &quot;UNKNOWN:Error received from peer ipv4:199.36.153.8:443 {created_time:&quot;2025-02-05T01:30:16.346757668+00:00&quot;, grpc_status:3, grpc_message:&quot;Request contains an invalid argument.&quot;}&quot;
&amp;gt;

errors {
error_code {
request_error: UNSUPPORTED_VERSION
}
message: &quot;Version v16 is deprecated. Requests to this version will be blocked.&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;참고로 위 IP (&lt;span style=&quot;color: #202124; text-align: left;&quot;&gt;199.36.153.8&lt;/span&gt;)는&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: start; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;온프레미스 호스트의 비공개 Google&lt;span&gt;&amp;nbsp;&lt;/span&gt;액세스를&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용하기 위한 특수 도메인이다 !&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&lt;a href=&quot;https://cloud.google.com/vpc/docs/configure-private-google-access-hybrid?hl=ko&quot;&gt;https://cloud.google.com/vpc/docs/configure-private-google-access-hybrid?hl=ko&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;오류가 발생한 호출 코드는 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1739186513579&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;googleads_client = GoogleAdsClient(developer_token=developer_token, credentials=credentials)

gads_service = googleads_client.get_service(&quot;GoogleAdsService&quot;)


adgroup_query = f&quot;&quot;&quot;
    SELECT
    ad_group.id,
    ad_group.name,
    ad_group.campaign,
    segments.ad_network_type,
    metrics.impressions,
    metrics.clicks
    FROM ad_group
    WHERE segments.date BETWEEN '{dashboard}' AND '{dashboard}'
    ORDER BY ad_group.id&quot;&quot;&quot;


adgroups = []
adgroup_stream = gads_service.search_stream(customer_id=customer_id, query=adgroup_query)

for batch in adgroup_stream:
    for row in batch.results:
        adgroup = {
            &quot;campaign_id&quot;: row.ad_group.campaign,
            &quot;adgroup_id&quot;: row.ad_group.id,
            &quot;adgroup_name&quot;: row.ad_group.name,
            &quot;network&quot;: row.segments.ad_network_type,
            &quot;impressions&quot;: row.metrics.impressions,
            &quot;clicks&quot;: row.metrics.clicks
        }
        adgroups.append(adgroup)

adgroup_df = pd.DataFrame(adgroups)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;혹시나 v16까지 지원되는 dimension이나 metrics이 있는지 docs부터 확인하였지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;v18에도 모두 지원되는 값들이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;계속 감을 못 잡고 있었는데 google ads api의 버전 업그레이드는 아래처럼&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;호출해주는 부분에 버전만 기재해주면 된다 !!!!&lt;/p&gt;
&lt;pre id=&quot;code_1739186671402&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;googleads_client = GoogleAdsClient(developer_token=developer_token, credentials=credentials)

gads_service = googleads_client.get_service(&quot;GoogleAdsService&quot;, version=&quot;v18&quot;)&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;size18&quot;&gt;생각보다 ,,, 넘 간단,,,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;찾아보니까 google ads api의 수명은 12개월 정도이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그래서 업데이트가 다른 api 수명에 비해 잦은 편이고 그에 맞춰서 노티가 오면 버전을 수정해주면 된다 !&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1332&quot; data-origin-height=&quot;1129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pSx8U/btsMb1MZSzp/jDHEfyyAzIKcWdr5xvsFhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pSx8U/btsMb1MZSzp/jDHEfyyAzIKcWdr5xvsFhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pSx8U/btsMb1MZSzp/jDHEfyyAzIKcWdr5xvsFhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpSx8U%2FbtsMb1MZSzp%2FjDHEfyyAzIKcWdr5xvsFhk%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;1332&quot; height=&quot;1129&quot; data-origin-width=&quot;1332&quot; data-origin-height=&quot;1129&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;물론 버전을 업그레이드 해도 오류가 발생한다면,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;더이상 지원하지 않는 파라미터들이니 docs를 참고해서 대체하는 값으로 바꿔주면 된다 !!!!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developers.google.com/google-ads/api/docs/upgrade&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developers.google.com/google-ads/api/docs/upgrade&lt;/a&gt;&lt;/p&gt;</description>
      <category>Python/API Connect</category>
      <category>google ads api</category>
      <category>google ads api 버전</category>
      <category>google ads api 업그레이드</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/134</guid>
      <comments>https://milkyspace.tistory.com/134#entry134comment</comments>
      <pubDate>Mon, 10 Feb 2025 20:30:02 +0900</pubDate>
    </item>
    <item>
      <title>[GCP] Google Cloud SDK로 SSH 터널링 (로컬 cmd에서 서버 접속)</title>
      <link>https://milkyspace.tistory.com/133</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;내가 현재 진행하고 있는 프로젝트는 GCP 기반으로 폐쇄망을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;추가로 Public IP도 사용하지 않고 GCP 내부 IP만 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;초반에 Airflow를 Public IP로 구성을 해놓았는데 내부 IP만 허용이 되는 정책으로 변경이 되었다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;어쩔 수 없이 Airflow 서버를 내부 IP만 사용되게 하였는데 당연하게도 Airflow UI 접속이 불가능해졌다 !&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그래서 내가 생각한 방법은 로컬에서 서버로 접속하기 !&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;내부 IP만 사용하지만 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;SSH 터널링을 사용하면 서버로 접속이 가능&lt;/b&gt;&lt;/span&gt;하다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 로컬에 SSH 연결&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;외부 IP 없이 Airflow UI에 접속하기 위해 SSH 터널링을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 방법은 로컬에서 GCP의 VM 인스턴스에 SSH로 연결한 후,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Airflow UI에 접근할 수 있도록 포트를 포워딩하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;먼저 Airflow를 접속하려는 로컬에 Google CLI를 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;[링크 참고]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://cloud.google.com/sdk/docs/install?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cloud.google.com/sdk/docs/install?hl=ko&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1734517701575&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;gcloud CLI 설치 &amp;nbsp;|&amp;nbsp; Google Cloud CLI Documentation&quot; data-og-description=&quot;이 페이지는 Cloud Translation API를 통해 번역되었습니다. 의견 보내기 gcloud CLI 설치 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에는 Google Cloud CLI &quot; data-og-host=&quot;cloud.google.com&quot; data-og-source-url=&quot;https://cloud.google.com/sdk/docs/install?hl=ko&quot; data-og-url=&quot;https://cloud.google.com/sdk/docs/install?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bsO2BK/hyXOgwCTEr/k0Ew4kkk2Vw1pmeFgD0aRk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://cloud.google.com/sdk/docs/install?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cloud.google.com/sdk/docs/install?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bsO2BK/hyXOgwCTEr/k0Ew4kkk2Vw1pmeFgD0aRk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;gcloud CLI 설치 &amp;nbsp;|&amp;nbsp; Google Cloud CLI Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이 페이지는 Cloud Translation API를 통해 번역되었습니다. 의견 보내기 gcloud CLI 설치 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에는 Google Cloud CLI&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cloud.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;1388&quot; data-origin-height=&quot;651&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uVzSG/btsLnJk7PGi/GzONKCR9m4r5J246Hg99R0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uVzSG/btsLnJk7PGi/GzONKCR9m4r5J246Hg99R0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uVzSG/btsLnJk7PGi/GzONKCR9m4r5J246Hg99R0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuVzSG%2FbtsLnJk7PGi%2FGzONKCR9m4r5J246Hg99R0%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;1388&quot; height=&quot;651&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;651&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;설치 방법은 아주 간단하며 몇 번의 인증이면 완료가 된다 !&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 설치한 Shell을 실행 !&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;428&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FYpeb/btsLoKQR15L/fC3C4GDOTEDnKoxGISjqRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FYpeb/btsLoKQR15L/fC3C4GDOTEDnKoxGISjqRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FYpeb/btsLoKQR15L/fC3C4GDOTEDnKoxGISjqRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFYpeb%2FbtsLoKQR15L%2FfC3C4GDOTEDnKoxGISjqRk%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;428&quot; height=&quot;196&quot; data-origin-width=&quot;428&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;먼저 아래 명령어를 입력해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1734517876766&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;1. 현재 프로젝트 설정현재 사용하고자 하는 프로젝트를 설정
&amp;gt;&amp;gt; gcloud config set project &amp;lt;PROJECT_NAME&amp;gt;

2. 프로젝트 확인설정한 프로젝트가 올바른지 확인
&amp;gt;&amp;gt; gcloud config get-value project&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;1138&quot; data-origin-height=&quot;146&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P3LzI/btsLmQ54Mf6/telXttyOdKXUnqVwz64xjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P3LzI/btsLmQ54Mf6/telXttyOdKXUnqVwz64xjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P3LzI/btsLmQ54Mf6/telXttyOdKXUnqVwz64xjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP3LzI%2FbtsLmQ54Mf6%2FtelXttyOdKXUnqVwz64xjK%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;1138&quot; height=&quot;146&quot; data-origin-width=&quot;1138&quot; data-origin-height=&quot;146&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;내가 터널링하려는 프로젝트를 설정해주었고, 확인까지 마쳤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음 명령어를 입력해서 GCP 인스턴스에 연결이 되나 확인한다.&lt;/p&gt;
&lt;pre id=&quot;code_1734517957655&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;명령어를 입력하여 GCP 인스턴스에 연결되나 확인
&amp;gt;&amp;gt; gcloud compute ssh &amp;lt;INSTANCE_NAME&amp;gt; --zone=asia-northeast3-a&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;1513&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EY81t/btsLn5Vt1qp/g4U8P3vQ5nSUEySYrAyRZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EY81t/btsLn5Vt1qp/g4U8P3vQ5nSUEySYrAyRZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EY81t/btsLn5Vt1qp/g4U8P3vQ5nSUEySYrAyRZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEY81t%2FbtsLn5Vt1qp%2Fg4U8P3vQ5nSUEySYrAyRZK%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;1513&quot; height=&quot;264&quot; data-origin-width=&quot;1513&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 명령어를 입력하고 조금 기다리면 새로운 터미널 (나의 경우 putty)가 열리면서 서버 로그인에 성공한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blbzG2/btsLmmj5qSA/v3SvkK6SDW4kIy5GXkHBH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blbzG2/btsLmmj5qSA/v3SvkK6SDW4kIy5GXkHBH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blbzG2/btsLmmj5qSA/v3SvkK6SDW4kIy5GXkHBH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblbzG2%2FbtsLmmj5qSA%2Fv3SvkK6SDW4kIy5GXkHBH0%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;1040&quot; height=&quot;667&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;667&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;연결이 성공하면 로컬 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;머신의&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 터미널에서 GCP 인스턴스의 셀에 접근할 수 있게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이후 SSH 터널링을 설정하여 내부 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IP를&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 통해 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Airflow&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;UI에&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 접근할 수 있다.&lt;/span&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;b&gt;※ 주의해야할 점은 --sh-flag에서 앞에는 로컬에서 들어갈 PORT이고,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;뒤에는 인스턴스에서 실행되고 있는 서비스의 PORT이다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1734518191022&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;gcloud compute ssh &amp;lt;INSTANCE_NAME&amp;gt; --project &amp;lt;PROJECT_NAME&amp;gt; 
--zone asia-northeast3-a --ssh-flag=&quot;-L&quot; --ssh-flag=&quot;&amp;lt;로컬 PORT&amp;gt;:localhost:&amp;lt;인스턴스 PORT&amp;gt;&quot;&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;1614&quot; data-origin-height=&quot;130&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lq3rf/btsLnO0McFD/dTSAkD4qhghfZQeYYToNi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lq3rf/btsLnO0McFD/dTSAkD4qhghfZQeYYToNi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lq3rf/btsLnO0McFD/dTSAkD4qhghfZQeYYToNi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flq3rf%2FbtsLnO0McFD%2FdTSAkD4qhghfZQeYYToNi1%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;1614&quot; height=&quot;130&quot; data-origin-width=&quot;1614&quot; data-origin-height=&quot;130&quot;/&gt;&lt;/span&gt;&lt;/figure&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;외부 IP가 없어서 디폴트로 IAP 터널링을 사용한다는 문구가 뜨고 다시 새로운 터미널이 뜨고 서버에 접속이 완료된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이후에 로컬 브라우저에서 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;127.0.0.1&lt;/span&gt;&lt;/b&gt;과 위에서 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;포워딩해준 port&lt;/span&gt;&lt;/b&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;2004&quot; data-origin-height=&quot;665&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ekAR0T/btsLm5oC8P7/IBXKc0HryBCd5t6HfrUXTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ekAR0T/btsLm5oC8P7/IBXKc0HryBCd5t6HfrUXTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ekAR0T/btsLm5oC8P7/IBXKc0HryBCd5t6HfrUXTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FekAR0T%2FbtsLm5oC8P7%2FIBXKc0HryBCd5t6HfrUXTK%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;2004&quot; height=&quot;665&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;665&quot;/&gt;&lt;/span&gt;&lt;/figure&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;스크린 샷은 Airflow 서버가 아니지만 다른 모든 인스턴스에서도 다 터널링이 가능하다는 것을 보여주기 위해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첨부하였다 !&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;challenge&quot; data-emoticon-name=&quot;010&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/challenge/large/010.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/challenge/large/010.png&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>DevOps/GCP</category>
      <category>gcp 로컬 접속</category>
      <category>gcp 터널링</category>
      <category>google cli</category>
      <category>ssh 터널링</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/133</guid>
      <comments>https://milkyspace.tistory.com/133#entry133comment</comments>
      <pubDate>Wed, 18 Dec 2024 19:43:03 +0900</pubDate>
    </item>
    <item>
      <title>[pandas] Grand Total 구하기</title>
      <link>https://milkyspace.tistory.com/132</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;각 컬럼의 grand total (총 합계)를 구하고 싶을 때에는 아래와 같은 sum 함수에&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;numeric_only 파라미터를 True로 작성해주면 된다 !!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;386&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bS1JDb/btsLdhBB1pZ/Z6ivfQrlRkV6cSH3QopvqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bS1JDb/btsLdhBB1pZ/Z6ivfQrlRkV6cSH3QopvqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bS1JDb/btsLdhBB1pZ/Z6ivfQrlRkV6cSH3QopvqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbS1JDb%2FbtsLdhBB1pZ%2FZ6ivfQrlRkV6cSH3QopvqK%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;386&quot; height=&quot;339&quot; data-origin-width=&quot;386&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;/figure&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;pre id=&quot;code_1733745205647&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df.loc['Grand_Total']= df.sum(numeric_only=True, axis=0) #열 기준
df.loc[:,'Row_Total'] = df.sum(numeric_only=True, axis=1) #행 기준&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;546&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bam9sL/btsLdbIhqbX/Mjlt3zeHILc0yE29Foy5OK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bam9sL/btsLdbIhqbX/Mjlt3zeHILc0yE29Foy5OK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bam9sL/btsLdbIhqbX/Mjlt3zeHILc0yE29Foy5OK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbam9sL%2FbtsLdbIhqbX%2FMjlt3zeHILc0yE29Foy5OK%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;546&quot; height=&quot;358&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python/요약 정리</category>
      <category>numeric_only</category>
      <category>pandas grand total</category>
      <category>판다스 총합</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/132</guid>
      <comments>https://milkyspace.tistory.com/132#entry132comment</comments>
      <pubDate>Mon, 9 Dec 2024 20:55:03 +0900</pubDate>
    </item>
    <item>
      <title>[Airflow] Gmail로 alert 메일 보내기(Email Operator 설정)</title>
      <link>https://milkyspace.tistory.com/131</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Airflow Dag들이 실패하면 메일로 alert를 받아볼 수 있게&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Email Operator를 설정해주려고 한다!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;먼저 mail을 보낼 gmail 계정이 있어야 하기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;없다면 먼저 google에 가입을 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. Gmail의 IMAP 활성화&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 구글에 로그인을 해서 IMAP를 켜줘야한다!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[Gmail] -&amp;gt; [설정] -&amp;gt; 모든 설정 보기&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클릭!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;617&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7mJTC/btsKK1UzY4m/eKIXAYD2YEBUfGsXFZQ9Z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7mJTC/btsKK1UzY4m/eKIXAYD2YEBUfGsXFZQ9Z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7mJTC/btsKK1UzY4m/eKIXAYD2YEBUfGsXFZQ9Z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7mJTC%2FbtsKK1UzY4m%2FeKIXAYD2YEBUfGsXFZQ9Z1%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;798&quot; height=&quot;246&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;617&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[전달 및 POP/IMAP] -&amp;gt; [IMAP 액세스]&lt;/b&gt;에서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;IMAP 사용을 체크 !!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1608&quot; data-origin-height=&quot;1129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDZ9EO/btsKLp8CQLT/Pu0vPBKXKE7tSJtxjkjWg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDZ9EO/btsKLp8CQLT/Pu0vPBKXKE7tSJtxjkjWg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDZ9EO/btsKLp8CQLT/Pu0vPBKXKE7tSJtxjkjWg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDZ9EO%2FbtsKLp8CQLT%2FPu0vPBKXKE7tSJtxjkjWg0%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;696&quot; height=&quot;489&quot; data-origin-width=&quot;1608&quot; data-origin-height=&quot;1129&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. SMTP 비밀번호 설정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 airflow config 파일에 넣어줄 smtp 비밀번호를 설정해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;smtp 비밀번호를 생성하기 위해선 먼저 2단계 인증이 설정되어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1611&quot; data-origin-height=&quot;984&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br9JfH/btsKKoQhJ7R/JLiNHA0umFiG036aCqmTWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br9JfH/btsKKoQhJ7R/JLiNHA0umFiG036aCqmTWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br9JfH/btsKKoQhJ7R/JLiNHA0umFiG036aCqmTWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr9JfH%2FbtsKKoQhJ7R%2FJLiNHA0umFiG036aCqmTWk%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;629&quot; height=&quot;384&quot; data-origin-width=&quot;1611&quot; data-origin-height=&quot;984&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 앱 비밀번호를 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;929&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs1hvZ/btsKMerWJ6J/vGfV7ALlwMI95J5pdvgBk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs1hvZ/btsKMerWJ6J/vGfV7ALlwMI95J5pdvgBk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs1hvZ/btsKMerWJ6J/vGfV7ALlwMI95J5pdvgBk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs1hvZ%2FbtsKMerWJ6J%2FvGfV7ALlwMI95J5pdvgBk1%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;669&quot; height=&quot;571&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;929&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;앱 이름을 입력해주고 만들기를 클릭하면 다음처럼 16자리 앱 비밀번호가 생성된다!&lt;/p&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;695&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A4JPi/btsKKflCIec/Jy3CFQdiEtdFXo6uyzRS5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A4JPi/btsKKflCIec/Jy3CFQdiEtdFXo6uyzRS5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A4JPi/btsKKflCIec/Jy3CFQdiEtdFXo6uyzRS5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA4JPi%2FbtsKKflCIec%2FJy3CFQdiEtdFXo6uyzRS5k%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;742&quot; height=&quot;574&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;695&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. Airflow config 파일 수정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위에서 생성한 smtp 정보를 airflow의 config 파일에 입력해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;airflow가 설치되어 있는 경로에 가서 아래와 같이 명령어를 입력해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1731676720017&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vi airflow.cfg&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;size18&quot;&gt;config 파일에&amp;nbsp; &lt;b&gt;[smtp]&lt;/b&gt; 라는 항목이 보일 것 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여기에서 아래와 같이 설정해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1731676797897&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;smtp_host = smtp.gmail.com
smtp_starttls = True #default
smtp_ssl = False #default
smtp_user = 생성한 gmail
smtp_password = 발급 받은 16자리 패스워드(띄어쓰기 없이)
smtp_port = 587
smtp_mail_from = 생성한 gmail
smtp_timeout = 30
smtp_retry_limit = 5&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;1572&quot; data-origin-height=&quot;565&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BZDbs/btsKKeG0oJc/EMOXKwgqHQKdXhlzCRJaHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BZDbs/btsKKeG0oJc/EMOXKwgqHQKdXhlzCRJaHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BZDbs/btsKKeG0oJc/EMOXKwgqHQKdXhlzCRJaHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBZDbs%2FbtsKKeG0oJc%2FEMOXKwgqHQKdXhlzCRJaHk%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;1572&quot; height=&quot;565&quot; data-origin-width=&quot;1572&quot; data-origin-height=&quot;565&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;config 파일을 수정해 준 뒤,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;제대로 설정이 되게 airflow &lt;b&gt;서비스를 재기동&lt;/b&gt; 시켜준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1924&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/saSmB/btsKKre9USt/rzKMnXjMXamhJi1zXDkvA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/saSmB/btsKKre9USt/rzKMnXjMXamhJi1zXDkvA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/saSmB/btsKKre9USt/rzKMnXjMXamhJi1zXDkvA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsaSmB%2FbtsKKre9USt%2FrzKMnXjMXamhJi1zXDkvA0%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;1924&quot; height=&quot;286&quot; data-origin-width=&quot;1924&quot; data-origin-height=&quot;286&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 airflow에서 일부러 오류를 내보았다 !!&lt;/p&gt;
&lt;pre id=&quot;code_1731677489512&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import json
import logging
import requests
import pandas as pd
from datetime import datetime
from airflow import DAG
from airflow.operators.python import PythonOperator
from airflow.operators.email_operator import EmailOperator


logging.basicConfig(level=logging.DEBUG)


default_args = {
    'email_on_retry': False,
    'email_on_failure': True,
    'email' : ['sample@email.com']
}

with DAG(
    'email_test',
    default_args=default_args,
    schedule_interval='@once',
    start_date=pendulum.datetime(2024, 6, 1, tz=&quot;UTC&quot;),
    tags=['email'],
    catchup=False
) as dag:

    #환율 구하는 API 호출
    def extract_currency(**kwargs):
	#코드 작성

    extract_task = PythonOperator(
        task_id='extract_currency',
        python_callable=extract_currency,
    )


    extract_task&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;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오류가 발생했다는 alert 메일이 잘 도착했다 !!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1910&quot; data-origin-height=&quot;792&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B8Blm/btsKKre9WwA/euPyTYIoMI70Nck7rQRJU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B8Blm/btsKKre9WwA/euPyTYIoMI70Nck7rQRJU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B8Blm/btsKKre9WwA/euPyTYIoMI70Nck7rQRJU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB8Blm%2FbtsKKre9WwA%2FeuPyTYIoMI70Nck7rQRJU1%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;1910&quot; height=&quot;792&quot; data-origin-width=&quot;1910&quot; data-origin-height=&quot;792&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>DevOps/Airflow</category>
      <category>airflow alert</category>
      <category>airflow email operator</category>
      <category>airflow gmail</category>
      <category>airflow smtp</category>
      <category>airflow.cfg</category>
      <category>gmail imap</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/131</guid>
      <comments>https://milkyspace.tistory.com/131#entry131comment</comments>
      <pubDate>Fri, 15 Nov 2024 22:33:35 +0900</pubDate>
    </item>
    <item>
      <title>[GCP] 랜딩존 설정으로 차단된 Google API 호출 (GA, GSC, Google Ads, Youtube)</title>
      <link>https://milkyspace.tistory.com/130</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;GCP 프로젝트가 랜딩존으로 들어가면서&amp;nbsp;네트워크 구성이 바뀌었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;기존 내가 생성한 VPC에서 조직 범위에서 생성한 VPC가 공유되었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;공유된 VPC를 써서 Google 소유의 API들 호출이 오류가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;GA, GSC, Google Ads, Youtube 등...&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;발생한 오류는 다음과 같았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;google.api_core.exceptions.permissiondenied:&amp;nbsp;403&amp;nbsp;received&amp;nbsp;http2&amp;nbsp;header&amp;nbsp;with&amp;nbsp;status:&amp;nbsp;403&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1468&quot; data-origin-height=&quot;261&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvi2U9/btsKLdNP7iC/R71Rhkb0aJjJs8wZMNv6d1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvi2U9/btsKLdNP7iC/R71Rhkb0aJjJs8wZMNv6d1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvi2U9/btsKLdNP7iC/R71Rhkb0aJjJs8wZMNv6d1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcvi2U9%2FbtsKLdNP7iC%2FR71Rhkb0aJjJs8wZMNv6d1%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;1468&quot; height=&quot;261&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;261&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;랜딩존 설정으로 인하여 API 주소를 찾지 못하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;해결 방법으로는 &lt;span style=&quot;background-color: #f3c000;&quot;&gt;&lt;b&gt;hosts 파일에 API를 직접 하나씩 등록&lt;/b&gt;&lt;/span&gt;해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1731663304470&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo vi/etc/hosts&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;hosts 파일은 root로 수정해야한다 !&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 아래와 같이 사용하는 API들을 넣어준다!&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;686&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mpm2r/btsKKfsdD91/H6MWSkcaK41kl7EJKLakT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mpm2r/btsKKfsdD91/H6MWSkcaK41kl7EJKLakT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mpm2r/btsKKfsdD91/H6MWSkcaK41kl7EJKLakT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmpm2r%2FbtsKKfsdD91%2FH6MWSkcaK41kl7EJKLakT1%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;686&quot; height=&quot;228&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;API 주소 앞에 IP는 GCP docs에서 찾았다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://cloud.google.com/vpc/docs/access-apis-external-ip?hl=ko#config-options&quot;&gt;https://cloud.google.com/vpc/docs/access-apis-external-ip?hl=ko#config-options&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1731663386058&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;외부 IP 주소를 사용하여 VM에서 API에 액세스 &amp;nbsp;|&amp;nbsp; VPC &amp;nbsp;|&amp;nbsp; Google Cloud&quot; data-og-description=&quot;의견 보내기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 외부 IP 주소를 사용하여 VM에서 API에 액세스 네트워크 인터페이스에 할당된 외부 IP 주소가 있는&quot; data-og-host=&quot;cloud.google.com&quot; data-og-source-url=&quot;https://cloud.google.com/vpc/docs/access-apis-external-ip?hl=ko#config-options&quot; data-og-url=&quot;https://cloud.google.com/vpc/docs/access-apis-external-ip?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/csTJUD/hyXzNOzv7q/C9PY8LcImBkvpAB4liiIK1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://cloud.google.com/vpc/docs/access-apis-external-ip?hl=ko#config-options&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cloud.google.com/vpc/docs/access-apis-external-ip?hl=ko#config-options&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/csTJUD/hyXzNOzv7q/C9PY8LcImBkvpAB4liiIK1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;외부 IP 주소를 사용하여 VM에서 API에 액세스 &amp;nbsp;|&amp;nbsp; VPC &amp;nbsp;|&amp;nbsp; Google Cloud&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;의견 보내기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 외부 IP 주소를 사용하여 VM에서 API에 액세스 네트워크 인터페이스에 할당된 외부 IP 주소가 있는&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cloud.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Google에서 제공하는 대부분의 API는 &lt;b&gt;199.36153.8&lt;/b&gt; IP를 쓰면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;173&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ujONy/btsKKq1mZHK/SaZByGeAi4e5lcjdtC3QZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ujONy/btsKKq1mZHK/SaZByGeAi4e5lcjdtC3QZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ujONy/btsKKq1mZHK/SaZByGeAi4e5lcjdtC3QZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FujONy%2FbtsKKq1mZHK%2FSaZByGeAi4e5lcjdtC3QZ1%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;584&quot; height=&quot;173&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;173&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;사용하는 API의 이름을 몰라도 걱정하지 않아도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;GCP 콘솔에서 API 및 서비스에 가서 사용한 API들을 보면 아래와 같이 서비스 이름에 API 주소를 제공한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;607&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4q71S/btsKLZuSxOz/LzWa8272teYknxViOynBSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4q71S/btsKLZuSxOz/LzWa8272teYknxViOynBSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4q71S/btsKLZuSxOz/LzWa8272teYknxViOynBSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4q71S%2FbtsKLZuSxOz%2FLzWa8272teYknxViOynBSK%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;2004&quot; height=&quot;607&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;607&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;587&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lRtTo/btsKLdf9pPH/QS8mFmUgrj9VsLgVXwo9h0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lRtTo/btsKLdf9pPH/QS8mFmUgrj9VsLgVXwo9h0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lRtTo/btsKLdf9pPH/QS8mFmUgrj9VsLgVXwo9h0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlRtTo%2FbtsKLdf9pPH%2FQS8mFmUgrj9VsLgVXwo9h0%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;915&quot; height=&quot;587&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;587&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위 두 개를 확인해서 hosts 파일을 수정하고 다시 호출을 해보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;통신이 아주아주 잘 되는 것을 확인 할 수 있다 !!!!!!!!!!!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;눈물나는 폐쇄망 ..&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;niniz&quot; data-emoticon-name=&quot;003&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/003.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/003.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>DevOps/GCP</category>
      <category>ga api 호출</category>
      <category>gcp 403 error</category>
      <category>gcp 랜딩존</category>
      <category>gcp 외부 api 호출</category>
      <category>google.api_core.exceptions.permissiondenied</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/130</guid>
      <comments>https://milkyspace.tistory.com/130#entry130comment</comments>
      <pubDate>Fri, 15 Nov 2024 18:44:59 +0900</pubDate>
    </item>
    <item>
      <title>[Airflow] GCP 내부 IP로 Airflow UI 접속하기</title>
      <link>https://milkyspace.tistory.com/129</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;GCP 프로젝트에서 고정 IP를 생성하여 인스턴스에 할당을 해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그래서 외부 IP로 Airflow UI에 접속하여 ETL 운영 작업을 했었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;갑자기 보안 정책으로 인하여,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;고정 IP를 제거하라는 요청이 들어왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;SSH 터널링을 이용해서 외부 IP 없이 내부 IP로 Airflow UI에 접속할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로컬 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;머신에서&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;GCP의&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; VM 인스턴스에 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;SSH로&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 연결한 후,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Airflow&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;UI에&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 접근할 수 있도록 포트를 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;포워딩&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;0. 사전 작업 (gcloud 설치)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;gcloud sdk를 이용하여 로컬 기기에 ssh 연결을 해주어야 하기 때문에 gcloud cli를 입력할 수 있는 gcloud를&amp;nbsp; 설치해야한다. 다음 링크를 들어가서 설치를 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cloud.google.com/sdk/docs/install?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cloud.google.com/sdk/docs/install?hl=ko&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730799740613&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;gcloud CLI 설치 &amp;nbsp;|&amp;nbsp; Google Cloud CLI Documentation&quot; data-og-description=&quot;의견 보내기 gcloud CLI 설치 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에는 Google Cloud CLI 설치를 선택하고 유지하기 위한 안내가 포함되어 있습&quot; data-og-host=&quot;cloud.google.com&quot; data-og-source-url=&quot;https://cloud.google.com/sdk/docs/install?hl=ko&quot; data-og-url=&quot;https://cloud.google.com/sdk/docs/install?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dqArUC/hyXsQ6CUiX/vDap19PkkzCxv1Gt4YO8W0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://cloud.google.com/sdk/docs/install?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cloud.google.com/sdk/docs/install?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dqArUC/hyXsQ6CUiX/vDap19PkkzCxv1Gt4YO8W0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;gcloud CLI 설치 &amp;nbsp;|&amp;nbsp; Google Cloud CLI Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;의견 보내기 gcloud CLI 설치 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에는 Google Cloud CLI 설치를 선택하고 유지하기 위한 안내가 포함되어 있습&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cloud.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;798&quot; data-origin-height=&quot;626&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RVii5/btsKyWEsJvi/evRKOcjkPcukp0B6fLiFSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RVii5/btsKyWEsJvi/evRKOcjkPcukp0B6fLiFSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RVii5/btsKyWEsJvi/evRKOcjkPcukp0B6fLiFSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRVii5%2FbtsKyWEsJvi%2FevRKOcjkPcukp0B6fLiFSK%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;583&quot; height=&quot;457&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;626&quot;/&gt;&lt;/span&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;1388&quot; data-origin-height=&quot;651&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nViJL/btsKwzYwTXJ/MtK45YIfwa2Nw1DKd29cU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nViJL/btsKwzYwTXJ/MtK45YIfwa2Nw1DKd29cU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nViJL/btsKwzYwTXJ/MtK45YIfwa2Nw1DKd29cU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnViJL%2FbtsKwzYwTXJ%2FMtK45YIfwa2Nw1DKd29cU1%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;766&quot; height=&quot;359&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;651&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;설치 방법은 간단하고 설치가 완료되면 GCP 계정과 인증을 한 번 해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;인증을 완료하면 위와 같은&amp;nbsp; 화면이 출력된다 !&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;1. 로컬에 SSH 연결&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위에서 설치한 Google Cloud SDK Shell을 실행하여 다음과 같은 명령어를 실행시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;1. 현재 프로젝트 설정&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730800115389&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;gcloud config set project &amp;lt;PROJECT_ID&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;2. 프로젝트 확인 (설정한 프로젝트가 올바른지 확인)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730800131060&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;gcloud config get-value project&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;1114&quot; data-origin-height=&quot;139&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1wS7r/btsKwxsTpma/FPlKivBpzGH3QysX2GICZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1wS7r/btsKwxsTpma/FPlKivBpzGH3QysX2GICZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1wS7r/btsKwxsTpma/FPlKivBpzGH3QysX2GICZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1wS7r%2FbtsKwxsTpma%2FFPlKivBpzGH3QysX2GICZK%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;1114&quot; height=&quot;139&quot; data-origin-width=&quot;1114&quot; data-origin-height=&quot;139&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;3. GCP 인스턴스 연결 확인&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730800282674&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;gcloud compute ssh &amp;lt;INSTANCE_NAME&amp;gt; --zone=&amp;lt;ZONE&amp;gt;&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;1509&quot; data-origin-height=&quot;259&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1frOn/btsKxUUWhMP/9MoWotSwKFUcnQFNUeAv1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1frOn/btsKxUUWhMP/9MoWotSwKFUcnQFNUeAv1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1frOn/btsKxUUWhMP/9MoWotSwKFUcnQFNUeAv1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1frOn%2FbtsKxUUWhMP%2F9MoWotSwKFUcnQFNUeAv1K%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;1509&quot; height=&quot;259&quot; data-origin-width=&quot;1509&quot; data-origin-height=&quot;259&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위 명령어로 SSH 연결이 성공하면 로컬 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;머신의&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 터미널에서 GCP 인스턴스에 접근할 수 있게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아래와 같이 터미널 창이 자동으로 켜지면서 인스턴스 접근을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NkMLY/btsKw71v0RQ/CIUcIqMQ8169bhIIpEtZb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NkMLY/btsKw71v0RQ/CIUcIqMQ8169bhIIpEtZb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NkMLY/btsKw71v0RQ/CIUcIqMQ8169bhIIpEtZb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNkMLY%2FbtsKw71v0RQ%2FCIUcIqMQ8169bhIIpEtZb0%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;646&quot; height=&quot;414&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;667&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;SSH 연결에 성공했으니 이제 SSH 터널링을 설정 해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;2. 포트 포워딩&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;나의 경우 GCP 인스턴스 내에 있던 airflow web server의 port는 기본 port인 &lt;b&gt;8080&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;포트 포워딩을 해주려면 아래와 같은 명령어를 입력해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt; ※ 윈도우 기준 명령어 (ssh-flag 이용)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730800689150&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;gcloud compute ssh &amp;lt;instance name&amp;gt; \
--project &amp;lt;project id&amp;gt; --zone &amp;lt;region&amp;gt; \
--ssh-flag=&quot;-L&quot; \
--ssh-flag=&amp;ldquo;&amp;lt;target port&amp;gt;:localhost:&amp;lt;instance port&amp;gt;&amp;ldquo;&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;2000&quot; data-origin-height=&quot;71&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zIp9Z/btsKyCsGAGL/P8q5d5oKyLBSlCN6KcDku1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zIp9Z/btsKyCsGAGL/P8q5d5oKyLBSlCN6KcDku1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zIp9Z/btsKyCsGAGL/P8q5d5oKyLBSlCN6KcDku1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzIp9Z%2FbtsKyCsGAGL%2FP8q5d5oKyLBSlCN6KcDku1%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;2000&quot; height=&quot;71&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;71&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;692&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cum48Z/btsKyAIoZ0V/IbHOkKKB4btb5apQJamC9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cum48Z/btsKyAIoZ0V/IbHOkKKB4btb5apQJamC9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cum48Z/btsKyAIoZ0V/IbHOkKKB4btb5apQJamC9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcum48Z%2FbtsKyAIoZ0V%2FIbHOkKKB4btb5apQJamC9k%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;586&quot; height=&quot;372&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 브라우저 창을 열어 localhost와 포워딩 해준 port를 입력해서 접속해준다!!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qul4K/btsKyjUvukq/i58qEFKuiWSZwigYWuRze1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qul4K/btsKyjUvukq/i58qEFKuiWSZwigYWuRze1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qul4K/btsKyjUvukq/i58qEFKuiWSZwigYWuRze1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqul4K%2FbtsKyjUvukq%2Fi58qEFKuiWSZwigYWuRze1%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;2004&quot; height=&quot;287&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;287&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;접속이 잘 되는 것을 확인했다 !!!!!!!!!!!!!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 외부 IP를 지우기 위해 GCP 내의 Compute Engine에 들어가서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;고정 IP를 지울 인스턴스에 대해 [수정]을 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;밑쪽으로 내리면 [네트워크 인터페이스 수정] 항목이 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여기에서 &lt;b&gt;외부 Ipv4 주소&lt;/b&gt;를 &lt;span style=&quot;color: #ee2323;&quot;&gt;없음&lt;/span&gt;으로 변경해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1290&quot; data-origin-height=&quot;881&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djwnXN/btsKw4Ktnrd/qYNILur9YZJIeW56AFbpgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djwnXN/btsKw4Ktnrd/qYNILur9YZJIeW56AFbpgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djwnXN/btsKw4Ktnrd/qYNILur9YZJIeW56AFbpgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjwnXN%2FbtsKw4Ktnrd%2FqYNILur9YZJIeW56AFbpgK%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;668&quot; height=&quot;456&quot; data-origin-width=&quot;1290&quot; data-origin-height=&quot;881&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;외부 IP 변경에는 인스턴스 중단이 필요 없어서 바로 완료를 눌러주면 설정이 바뀐다 !&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다만 ssh 터널링 해준 터미널이 중단 되어서 다시 접속 해주어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1638&quot; data-origin-height=&quot;111&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYPKTA/btsKyBAy7Os/GmYOWnoCV7s2Wcef0kjIK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYPKTA/btsKyBAy7Os/GmYOWnoCV7s2Wcef0kjIK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYPKTA/btsKyBAy7Os/GmYOWnoCV7s2Wcef0kjIK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYPKTA%2FbtsKyBAy7Os%2FGmYOWnoCV7s2Wcef0kjIK0%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;1638&quot; height=&quot;111&quot; data-origin-width=&quot;1638&quot; data-origin-height=&quot;111&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;외부 IP가 없다는 경고 문구가 뜨고 알아서 포워딩 된다 !!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;정말 힘든 보안 정책이당,,,, ㅜ&lt;/p&gt;</description>
      <category>DevOps/Airflow</category>
      <category>gcp airflow 내부 ip</category>
      <category>gcp 내부ip</category>
      <category>gcp 외부 ip 삭제</category>
      <category>gcp 포트 포워딩</category>
      <category>ssh 터널링</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/129</guid>
      <comments>https://milkyspace.tistory.com/129#entry129comment</comments>
      <pubDate>Tue, 5 Nov 2024 19:10:01 +0900</pubDate>
    </item>
    <item>
      <title>[Airflow] Airflow db 변경</title>
      <link>https://milkyspace.tistory.com/128</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-e9340255bfdd4aab857c37376c6051c9&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;전 글에서 잠깐 설명한 Airflow default DB를 sqlite에서 MySQL로 바꾸는 작업과&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;GCP 인스턴스에 설치한 Airflow를 서비스(데몬)으로 띄우는 작업에 대해서 글을 쓰려고 한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-63e4dd63610a485eabd9dff9a63fbe31&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;만약 아직 Airflow를 설치하지 않았다면 이전 글을 참고해서 Airflow부터 설치해야 한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-b42e0b53c6e74ea7b61bb1a0ec484bd3&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://milkyspace.tistory.com/127&quot;&gt;https://milkyspace.tistory.com/127&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724411547682&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;[Airflow] 설치 (by.GCP 환경)&quot; data-og-description=&quot;GCP에 Airflow를 설치하려면 당연히 인스턴스가 있어야 한다.혹시나 인스턴스 생성이 안되어 있다면 이전 게시글을 참조하면 된다.&amp;nbsp;https://milkyspace.tistory.com/125&amp;nbsp;[GCP] VM Instance 생성 및 고정 IP 할당GCP&quot; data-og-host=&quot;milkyspace.tistory.com&quot; data-og-source-url=&quot;https://milkyspace.tistory.com/127&quot; data-og-url=&quot;https://milkyspace.tistory.com/127&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cJYZXF/hyWSphKFcs/E2lHL6LQ1Qq34PpXGZZKKk/img.png?width=800&amp;amp;height=160&amp;amp;face=0_0_800_160,https://scrap.kakaocdn.net/dn/5Ixh3/hyWR9FYiwx/6JA6R7Uuk6Tbc6hvrNgpO0/img.png?width=800&amp;amp;height=160&amp;amp;face=0_0_800_160,https://scrap.kakaocdn.net/dn/pYchE/hyWSpvg4WI/HQeU7DnqzHPJD29HKIGoZK/img.jpg?width=577&amp;amp;height=740&amp;amp;face=159_255_393_510&quot;&gt;&lt;a href=&quot;https://milkyspace.tistory.com/127&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://milkyspace.tistory.com/127&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cJYZXF/hyWSphKFcs/E2lHL6LQ1Qq34PpXGZZKKk/img.png?width=800&amp;amp;height=160&amp;amp;face=0_0_800_160,https://scrap.kakaocdn.net/dn/5Ixh3/hyWR9FYiwx/6JA6R7Uuk6Tbc6hvrNgpO0/img.png?width=800&amp;amp;height=160&amp;amp;face=0_0_800_160,https://scrap.kakaocdn.net/dn/pYchE/hyWSpvg4WI/HQeU7DnqzHPJD29HKIGoZK/img.jpg?width=577&amp;amp;height=740&amp;amp;face=159_255_393_510');&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;[Airflow] 설치 (by.GCP 환경)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;GCP에 Airflow를 설치하려면 당연히 인스턴스가 있어야 한다.혹시나 인스턴스 생성이 안되어 있다면 이전 게시글을 참조하면 된다.&amp;nbsp;https://milkyspace.tistory.com/125&amp;nbsp;[GCP] VM Instance 생성 및 고정 IP 할당GCP&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;milkyspace.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 id=&quot;block-3893ecfd0bf445eb8998adbe3aed60fc&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;b&gt;3. MySQL 설치 및 db생성, 계정 권한 부여&lt;/b&gt;&lt;/h1&gt;
&lt;p id=&quot;block-becafd2454294db8addd6b3ac35411bf&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Airflow의 DB를 MySQL로 변경하기 전에 먼저 설치를 해야 한다.&lt;/p&gt;
&lt;p id=&quot;block-c25de3b32ef04a018dccc6979b26da15&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;설치 방법은 apt-get 명령어를 이용해서 쉽게 설치할 수 있다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;block-24edadc71b0944328db81dcddaa2c273&quot;&gt;&lt;b&gt;MySQL 설치&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1724411572904&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt-get install mysql-server
sudo apt-get install mysql-client  libmysqlclient-dev pkg-config
sudo apt-get install python3-dev default-libmysqlclient-dev build-essential&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;1280&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beVdjA/btsJdPnYhnO/9ONaE4HsrKCo0kogBiCbQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beVdjA/btsJdPnYhnO/9ONaE4HsrKCo0kogBiCbQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beVdjA/btsJdPnYhnO/9ONaE4HsrKCo0kogBiCbQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeVdjA%2FbtsJdPnYhnO%2F9ONaE4HsrKCo0kogBiCbQ0%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;1051&quot; height=&quot;424&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;아래 명령어를 입력해서&amp;nbsp; mysql 서버로 접속이 되면 설치는 쉽게 완료되었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724411618197&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/usr/bin/mysql &amp;ndash;u root &amp;ndash;p

# password는 그냥 엔터&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;block-f495eed6cb6548f189960aa7a8159dd4&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;471&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HprfG/btsJd90NqqU/APnK2PXcYw2PpVa2dfoTLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HprfG/btsJd90NqqU/APnK2PXcYw2PpVa2dfoTLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HprfG/btsJd90NqqU/APnK2PXcYw2PpVa2dfoTLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHprfG%2FbtsJd90NqqU%2FAPnK2PXcYw2PpVa2dfoTLK%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;996&quot; height=&quot;367&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;471&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&lt;/p&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;block-c9c6ca1d393c421db69c05a9857d58e0&quot;&gt;&lt;b&gt;db생성 및 계정 권한 부여&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;block-92615f7f51184ba7a365e4f79c506ff2&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위에 명령어로 MySQL을 설치해주고 난 뒤,&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MySQL 서버에 접속하여 Airflow meta data와 dag들을 저장할 airflow 전용 db를 생성해준다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-9d71d43214844130becd62210ce9699d&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;나는 관리의 용이성을 위해 airflow 전용 사용자를 추가로 만들어주어서 진행했다.&lt;/p&gt;
&lt;p id=&quot;block-1eca5e0f5a924b8b95f379002ba87bab&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(사실 아래 스크린샷에는 user를 만들지 않고 그냥 root에 권한을 주었는데 이렇게 되니까 뒤에서 꼬여서 admin이라는 user로 다시 생성해주었다..ㅜ)&lt;/p&gt;
&lt;pre id=&quot;code_1724411695893&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#mysql 접속
mysql -u root -p

#airflow db 전용 user 생성
mysql&amp;gt; create user '{user명}'@'localhost' IDENTIFIED BY '{패스워드}';

#airflow db 생성
mysql &amp;gt; create database airflow(db명);

#airflow user에 airflowdb 권한 부여
mysql&amp;gt; GRANT ALL PRIVILEGES ON airflow(db명).* TO '{user명}'@'localhost';&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;block-1729d9951dec4fb69024d80784073b14&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYdyji/btsJfllklew/Fz0pDS9kAGyurikoCC5qS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYdyji/btsJfllklew/Fz0pDS9kAGyurikoCC5qS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYdyji/btsJfllklew/Fz0pDS9kAGyurikoCC5qS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYdyji%2FbtsJfllklew%2FFz0pDS9kAGyurikoCC5qS0%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;1028&quot; height=&quot;442&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;550&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1 id=&quot;block-7c0c483cfcca4878a2837aa47bf84935&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;b&gt;4. Airflow db 변경(MySQL)&lt;/b&gt;&lt;/h1&gt;
&lt;p id=&quot;block-ab9a655e7f384de98c88834f403f319f&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위에서 생성한 MySQL로 이제 Airflow의 DB를 변경해주는 작업을 진행하면 된다.&lt;/p&gt;
&lt;p id=&quot;block-5b755773d2514ecdaf443dc3db07cdf0&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;어려운 방법은 아니고 config 정도만 바꿔주고 초기화를 해주면 된다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;block-88be9672c1a643589fe10e1c34bd452f&quot;&gt;&lt;b&gt;airflow.cfg 수정&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;block-6e41486cbc9e4e77a9007ee1a5d457a1&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Airflow가 설치된 경로에 가서 airflow.cfg 파일을 찾아서 vi로 열어준다.&lt;/p&gt;
&lt;p id=&quot;block-5bcfdde947aa43bc906fc68888f79f4c&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그 파일에서 쭉 내리다 보면 다음과 같은 세 개의 변수들이 보일 것이다.&lt;/p&gt;
&lt;p id=&quot;block-dd4e78a88666453d8aa40a430a00a966&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 세 개의 설정을 아래와 같이 변경해주면 된다.&lt;/p&gt;
&lt;p id=&quot;block-788676839f694a4e802f8fd644173c2f&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기도 mysql user가 root로 되어있는 스크린샷인데 꼭 airflow user로 변경 해주어야 한다!! ㅠ&lt;/p&gt;
&lt;div id=&quot;block-a2b1e8dbfd5c4efda95767f939e987d6&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;353&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5agPN/btsJdpJLOJ1/nR4rGEQTMlOiSYv8KmkvW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5agPN/btsJdpJLOJ1/nR4rGEQTMlOiSYv8KmkvW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5agPN/btsJdpJLOJ1/nR4rGEQTMlOiSYv8KmkvW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5agPN%2FbtsJdpJLOJ1%2FnR4rGEQTMlOiSYv8KmkvW0%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;1403&quot; height=&quot;387&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;353&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;block-a551fd09ffe343d18edb019f0c41dc89&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;747&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpIr7S/btsJdqaQOL1/Skmjij3Ab5JdK7O0jrJ5V0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpIr7S/btsJdqaQOL1/Skmjij3Ab5JdK7O0jrJ5V0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpIr7S/btsJdqaQOL1/Skmjij3Ab5JdK7O0jrJ5V0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpIr7S%2FbtsJdqaQOL1%2FSkmjij3Ab5JdK7O0jrJ5V0%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;517&quot; height=&quot;302&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;747&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-42a080309c2e42faab19f72b7edab100&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;[참고. executor]&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;
&lt;table style=&quot;border-collapse: collapse; width: 82.7909%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;color: #000000;&quot;&gt;
&lt;td style=&quot;width: 20.7476%;&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;설정값&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 62.138%;&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;의미&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;color: #000000;&quot;&gt;
&lt;td style=&quot;width: 20.7476%;&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;SequentialExecutor &lt;br /&gt;(Default)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 62.138%;&quot;&gt;
&lt;div&gt;&lt;span&gt;task가 한 번에 한 개만 수행 &lt;br /&gt;&lt;b&gt;-&lt;/b&gt; Airflow DB가 sqlite(싱글작업만 가능)일 때 유일하게 가능한 executor 설정&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;color: #000000;&quot;&gt;
&lt;td style=&quot;width: 20.7476%;&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;b&gt;LocalExecutor&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 62.138%;&quot;&gt;
&lt;div&gt;&lt;span&gt;task들이 local에서 병렬적으로 수행 &lt;br /&gt;&lt;b&gt;- &lt;/b&gt;Unlimited Parallelism : task 개수 제한 없음 &lt;br /&gt;&lt;b&gt;-&lt;/b&gt; Limited Parallelism : task 개수 제한 있음 (task queue 존재)&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;block-dddb93b403884422ae151b7b60bf42ad&quot;&gt;&lt;b&gt;추가 설정&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;block-8e4dd3d83dfa46c0a2c00e3235664a6b&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Airflow에 MySQL을 연결하기 위해 필요한 패키지를 추가로 설치해 주었다.&lt;/p&gt;
&lt;pre id=&quot;code_1724411843835&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install mysqlclient&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;block-00400881cdd64fe285d2b956a39461a1&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;389&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddRlT0/btsJdeaFPMW/iXFMRIJ5BSrKFAZJBOyek1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddRlT0/btsJdeaFPMW/iXFMRIJ5BSrKFAZJBOyek1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddRlT0/btsJdeaFPMW/iXFMRIJ5BSrKFAZJBOyek1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FddRlT0%2FbtsJdeaFPMW%2FiXFMRIJ5BSrKFAZJBOyek1%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;1210&quot; height=&quot;368&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;389&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;block-654f7fc23e4f481b87f02b2e346cb2dc&quot;&gt;&lt;b&gt;dags 폴더 생성&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;block-a40b108a042b45bd8b0bb6284e61977c&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;airflow.cfg에 보면 dag들 경로도 설정되어 있는 부분이 있는데&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 폴더는 default로 존재하지 않아서 추가로 dags라는 폴더를 생성해주었다.&lt;/p&gt;
&lt;div id=&quot;block-2da63e754b67476194d5c308d4606cc7&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;99&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lfaty/btsJdsfsiSM/4Lzohl5UlygCN3IKpNOInK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lfaty/btsJdsfsiSM/4Lzohl5UlygCN3IKpNOInK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lfaty/btsJdsfsiSM/4Lzohl5UlygCN3IKpNOInK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flfaty%2FbtsJdsfsiSM%2F4Lzohl5UlygCN3IKpNOInK%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;708&quot; height=&quot;55.202175&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;99&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;block-a48bc824180d47a9a0faee2c2ff1f2c3&quot;&gt;&lt;b&gt;airflow db init (초기화)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;block-eae03440bacd405ea12f0919164cfd11&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이제 설정을 끝낸 MySQL과 Airflow를 연결시키기 위해 Airflow의 DB를 초기화 해준다.&lt;/p&gt;
&lt;div id=&quot;block-b329234225d94d0a87c7ad5a74e48341&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DnfaD/btsJdq9EIYb/AYiHWoqSh1kdw6YWoytLB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DnfaD/btsJdq9EIYb/AYiHWoqSh1kdw6YWoytLB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DnfaD/btsJdq9EIYb/AYiHWoqSh1kdw6YWoytLB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDnfaD%2FbtsJdq9EIYb%2FAYiHWoqSh1kdw6YWoytLB0%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;1246&quot; height=&quot;282&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;289&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-3d7cbc9485c1433bac57bae9eb968159&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;초기화를 해주면 위와 같이 mysql과 연결되었다는 메세지를 확인할 수 있다.&lt;/p&gt;
&lt;p id=&quot;block-1a212bf6bb8b45a5982ac2d67e7dcba2&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 mysql에 생성한 airflow db의 table를 확인해보면 airflow meta table들이 생겼는지 한 번 더 확인을 해준다.&lt;/p&gt;
&lt;p id=&quot;block-174d3afb9f4b4a8faaff0a1ea50760e4&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아래처럼 잘 보이면 Airflow의 db가 정상적으로 변경된 것이다.&lt;/p&gt;
&lt;div id=&quot;block-a1abb8f2ce6f404d8d0b1b36682e4549&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1672&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwHKuV/btsJeQlNBQh/qKzdrMP74YcBk9LVAYKdM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwHKuV/btsJeQlNBQh/qKzdrMP74YcBk9LVAYKdM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwHKuV/btsJeQlNBQh/qKzdrMP74YcBk9LVAYKdM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwHKuV%2FbtsJeQlNBQh%2FqKzdrMP74YcBk9LVAYKdM1%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;861&quot; height=&quot;1125&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1672&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;block-1a11d2458fb24eac85060b6d3a6a10b2&quot;&gt;&lt;b&gt;Airflow 계정 생성&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;block-0ed0e589bd104fda9911a7b2ebf27b11&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이제 Airflow를 접속할 계정을 생성해준다.&lt;/p&gt;
&lt;p id=&quot;block-a536987bc0e84906b744319e04066c03&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;계정을 생성하는 명령어는 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1724411944602&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;airflow users create \ 
--username &amp;lt;유저ID&amp;gt; \ 
--firstname &amp;lt;유저 firstname&amp;gt; \ 
--lastname &amp;lt;유저 lastname&amp;gt; \ 
--role &amp;lt;유저 role&amp;gt; \ 
--email &amp;lt;유저 email&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;block-731e4e7667c44a4cba2d5dc2a452e265&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7r7m4/btsJePNYsr4/Km7xXNbEsS8071K1cKB2hK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7r7m4/btsJePNYsr4/Km7xXNbEsS8071K1cKB2hK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7r7m4/btsJePNYsr4/Km7xXNbEsS8071K1cKB2hK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7r7m4%2FbtsJePNYsr4%2FKm7xXNbEsS8071K1cKB2hK%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;1002&quot; height=&quot;268&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;342&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;block-e4b3cdf694754ae5b7af10614d4cb242&quot;&gt;&lt;b&gt;Airflow Server 실행 및 로그인&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;block-fbcf7b8316cc4a49ae8be00dd403a702&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;생성한 user와 db 전환이 잘 되었는지 Airflow Webserver를 실행하고 접속을 해보려고 한다.&lt;/p&gt;
&lt;p id=&quot;block-c3fb79775b424da2b7e555d4b8b37e3a&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다음과 같은 명령어로 airflow webserver를 기동 시킬 수 있다.&lt;/p&gt;
&lt;p id=&quot;block-dffe6567c9434c6db5e7b9f2704b3652&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이전 글에서 airflow를 설치할 때 설정해준 port를 넣어주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1724411974084&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;airflow webserver -p 8080&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;block-8cebff799a0d475685ddd5834380a6f4&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;399&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xpRPS/btsJfl6Hy5c/sXBTKr6GNzRjRNubq4oAqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xpRPS/btsJfl6Hy5c/sXBTKr6GNzRjRNubq4oAqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xpRPS/btsJfl6Hy5c/sXBTKr6GNzRjRNubq4oAqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxpRPS%2FbtsJfl6Hy5c%2FsXBTKr6GNzRjRNubq4oAqK%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;1166&quot; height=&quot;364&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;399&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-7cd094dfdd064316a330a9bb40f7b482&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이제 직접 UI에서 접속을 해보자 !&lt;/p&gt;
&lt;div id=&quot;block-eb2c13fd065648eb8cd2b3b2dc38f5a3&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;433&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br01Hn/btsJead1X2h/9NX3hUHb3CbcuMXmWmtZSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br01Hn/btsJead1X2h/9NX3hUHb3CbcuMXmWmtZSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br01Hn/btsJead1X2h/9NX3hUHb3CbcuMXmWmtZSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr01Hn%2FbtsJead1X2h%2F9NX3hUHb3CbcuMXmWmtZSk%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;1791&quot; height=&quot;607&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;433&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;block-9d767c7a17f147a5a0e08d2febfcb51c&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;271&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KwxiQ/btsJe8zLvJE/G1Hnkx5S9DWImkCl8h2SX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KwxiQ/btsJe8zLvJE/G1Hnkx5S9DWImkCl8h2SX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KwxiQ/btsJe8zLvJE/G1Hnkx5S9DWImkCl8h2SX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKwxiQ%2FbtsJe8zLvJE%2FG1Hnkx5S9DWImkCl8h2SX1%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;708&quot; height=&quot;150.1497&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;271&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-9e1b4814f89b44cabc37edecee6530ae&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;접속이 잘 되는 것을 확인 했고 원래 sample dag들이 몇 개 있는데,&lt;/p&gt;
&lt;p id=&quot;block-dd94d2342f3b49f08de5547dcc1d3075&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위에서 airflow.cfg 파일에서 load_example를 False로 변경해주어서 sample dag들은 없다.&lt;/p&gt;
&lt;p id=&quot;block-34aa0d754aa8492f9d51d8b368660908&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이제 설치는 아주 정상적으로 되었다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-5e58921b1b98424ca5fd5f6ed888f21b&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아래부터는 선택사항인데 Airflow의 webserver와 scheduler가 GCP 서버가 시작되면 자동으로 시작되도록 서비스로 등록해줄 것이다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 id=&quot;block-397f949fc2fc42d4b3a4c0fef7bb789d&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;b&gt;5. Airflow의 webserver와 scheduler 서비스 등록&lt;/b&gt;&lt;/h1&gt;
&lt;p id=&quot;block-29bf4947727e484d9673f87d2774ce8d&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 airflow-webserver와 airflow-scheduler를 서비스로 만들어준다.&lt;/p&gt;
&lt;pre id=&quot;code_1724412017535&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#airflow-webserver.service 생성
sudo vi /etc/systemd/system/airflow-webserver.service

[Unit]
Description=Airflow webserver daemon
After=network.target mysql.service
wants=mysql.service

[Service] 
Environment=&quot;AIRFLOW_HOME=/home/airflow/airflow&quot;
User=airflow 
Group=airflow 
Type=simple
ExecStart=/usr/local/bin/airflow webserver 
Restart=on-failure 
RestartSec=5s 
PrivateTmp=true

[Install]
WantedBy=multi-user.target&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724412057695&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#airflow-scheduler.service 생성
sudo vi /etc/systemd/system/airflow-scheduler.service

[Unit]
Description=Airflow scheduler daemon
After=network.target mysql.service
wants=mysql.service

[Service]
Environment=&quot;AIRFLOW_HOME=/home/airflow/airflow&quot; 
User=airflow 
Group=airflow 
Type=simple
ExecStart=/usr/local/bin/airflow scheduler
Restart=on-failure
RestartSec=5s
PrivateTmp=true

[Install]
WantedBy=multi-user.target&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;span style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;그리고 데몬을 재실행 해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724412131197&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd /usr/bin/python3 
sudo systemctl daemon-reload&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;span style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;그리고 아래 명령어를 입력해주면 GCP 인스턴스가 실행 시 자동으로 Airflow가 시작되게 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724412147220&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#서버 실행시 자동으로 시작되게끔 하기
sudo systemctl enable airflow-webserver 
sudo systemctl enable airflow-scheduler

#서비스 시작하기
sudo systemctl start airflow-webserver 
sudo systemctl start airflow-scheduler

#서비스 상태 확인하기
sudo systemctl status airflow-webserver 
sudo systemctl status airflow-scheduler&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;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 설치랑 환경 설정은 모두 끝났고 Airflow의 Dags들만 잘 만들어서 ETL 파이프라인 개발에 사용하면 된다 !!!!!!!!!&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;006&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/006.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/006.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>DevOps/Airflow</category>
      <category>airflow db 변경</category>
      <category>airflow mysql</category>
      <category>airflow 계정 생성</category>
      <category>airflow 데몬 생성</category>
      <category>airflow 병렬 task</category>
      <category>airflow 설치</category>
      <category>airflow.cfg</category>
      <category>gcp mysql 설치</category>
      <category>gcp 서비스 생성</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/128</guid>
      <comments>https://milkyspace.tistory.com/128#entry128comment</comments>
      <pubDate>Fri, 23 Aug 2024 20:25:04 +0900</pubDate>
    </item>
    <item>
      <title>[Airflow] 설치 (by.GCP 환경)</title>
      <link>https://milkyspace.tistory.com/127</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-21db555ecf4e4f36a95fb44669e0f9f4&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;GCP에 Airflow를 설치하려면 당연히 인스턴스가 있어야 한다.&lt;/p&gt;
&lt;p id=&quot;block-fffaaf32500b80088029e5307423f325&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;혹시나 인스턴스 생성이 안되어 있다면 이전 게시글을 참조하면 된다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://milkyspace.tistory.com/125&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://milkyspace.tistory.com/125&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724322582084&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;[GCP] VM Instance 생성 및 고정 IP 할당&quot; data-og-description=&quot;GCP에 VM Instance를 생성하는 법은 간단한 클릭 몇 번만으로 할 수 있다.&amp;nbsp;먼저 GCP에 로그인 한 후,[Compute Engine] &amp;rarr; [VM 인스턴스] &amp;rarr; [인스턴스 만들기] 를 클릭한다.&amp;nbsp;1. 머신 구성그리고 서버 용도에 &quot; data-og-host=&quot;milkyspace.tistory.com&quot; data-og-source-url=&quot;https://milkyspace.tistory.com/125&quot; data-og-url=&quot;https://milkyspace.tistory.com/125&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Wu8Ab/hyWSeUvbbP/pydniiiWUKru22PxjsSqX0/img.png?width=800&amp;amp;height=237&amp;amp;face=0_0_800_237,https://scrap.kakaocdn.net/dn/7KkUn/hyWSgY6qNP/D0PfLfJVKedvxNGmm5WsKk/img.png?width=800&amp;amp;height=237&amp;amp;face=0_0_800_237,https://scrap.kakaocdn.net/dn/nUZ2V/hyWSaEBnjd/AdBTzsnkeoASXjSJbJND21/img.png?width=1798&amp;amp;height=1129&amp;amp;face=0_0_1798_1129&quot;&gt;&lt;a href=&quot;https://milkyspace.tistory.com/125&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://milkyspace.tistory.com/125&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Wu8Ab/hyWSeUvbbP/pydniiiWUKru22PxjsSqX0/img.png?width=800&amp;amp;height=237&amp;amp;face=0_0_800_237,https://scrap.kakaocdn.net/dn/7KkUn/hyWSgY6qNP/D0PfLfJVKedvxNGmm5WsKk/img.png?width=800&amp;amp;height=237&amp;amp;face=0_0_800_237,https://scrap.kakaocdn.net/dn/nUZ2V/hyWSaEBnjd/AdBTzsnkeoASXjSJbJND21/img.png?width=1798&amp;amp;height=1129&amp;amp;face=0_0_1798_1129');&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;[GCP] VM Instance 생성 및 고정 IP 할당&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;GCP에 VM Instance를 생성하는 법은 간단한 클릭 몇 번만으로 할 수 있다.&amp;nbsp;먼저 GCP에 로그인 한 후,[Compute Engine] &amp;rarr; [VM 인스턴스] &amp;rarr; [인스턴스 만들기] 를 클릭한다.&amp;nbsp;1. 머신 구성그리고 서버 용도에&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;milkyspace.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 id=&quot;block-cc69cbc9e4e244ab87f0fc31420cd662&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;b&gt;1. 사전 작업&lt;/b&gt;&lt;/h1&gt;
&lt;p id=&quot;block-664a580719aa47128a9182ac404389c5&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;GCP에 Airflow를 설치하기 전에 먼저 해주어야 할 작업이 있다.&lt;/p&gt;
&lt;p id=&quot;block-eab81f025f54466984ffa97819dbf519&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;계정 생성과 Python을 설치해 주어야 한다.&lt;/p&gt;
&lt;p id=&quot;block-909575986af0495e8d1f82d7e3b7b068&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Service를 사용하지 않으면 계정은 굳이 만들지 않아도 되긴 하지만 나는 Service를 만들어서 띄우기 위해 계정을 생성하려고 한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;block-9189e427d0dc4a569402d9dfbad90a4f&quot;&gt;&lt;b&gt;Airflow 계정 생성&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;block-b3fd4183291745f8849f0a04f16b1ae3&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Airflow 계정을 생성하고 비밀번호를 설정해주었다.&lt;/p&gt;
&lt;pre id=&quot;code_1724322544856&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo groupadd airflow
sudo useradd -m -d /home/airflow -g airflow airflow 
sudo passwd airflow&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;text-align: center; caret-color: transparent; background-color: #ffffff; color: #37352f; letter-spacing: 0px;&quot; src=&quot;https://blog.kakaocdn.net/dn/EV6cF/btsJdo3oS4P/7RgsEvbzM68jUA8q5Dnzjk/img.png&quot; width=&quot;1060&quot; height=&quot;278&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;336&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;block-de12a0cca2f44c0282d11e2c68260f2d&quot;&gt;&lt;b&gt;Python, pip 설치&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;block-91285be3159b4e95897b87eaf327fe66&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Python과 이후 라이브러리들을 쉽게 받기 위해 pip도 함께 설치해준다.&lt;/p&gt;
&lt;p id=&quot;block-dd824c327f834af1aadf9d85b196787b&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그런데 새로 생성한 계정에 sudo 권한이 없어서 먼저 sudo 추가를 해준다.&lt;/p&gt;
&lt;div id=&quot;block-4202882b0be247f3aa28870c4cff7fce&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;257&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KxS4q/btsJcSxg1Z9/12mmjOL7ISAVEO28dJQkNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KxS4q/btsJcSxg1Z9/12mmjOL7ISAVEO28dJQkNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KxS4q/btsJcSxg1Z9/12mmjOL7ISAVEO28dJQkNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKxS4q%2FbtsJcSxg1Z9%2F12mmjOL7ISAVEO28dJQkNk%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;871&quot; height=&quot;175&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;257&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;block-1b18d6b0b3de45cfa3603ce921eca3db&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;317&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IgwnB/btsJcgrM5K8/5hYevgmiuKx2x5KGKUHuU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IgwnB/btsJcgrM5K8/5hYevgmiuKx2x5KGKUHuU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IgwnB/btsJcgrM5K8/5hYevgmiuKx2x5KGKUHuU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIgwnB%2FbtsJcgrM5K8%2F5hYevgmiuKx2x5KGKUHuU1%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;372&quot; height=&quot;317&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;317&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-f32acd9a68cb4e52a87d3020dfe3981e&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Python, pip 설치 및 버전 확인을 해준다.&lt;/p&gt;
&lt;p id=&quot;block-3d268dbdb5594988bcc8cdb4e9f28d35&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위에서 생성한 airflow 계정으로 설치를 하는게 맞는데 계정 로그인을 다시 안해서.. root 권한으로 설치한 스크린샷으로 대체하였다.. ㅎ&lt;/p&gt;
&lt;div id=&quot;block-2341ee1deeb14bfdac4b3e867f178b63&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;798&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tCzB4/btsJb5qB7cI/UYpyRuu3Aj1AHXcus22zkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tCzB4/btsJb5qB7cI/UYpyRuu3Aj1AHXcus22zkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tCzB4/btsJb5qB7cI/UYpyRuu3Aj1AHXcus22zkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtCzB4%2FbtsJb5qB7cI%2FUYpyRuu3Aj1AHXcus22zkk%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;797&quot; height=&quot;497&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;798&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-a61b84f80a7e488081498ed37e8ad981&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;추가로 이후 airflow dag에서 사용할 라이브러리들도 미리 설치하였다.&lt;/p&gt;
&lt;pre id=&quot;code_1724322749415&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install google-analytics-data
pip install pandas
pip install Python-dateutil
pip install google-cloud-bigquery
....&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;block-2b6e41dd738342e099936f63e977d720&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1274&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mtiqY/btsJcj9Srlu/9WRTlBPB96AJGTDOw91cDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mtiqY/btsJcj9Srlu/9WRTlBPB96AJGTDOw91cDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mtiqY/btsJcj9Srlu/9WRTlBPB96AJGTDOw91cDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmtiqY%2FbtsJcj9Srlu%2F9WRTlBPB96AJGTDOw91cDK%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;336&quot; height=&quot;334.72&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1274&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;h1 style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1 id=&quot;block-fd7311321ea1456da35d2758647db93a&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;b&gt;2. Airflow 설치&lt;/b&gt;&lt;/h1&gt;
&lt;p id=&quot;block-2a3c87dde5a34e22824343b4178c7f53&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Airflow에 공식 가이드 문서가 있어서 이 docs를 참조해서 설치하였다.&lt;/p&gt;
&lt;p id=&quot;block-fffaaf32500b80108d80f8b3053fb943&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://airflow.apache.org/docs/apache-airflow/stable/start.html&quot;&gt;https://airflow.apache.org/docs/apache-airflow/stable/start.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724322802520&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Quick Start &amp;mdash; Airflow Documentation&quot; data-og-description=&quot;&quot; data-og-host=&quot;airflow.apache.org&quot; data-og-source-url=&quot;https://airflow.apache.org/docs/apache-airflow/stable/start.html&quot; data-og-url=&quot;https://airflow.apache.org/docs/apache-airflow/stable/start.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://airflow.apache.org/docs/apache-airflow/stable/start.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://airflow.apache.org/docs/apache-airflow/stable/start.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Quick Start &amp;mdash; Airflow Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;airflow.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724322847029&quot; class=&quot;autoit&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;airflow@airflow-server:~# echo 'export AIRFLOW_HOME=~/airflow' &amp;gt;&amp;gt; ~/.bash_profile
airflow@airflow-server:~# source ~/.bash_profile

airflow@airflow-server:~# AIRFLOW_VERSION=2.9.1
airflow@airflow-server:~# PYTHON_VERSION=&quot;$(PYTHON3 --version | cut -d &quot; &quot; -f 2 | cut -d &quot;.&quot; -f 1-2)&quot;
airflow@airflow-server:~# CONSTRAINT_URL=&quot;https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt&quot;
airflow@airflow-server:~# sudo pip install &quot;apache-airflow==${AIRFLOW_VERSION}&quot; --constraint &quot;${CONSTRAINT_URL} &quot;

airflow@airflow-server:~# airflow standalone&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-f42653a2b034430cae9a8697275e44c4&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;설치 당시(2024.05) 최신 버전이었던 2.9.1을 설치해주었다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-5cdac31557de406ea38b3972bf659203&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;맨 밑에 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;airflow standalone&lt;/b&gt;&lt;/span&gt;&lt;b&gt; &lt;/b&gt;명령어를 입력하면,&lt;/p&gt;
&lt;p id=&quot;block-eabb9e4382de434b98dbb779dd650852&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Airflow는&amp;nbsp;&lt;span style=&quot;color: #ef6f53;&quot;&gt;$AIRFLOW_HOME&lt;/span&gt;폴더를 생성하고 기본 값으로 &quot;airflow.cfg&quot; 파일을 생성하여 빠르게 작업할 수 있다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;환경 변수를 사용하여 기본 값을 재정의 할 수 있게 된다. 또한 airflow 서버가 기동된다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-1af36b0b61ce4435a7fc87a1423c0e55&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;성공적으로 설치를 진행했다면, Listening 정보, username, password 를 확인할 수 있다.&lt;/p&gt;
&lt;div id=&quot;block-5d94fc63d962432d86a503909a2a968b&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvLVkW/btsJbMrdWIu/ciXghOMLHXwPACsEgpOMU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvLVkW/btsJbMrdWIu/ciXghOMLHXwPACsEgpOMU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvLVkW/btsJbMrdWIu/ciXghOMLHXwPACsEgpOMU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvLVkW%2FbtsJbMrdWIu%2FciXghOMLHXwPACsEgpOMU0%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;1406&quot; height=&quot;289&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-5ac18f99100e4d62b7b0d4226553c8db&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위에서 기동된 airflow에 접속을 해보려고 하는데 맨 처음 GCP 인스턴스를 생성했으면 아무런 방화벽 정책이 적용되어 있지 않을 것이다. 그래서 방화벽 규칙 추가부터 해주어야 한다.&lt;/p&gt;
&lt;p id=&quot;block-7fdd885138464fba9edb9034cd4eea5c&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;[VPC 네트워크] &amp;rarr; [방화벽]&lt;/b&gt;&lt;/span&gt;을 클릭해준다.&lt;/p&gt;
&lt;div id=&quot;block-0454c5d710f24101a72d56c021e811a6&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqm42a/btsJbHQUk8K/aLjcOCvA1UrcsclSpG9Xlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqm42a/btsJbHQUk8K/aLjcOCvA1UrcsclSpG9Xlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqm42a/btsJbHQUk8K/aLjcOCvA1UrcsclSpG9Xlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbqm42a%2FbtsJbHQUk8K%2FaLjcOCvA1UrcsclSpG9Xlk%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;1468&quot; height=&quot;562&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-b0083be5e24f49c6bba81ae6231db3d6&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;방화벽 규칙 만들기를 클릭해주고 아래처럼 airflow default port인 8080을 허용해준다.&lt;/p&gt;
&lt;div id=&quot;block-4d14808db5a34aef85132ede53d6f6cd&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;801&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P95KN/btsJc4jU5Vn/EkbNRhEKS7pkVMRmWpni51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P95KN/btsJc4jU5Vn/EkbNRhEKS7pkVMRmWpni51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P95KN/btsJc4jU5Vn/EkbNRhEKS7pkVMRmWpni51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP95KN%2FbtsJc4jU5Vn%2FEkbNRhEKS7pkVMRmWpni51%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;708&quot; height=&quot;443.25214&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;801&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-81a508da668445a3b9e061b357476425&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;허용을 해주고 서버의 IP(혹은 127.0.0.1 혹은 localhost):8080으로 접속하면 아래처럼 airflow 로그인 화면이 보일 것이다. 여기서 위에서 알려준 계정(admin)으로 접속을 하면 성공적으로 설치된 것이다.&lt;/p&gt;
&lt;div id=&quot;block-3715cfad3e7f457d925542835c1ed4ec&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;394&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEUJ13/btsJbqBTGmX/74z9D2tVQe8SaWDkeMck4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEUJ13/btsJbqBTGmX/74z9D2tVQe8SaWDkeMck4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEUJ13/btsJbqBTGmX/74z9D2tVQe8SaWDkeMck4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEUJ13%2FbtsJbqBTGmX%2F74z9D2tVQe8SaWDkeMck4K%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;708&quot; height=&quot;217.98204&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;394&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;block-bb0733a5ccd14331bc37a4d1e0828cee&quot; style=&quot;background-color: #ffffff; color: #37352f; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일단 설치는 완료되었지만 추가로 작업해주어야 할 사항이 있다.&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt; &amp;nbsp;airflow의 default db는 sqlite이다.&lt;br /&gt;&lt;b&gt;sqlite는 task 병렬 처리가 되지 않아서&lt;/b&gt;&amp;nbsp;싱글 작업만 할 경우에는 default db를 사용해도 무관하지만&lt;br /&gt;내가 개발한 파이프라인에는 task들이 병렬로 수행해야 하는 로직이 있다.&lt;br /&gt;이러한 경우에&amp;nbsp;&lt;b&gt;airflow의 db를 MySQL 이나 PostgreSQL로 변경&lt;/b&gt;해주어야 한다.&lt;br /&gt;그래서 airflow가 설치된 서버에 MySQL 을 설치하고 airflow의 config 파일 변경 작업이 필요하다.&lt;br /&gt;&lt;b&gt;MySQL 설치부터 환경 설정은&amp;nbsp;다음 게시글에서 작성&lt;/b&gt;하려고 한다.&lt;/blockquote&gt;</description>
      <category>DevOps/Airflow</category>
      <category>airflow 설치</category>
      <category>gcp airflow 설치</category>
      <category>gcp pip 설치</category>
      <category>gcp python설치</category>
      <category>sudo 수정</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/127</guid>
      <comments>https://milkyspace.tistory.com/127#entry127comment</comments>
      <pubDate>Thu, 22 Aug 2024 19:42:19 +0900</pubDate>
    </item>
    <item>
      <title>[GCP] VM Instance 생성 및 고정 IP 할당</title>
      <link>https://milkyspace.tistory.com/125</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;GCP에 VM Instance를 생성하는 법은 간단한 클릭 몇 번만으로 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;먼저 GCP에 로그인 한 후,&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7; background-color: #f3c000;&quot;&gt;&lt;b&gt;[Compute Engine] &amp;rarr; [VM 인스턴스] &amp;rarr; [인스턴스 만들기] &lt;/b&gt;&lt;/span&gt;를 클릭한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WGYlG/btsIvenqKm8/p25gMNzf9PFC1dml9DyPnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WGYlG/btsIvenqKm8/p25gMNzf9PFC1dml9DyPnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WGYlG/btsIvenqKm8/p25gMNzf9PFC1dml9DyPnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWGYlG%2FbtsIvenqKm8%2Fp25gMNzf9PFC1dml9DyPnk%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;728&quot; height=&quot;216&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 머신 구성&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 서버 용도에 맞는 머신의 스펙을 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;나는 데이터를 daily로 ETL하기 위한 Airflow가 운영될 환경이라서 다음과 같은 스펙을 선택했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;리전 별, 머신 시리즈별로 CPU의 최대 코어수가 정해져있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(&lt;b&gt;[IAM 및 관리자]&amp;rarr; [할당량 및 시스템 한도]&lt;/b&gt;로 가면 확인이 가능하다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;증액 요청을 하면 되긴 하는데 시간이 오래 걸릴 것 같아서 우선 해보고 나중에 부족하면 늘리기로 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1798&quot; data-origin-height=&quot;1129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VehLN/btsIuvwx7Lx/tl44QAv5YODcspq5tfPjl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VehLN/btsIuvwx7Lx/tl44QAv5YODcspq5tfPjl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VehLN/btsIuvwx7Lx/tl44QAv5YODcspq5tfPjl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVehLN%2FbtsIuvwx7Lx%2Ftl44QAv5YODcspq5tfPjl1%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;741&quot; height=&quot;465&quot; data-origin-width=&quot;1798&quot; data-origin-height=&quot;1129&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 부팅 디스크는 100GB로 늘려주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;default가 10G였던 것 같은데 이게 나중에 되면 은근 부족하다고 해서 처음부터 그냥 크게 잡아두었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;575&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O5vX7/btsIu5dbLCP/hy0GX6bRGMbrMLFFgkYKS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O5vX7/btsIu5dbLCP/hy0GX6bRGMbrMLFFgkYKS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O5vX7/btsIu5dbLCP/hy0GX6bRGMbrMLFFgkYKS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO5vX7%2FbtsIu5dbLCP%2Fhy0GX6bRGMbrMLFFgkYKS1%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;745&quot; height=&quot;363&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;575&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;airflow 서버를 띄울 것이기 때문에 방화벽도 체크를 해주었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HqR8x/btsItn0AHul/3MXIJKVKXc9mJTc9CrAOd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HqR8x/btsItn0AHul/3MXIJKVKXc9mJTc9CrAOd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HqR8x/btsItn0AHul/3MXIJKVKXc9mJTc9CrAOd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHqR8x%2FbtsItn0AHul%2F3MXIJKVKXc9mJTc9CrAOd0%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;646&quot; height=&quot;206&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 고정 IP를 할당해주어야하기 때문에 아직 생성은 클릭하면 안돼요 !!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 고정 IP 할당&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Airflow 서버를 띄워야하기 때문에 airflow UI에 접근할 수 있는 고정 IP를 할당해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;871&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wAwuV/btsIu1u42H5/gmOacIG6rhiaf1kAAb7KvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wAwuV/btsIu1u42H5/gmOacIG6rhiaf1kAAb7KvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wAwuV/btsIu1u42H5/gmOacIG6rhiaf1kAAb7KvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwAwuV%2FbtsIu1u42H5%2FgmOacIG6rhiaf1kAAb7KvK%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;593&quot; height=&quot;324&quot; data-origin-width=&quot;871&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/figure&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;살펴보면 default인 값이 하나 있고,&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;817&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxhJSO/btsIvtSaSuh/KiIkKN78IaP4mjj02MfIGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxhJSO/btsIvtSaSuh/KiIkKN78IaP4mjj02MfIGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxhJSO/btsIvtSaSuh/KiIkKN78IaP4mjj02MfIGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdxhJSO%2FbtsIvtSaSuh%2FKiIkKN78IaP4mjj02MfIGK%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;671&quot; height=&quot;220&quot; data-origin-width=&quot;817&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;&lt;span style=&quot;color: #006dd7; background-color: #f3c000;&quot;&gt;외부 Ipv4주소&lt;/span&gt;&lt;/b&gt;라는 임시라고 체크되어 있는 리스트가 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 선택하고 &lt;span style=&quot;color: #006dd7; background-color: #f3c000;&quot;&gt;&lt;b&gt;고정 외부 IP 주소 예약&lt;/b&gt;&lt;/span&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;1548&quot; data-origin-height=&quot;951&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OPpTz/btsIt9HhCHf/kqO3tpjXGUkzZAdFyZD8Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OPpTz/btsIt9HhCHf/kqO3tpjXGUkzZAdFyZD8Kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OPpTz/btsIt9HhCHf/kqO3tpjXGUkzZAdFyZD8Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOPpTz%2FbtsIt9HhCHf%2FkqO3tpjXGUkzZAdFyZD8Kk%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;1548&quot; height=&quot;951&quot; data-origin-width=&quot;1548&quot; data-origin-height=&quot;951&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&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;1416&quot; data-origin-height=&quot;1129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFcOE6/btsIvOhtPv0/1RQrzZKPLx4Cj3eIsHa2e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFcOE6/btsIvOhtPv0/1RQrzZKPLx4Cj3eIsHa2e1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFcOE6/btsIvOhtPv0/1RQrzZKPLx4Cj3eIsHa2e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFcOE6%2FbtsIvOhtPv0%2F1RQrzZKPLx4Cj3eIsHa2e1%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;626&quot; height=&quot;499&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;1129&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;아직 인스턴스가 생성되기 전이기 때문에 연결 대상은 없음&lt;/b&gt;&lt;/span&gt;으로 두어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 다시 인스턴스 생성하는 곳으로 와서 외부 IPv4를 방금 생성한 고정 주소로 선택해준다.&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;span style=&quot;color: #006dd7; background-color: #f3c000;&quot;&gt;&lt;b&gt;만들기&lt;/b&gt;&lt;/span&gt;를 클릭하면 인스턴스가 생성된다 !!!!!!!&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;niniz&quot; data-emoticon-name=&quot;024&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/024.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/024.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>DevOps/GCP</category>
      <category>gcp instance 생성</category>
      <category>gcp public ip 할당</category>
      <category>gcp 고정 ip</category>
      <category>gcp 외부 ip</category>
      <category>gcp 인스턴스 생성</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/125</guid>
      <comments>https://milkyspace.tistory.com/125#entry125comment</comments>
      <pubDate>Wed, 10 Jul 2024 19:50:40 +0900</pubDate>
    </item>
    <item>
      <title>LinkedIn Ads API 드디어 개발 완료</title>
      <link>https://milkyspace.tistory.com/124</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;LinkedIn API는 구조도 복잡하기로 유명하고(스택 오버플로우 진짜 정독 몇 경번 함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;광고 쪽 도메인 날리지는 없어서 무슨 지표인지 맨날 찾으러 다녔던 눈물의&amp;nbsp; 2개월&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드디어 LinkedIn 로직 개발 완료 했다 ...&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;요즘 복잡한 일이 너무 많이 생겨서 걱정 인형인 나에게 다른 잡생각들이 덜해지는 것 같다&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;이제 나머지 리소스 7개만 20일만에 더 개발하면 된다 ! ^^&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>밀키의 다이어리</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/124</guid>
      <comments>https://milkyspace.tistory.com/124#entry124comment</comments>
      <pubDate>Sat, 8 Jun 2024 13:02:43 +0900</pubDate>
    </item>
    <item>
      <title>GCP Repositories를 사용해서 Airflow DAG 반영하기</title>
      <link>https://milkyspace.tistory.com/123</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;GCP에서 스케줄 작업을 할 때 가장 많이 사용하는 방법이&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;VM Instance에 Airflow를 설치해서 사용하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;소스의 편한 형상관리와 Airflow DAG 코드를 쉽게 반영하기 위해서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;GCP의 Repositories를 사용&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그래서 이번에는 GCP의 Repositories를 사용해서 DAG 코드를 Airflow 서버에 반영하는 방법에 대해서 간단하게 설명하려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;여기서 구성할 DAG는 Open API인 환율 구하는 API를 사용해서 전처리하여 daily로 해당일의 환율을 빅쿼리에 적재하려고 한다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[DAG 코드는 다음과 같이 작성한 상태]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;환율 API 호출(extract) &amp;rarr; 판다스를 통한 전처리(transform)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;빅쿼리 적재(load)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.koreaexim.go.kr/ir/HPHKIR020M01?apino=2&amp;amp;viewtype=C&amp;amp;searchselect=&amp;amp;searchword=%EF%BB%BF&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;환율 API&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API 호출을 위한 인증 키는 미리 발급 받아야함&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 빅쿼리 테이블 생성&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;먼저 데이터를 적재할 테이블을 생성해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;826&quot; data-origin-height=&quot;975&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cflki1/btsHurAXf1N/jZ5MrVFTACvh7jGMVoCiu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cflki1/btsHurAXf1N/jZ5MrVFTACvh7jGMVoCiu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cflki1/btsHurAXf1N/jZ5MrVFTACvh7jGMVoCiu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcflki1%2FbtsHurAXf1N%2FjZ5MrVFTACvh7jGMVoCiu0%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;362&quot; height=&quot;427&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;975&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;생성된 데이터 세트에서 테이블을 생성해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음과 같이 UI로 해도 되고 DDL 문을 사용해서 만들어주어도 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bniM89/btsHtYTzlU9/uRiorSf42pOdX7J3NnWUA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bniM89/btsHtYTzlU9/uRiorSf42pOdX7J3NnWUA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bniM89/btsHtYTzlU9/uRiorSf42pOdX7J3NnWUA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbniM89%2FbtsHtYTzlU9%2FuRiorSf42pOdX7J3NnWUA1%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;610&quot; height=&quot;307&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;나는 바로 적재할 예정이기 때문에 빈 테이블을 선택하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;기존에 GCS(Storage)에 있는 테이블을 선택하려면 테이블을 만들 소스를 변경해주면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;1129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nFw05/btsHuccYVw1/LpuULfHigLrS5hMYPbXQuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nFw05/btsHuccYVw1/LpuULfHigLrS5hMYPbXQuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nFw05/btsHuccYVw1/LpuULfHigLrS5hMYPbXQuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnFw05%2FbtsHuccYVw1%2FLpuULfHigLrS5hMYPbXQuK%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;621&quot; height=&quot;418&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;1129&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1141&quot; data-origin-height=&quot;584&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjtlA3/btsHt5SBNI1/G7ZxF6skLC9aTNTcnBVIN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjtlA3/btsHt5SBNI1/G7ZxF6skLC9aTNTcnBVIN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjtlA3/btsHt5SBNI1/G7ZxF6skLC9aTNTcnBVIN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjtlA3%2FbtsHt5SBNI1%2FG7ZxF6skLC9aTNTcnBVIN0%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;641&quot; height=&quot;328&quot; data-origin-width=&quot;1141&quot; data-origin-height=&quot;584&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. Repositories Clone&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;DAG 코드를 Repositories에서 관리하기 위해 Repositories를 생성하고 연결을 해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Repositories를 Clone해서 로컬 VS Code에서 보다 편하게 관리하려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Clone를 하기 위해선 SSH 인증을 받아야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;SSH 인증 방식은 여러가지가 있지만 나는 Google Cloud SDK를 사용해서 인증할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;인증 방법 참고 : &lt;a href=&quot;https://cloud.google.com/source-repositories/docs/authentication?hl=ko#windows&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cloud.google.com/source-repositories/docs/authentication?hl=ko#windows&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아래처럼 Repositories에서 &lt;b&gt;[클론]&lt;/b&gt;을 누르면 &lt;b&gt;[설정 방법 보기]&lt;/b&gt;가 나오는데 이걸 클릭해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;379&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c76OCJ/btsHtjRIH6B/eSGyeT8kn7TdLtu4O9KQs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c76OCJ/btsHtjRIH6B/eSGyeT8kn7TdLtu4O9KQs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c76OCJ/btsHtjRIH6B/eSGyeT8kn7TdLtu4O9KQs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc76OCJ%2FbtsHtjRIH6B%2FeSGyeT8kn7TdLtu4O9KQs1%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;594&quot; height=&quot;217&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;379&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그러면 다음과 같이 SDK를 이용한 인증 방법이 자세하게 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;우선 SDK를 설치해야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;설치 링크 : &lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://dl.google.com/dl/cloudsdk/channels/rapid/GoogleCloudSDKInstaller.exe?hl=&quot;&gt;https://dl.google.com/dl/cloudsdk/channels/rapid/GoogleCloudSDKInstaller.exe?hl=&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://dl.google.com/dl/cloudsdk/channels/rapid/GoogleCloudSDKInstaller.exe?hl=ko&quot;&gt;ko&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1758&quot; data-origin-height=&quot;883&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxcGII/btsHuOo4wfs/pXdRiUvNRqhOkqLzkNYEF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxcGII/btsHuOo4wfs/pXdRiUvNRqhOkqLzkNYEF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxcGII/btsHuOo4wfs/pXdRiUvNRqhOkqLzkNYEF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdxcGII%2FbtsHuOo4wfs%2FpXdRiUvNRqhOkqLzkNYEF1%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;1758&quot; height=&quot;883&quot; data-origin-width=&quot;1758&quot; data-origin-height=&quot;883&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1599&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qcqDW/btsHtu6y6sS/n5GWq3M8kw3jFFFMZQ0T1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qcqDW/btsHtu6y6sS/n5GWq3M8kw3jFFFMZQ0T1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qcqDW/btsHtu6y6sS/n5GWq3M8kw3jFFFMZQ0T1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqcqDW%2FbtsHtu6y6sS%2Fn5GWq3M8kw3jFFFMZQ0T1k%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;1599&quot; height=&quot;608&quot; data-origin-width=&quot;1599&quot; data-origin-height=&quot;608&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2316&quot; data-origin-height=&quot;616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFZqzE/btsHsQPWGSQ/Lqla93YAEZTK183OLIlwPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFZqzE/btsHsQPWGSQ/Lqla93YAEZTK183OLIlwPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFZqzE/btsHsQPWGSQ/Lqla93YAEZTK183OLIlwPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFZqzE%2FbtsHsQPWGSQ%2FLqla93YAEZTK183OLIlwPK%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;2316&quot; height=&quot;616&quot; data-origin-width=&quot;2316&quot; data-origin-height=&quot;616&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1544&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bp24Ke/btsHtb7nX4b/GFmpK6LL8IjyPOpRaqndRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bp24Ke/btsHtb7nX4b/GFmpK6LL8IjyPOpRaqndRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bp24Ke/btsHtb7nX4b/GFmpK6LL8IjyPOpRaqndRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbp24Ke%2FbtsHtb7nX4b%2FGFmpK6LL8IjyPOpRaqndRk%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;1544&quot; height=&quot;602&quot; data-origin-width=&quot;1544&quot; data-origin-height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;설치 방법은 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 바로 Google Cloud SDK Shell을 실행시켜서 SDK command들을 실행시켜주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;첫번째 command를 입력한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;553&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOhpaG/btsHuR0pljt/hRrbrZhQ11g283FKp5NAZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOhpaG/btsHuR0pljt/hRrbrZhQ11g283FKp5NAZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOhpaG/btsHuR0pljt/hRrbrZhQ11g283FKp5NAZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOhpaG%2FbtsHuR0pljt%2FhRrbrZhQ11g283FKp5NAZk%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;689&quot; height=&quot;323&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;553&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그러면 browser가 열리면서 인증을 하라는 내용이 뜬다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;1057&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/triH1/btsHtfoqffj/zA7QoTZE9d4vBLHQqWMkKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/triH1/btsHtfoqffj/zA7QoTZE9d4vBLHQqWMkKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/triH1/btsHtfoqffj/zA7QoTZE9d4vBLHQqWMkKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtriH1%2FbtsHtfoqffj%2FzA7QoTZE9d4vBLHQqWMkKK%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;536&quot; height=&quot;283&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;1057&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;823&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPtikK/btsHtKH1AqC/5ttTKbd3jv3pcz8hUvddEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPtikK/btsHtKH1AqC/5ttTKbd3jv3pcz8hUvddEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPtikK/btsHtKH1AqC/5ttTKbd3jv3pcz8hUvddEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPtikK%2FbtsHtKH1AqC%2F5ttTKbd3jv3pcz8hUvddEk%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;538&quot; height=&quot;221&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;823&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;인증 방법은 간단하게 로그인만 해주고 승인을 해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 나서 다시 SDK Shell에 나머지 command를 입력해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1870&quot; data-origin-height=&quot;491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJ5kX5/btsHsRBllMa/htA6P4kELtlhIiJM66TISK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJ5kX5/btsHsRBllMa/htA6P4kELtlhIiJM66TISK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJ5kX5/btsHsRBllMa/htA6P4kELtlhIiJM66TISK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJ5kX5%2FbtsHsRBllMa%2FhtA6P4kELtlhIiJM66TISK%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;1870&quot; height=&quot;491&quot; data-origin-width=&quot;1870&quot; data-origin-height=&quot;491&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;push까지는 해주지 않아도 되고 clone만 해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;clone를 하고 난 뒤 VS code로 와서 clone한 repo를 선택해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1999&quot; data-origin-height=&quot;582&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xhML1/btsHuLsqsUJ/e3XJyW27kwCLdyS6cdEZ40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xhML1/btsHuLsqsUJ/e3XJyW27kwCLdyS6cdEZ40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xhML1/btsHuLsqsUJ/e3XJyW27kwCLdyS6cdEZ40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxhML1%2FbtsHuLsqsUJ%2Fe3XJyW27kwCLdyS6cdEZ40%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;1999&quot; height=&quot;582&quot; data-origin-width=&quot;1999&quot; data-origin-height=&quot;582&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 동의를 한 번 해주면 clone뜬 repo가 vs code와 연동이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1710&quot; data-origin-height=&quot;861&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tJEcN/btsHsCj3G38/SulQbAUPEyeAV1VyjgKOt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tJEcN/btsHsCj3G38/SulQbAUPEyeAV1VyjgKOt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tJEcN/btsHsCj3G38/SulQbAUPEyeAV1VyjgKOt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtJEcN%2FbtsHsCj3G38%2FSulQbAUPEyeAV1VyjgKOt1%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;624&quot; height=&quot;314&quot; data-origin-width=&quot;1710&quot; data-origin-height=&quot;861&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Airflow에 반영할 DAG를 새로 작성하고 Push를 했더니 다음과 같은 오류가 발생하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;config를 해주지 않아서 발생한 오류이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;SDK Shell에서 이름과 이메일을 설정해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1690&quot; data-origin-height=&quot;721&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nX0ph/btsHueBR9NP/1DTYjHXZ6We6xXGKqPjrlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nX0ph/btsHueBR9NP/1DTYjHXZ6We6xXGKqPjrlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nX0ph/btsHueBR9NP/1DTYjHXZ6We6xXGKqPjrlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnX0ph%2FbtsHueBR9NP%2F1DTYjHXZ6We6xXGKqPjrlK%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;764&quot; height=&quot;326&quot; data-origin-width=&quot;1690&quot; data-origin-height=&quot;721&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;config를 수정하고 다시 push를 하면 정상적으로 Repositories에 반영된 것을 확인할 수 있다.&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;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. Airflow 반영(pull)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위의 과정을 통하여 Repositories에 push한 소스들을 airflow 서버에서 pull을 해주어야 DAG들이 반영이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;VM 인스턴스에서 SSH 연결을 통하여 airflow에 접속한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;1009&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dnnyk/btsHsIEpCYF/jvBKnBcstPakhQBZcFaSgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dnnyk/btsHsIEpCYF/jvBKnBcstPakhQBZcFaSgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dnnyk/btsHsIEpCYF/jvBKnBcstPakhQBZcFaSgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDnnyk%2FbtsHsIEpCYF%2FjvBKnBcstPakhQBZcFaSgk%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;757&quot; height=&quot;381&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;1009&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;airflow를 설치할때 사용한 설치 계정으로 login을 해준다. (sudo login airflow계정)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 git이 설치되어 있는 경로로 가서 pull을 해주면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1414&quot; data-origin-height=&quot;625&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zj9GP/btsHt1bHytl/NugpJYieyK0Hc2cK7zKrzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zj9GP/btsHt1bHytl/NugpJYieyK0Hc2cK7zKrzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zj9GP/btsHt1bHytl/NugpJYieyK0Hc2cK7zKrzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzj9GP%2FbtsHt1bHytl%2FNugpJYieyK0Hc2cK7zKrzk%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;1414&quot; height=&quot;625&quot; data-origin-width=&quot;1414&quot; data-origin-height=&quot;625&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;airflow 서버에 가보면 DAG가 반영된 것을 볼 수 있다!!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JWfTL/btsHsJDoIya/XCnI8eDmPYvzQuWK8WW6Sk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JWfTL/btsHsJDoIya/XCnI8eDmPYvzQuWK8WW6Sk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JWfTL/btsHsJDoIya/XCnI8eDmPYvzQuWK8WW6Sk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJWfTL%2FbtsHsJDoIya%2FXCnI8eDmPYvzQuWK8WW6Sk%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;2004&quot; height=&quot;438&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;실행을 시키면 ETL 작업이 정상적으로 완료된 것을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;641&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/muowm/btsHttGxsKO/5JXUSYI4XO3uB8IWMb1HrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/muowm/btsHttGxsKO/5JXUSYI4XO3uB8IWMb1HrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/muowm/btsHttGxsKO/5JXUSYI4XO3uB8IWMb1HrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmuowm%2FbtsHttGxsKO%2F5JXUSYI4XO3uB8IWMb1HrK%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;2004&quot; height=&quot;641&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;641&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1114&quot; data-origin-height=&quot;989&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDkfZ9/btsHs1wZZuh/gPm0I0CMcFpI3TstS7Gvk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDkfZ9/btsHs1wZZuh/gPm0I0CMcFpI3TstS7Gvk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDkfZ9/btsHs1wZZuh/gPm0I0CMcFpI3TstS7Gvk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDkfZ9%2FbtsHs1wZZuh%2FgPm0I0CMcFpI3TstS7Gvk0%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;602&quot; height=&quot;534&quot; data-origin-width=&quot;1114&quot; data-origin-height=&quot;989&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;niniz&quot; data-emoticon-name=&quot;012&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/012.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/012.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>DevOps/GCP</category>
      <category>airflow git</category>
      <category>airflow repositories</category>
      <category>gcp airflow</category>
      <category>gcp repositories</category>
      <category>google cloud sdk</category>
      <category>repositories clone</category>
      <category>repositories ssh</category>
      <category>빅쿼리 적재 dag</category>
      <category>환율 api</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/123</guid>
      <comments>https://milkyspace.tistory.com/123#entry123comment</comments>
      <pubDate>Fri, 17 May 2024 21:49:33 +0900</pubDate>
    </item>
    <item>
      <title>[Meta Ads] Meta(Facebook) Marketing API 연결</title>
      <link>https://milkyspace.tistory.com/122</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Meta에도 Marketing API가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;광고 캠페인에 대한 지표를 보기 위해서 Meta의 API를 호출해서 데이터를 적재하는 파이프라인을 개발하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Meta의 Marketing API를 연결하려면 다음과 같은 순서대로 진행하면 된다.&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;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. Business Manager 권한 부여&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;API를&amp;nbsp; 호출하려면 먼저 비즈니스 포트폴리오에 전체 관리 권한이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;2004&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/di8rrS/btsHoevWrWB/i32iMQ99R6sxGrgJtFB3gK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/di8rrS/btsHoevWrWB/i32iMQ99R6sxGrgJtFB3gK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/di8rrS/btsHoevWrWB/i32iMQ99R6sxGrgJtFB3gK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdi8rrS%2FbtsHoevWrWB%2Fi32iMQ99R6sxGrgJtFB3gK%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;2004&quot; height=&quot;148&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 앱 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;권한이 부여된 것을 확인하고 앱을 만들어서 API를 호출하는 토큰과 사용하려는 API를 설정해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음처럼 &lt;a href=&quot;https://developers.facebook.com/?no_redirect=1&amp;amp;locale=ko_KR&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;개발자 지원 센터&lt;/a&gt;로 이동하여 앱 만들기를 클릭한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGnvKt/btsHpjXxtJb/gmPeaOOm7FkH0kzK7qreHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGnvKt/btsHpjXxtJb/gmPeaOOm7FkH0kzK7qreHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGnvKt/btsHpjXxtJb/gmPeaOOm7FkH0kzK7qreHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGnvKt%2FbtsHpjXxtJb%2FgmPeaOOm7FkH0kzK7qreHk%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;2004&quot; height=&quot;283&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;283&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1173&quot; data-origin-height=&quot;699&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b17iM4/btsHmWbVDoO/bqj1IoAJCcsz9vMIUgQoc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b17iM4/btsHmWbVDoO/bqj1IoAJCcsz9vMIUgQoc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b17iM4/btsHmWbVDoO/bqj1IoAJCcsz9vMIUgQoc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb17iM4%2FbtsHmWbVDoO%2Fbqj1IoAJCcsz9vMIUgQoc0%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;1173&quot; height=&quot;699&quot; data-origin-width=&quot;1173&quot; data-origin-height=&quot;699&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1042&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7nWAn/btsHockxpfr/3Zn9JuKxNFmjRCVFiH4rYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7nWAn/btsHockxpfr/3Zn9JuKxNFmjRCVFiH4rYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7nWAn/btsHockxpfr/3Zn9JuKxNFmjRCVFiH4rYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7nWAn%2FbtsHockxpfr%2F3Zn9JuKxNFmjRCVFiH4rYK%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;1042&quot; height=&quot;732&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;732&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그 다음으로는 비즈니스 포트폴리오를 선택한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1293&quot; data-origin-height=&quot;561&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/us17C/btsHnxQe4PP/FlygYmWCyCgWnaTkdmzqL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/us17C/btsHnxQe4PP/FlygYmWCyCgWnaTkdmzqL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/us17C/btsHnxQe4PP/FlygYmWCyCgWnaTkdmzqL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fus17C%2FbtsHnxQe4PP%2FFlygYmWCyCgWnaTkdmzqL0%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;1293&quot; height=&quot;561&quot; data-origin-width=&quot;1293&quot; data-origin-height=&quot;561&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그러면 앱이 만들어진다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 앱에 재품을 추가해주어야 하는데 나는 Marketing API를 사용할 것이기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;마케팅 API를 선택하여 내가 만든 앱에 추가를 해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1354&quot; data-origin-height=&quot;739&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQVaf4/btsHnK22fUY/jkGWBo2Lqevprur9em66U1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQVaf4/btsHnK22fUY/jkGWBo2Lqevprur9em66U1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQVaf4/btsHnK22fUY/jkGWBo2Lqevprur9em66U1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQVaf4%2FbtsHnK22fUY%2FjkGWBo2Lqevprur9em66U1%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;1354&quot; height=&quot;739&quot; data-origin-width=&quot;1354&quot; data-origin-height=&quot;739&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 토큰 받기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 앱 생성은 마쳤고 앱의 ID와 시크릿코드, 마케팅 API 호출할 때 필요한 토큰을 생성해주어야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[앱 대시보드] &amp;rarr; [앱 설정] &amp;rarr; [기본 설정]&lt;/b&gt;으로 가면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;앱 ID와 앱 시크릿 코드를 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1663&quot; data-origin-height=&quot;624&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cu4ypC/btsHpytpasQ/YhHBgcJBlWugXA0rt2y7Yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cu4ypC/btsHpytpasQ/YhHBgcJBlWugXA0rt2y7Yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cu4ypC/btsHpytpasQ/YhHBgcJBlWugXA0rt2y7Yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcu4ypC%2FbtsHpytpasQ%2FYhHBgcJBlWugXA0rt2y7Yk%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;1663&quot; height=&quot;624&quot; data-origin-width=&quot;1663&quot; data-origin-height=&quot;624&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음으로는 마케팅 API를 호출하기 위해 토큰을 생성해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;역시 &lt;b&gt;[앱 대시보드] &amp;rarr; [마케팅 API] &amp;rarr; [도구]&lt;/b&gt;에서 필요한 권한을 선택하고 토큰 받기를 클릭해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그러면 바로 밑 박스에 토큰이 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1748&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AFtst/btsHpevgrwh/cwGdNWg4UzQLUnI7LRsmq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AFtst/btsHpevgrwh/cwGdNWg4UzQLUnI7LRsmq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AFtst/btsHpevgrwh/cwGdNWg4UzQLUnI7LRsmq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAFtst%2FbtsHpevgrwh%2FcwGdNWg4UzQLUnI7LRsmq1%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;1748&quot; height=&quot;788&quot; data-origin-width=&quot;1748&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 간단한 API 호출 코드 작성 (Requests)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위에서 얻은 정보를 바탕으로 campaign과 insight fields를 조회하는 코드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;account는 &lt;a href=&quot;https://business.facebook.com/adsmanager/manage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;admanager&lt;/a&gt;에 있는 id를 넣어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;&lt;b&gt;앞에는 꼭 &quot;act_&quot;를 붙여줘야함!!!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(안 보이기는 하는데 ... 빨간색 네모의 id)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;595&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNwf4a/btsHpzf0XJG/ZmhRsSIJVOwLTPrKSuwkI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNwf4a/btsHpzf0XJG/ZmhRsSIJVOwLTPrKSuwkI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNwf4a/btsHpzf0XJG/ZmhRsSIJVOwLTPrKSuwkI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNwf4a%2FbtsHpzf0XJG%2FZmhRsSIJVOwLTPrKSuwkI1%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;2004&quot; height=&quot;595&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;595&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1715687790973&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ver = &quot;v19.0&quot;
account = 'act_{accountid}'
token = '{Insert Token}'

insights = 'campaign_name,adset_name,ad_name,impressions,clicks,reach,spend,conversions,conversion_values'
url = f&quot;https://graph.facebook.com/{ver}/{account}/insights&quot;

params = {
    'fields': insights,
    'access_token': token, 
    'level': 'ad',
    'time_range[since]' : '2024-01-01',
    'time_range[until]' : '2024-01-28',
    'action_report_time' : 'conversion',
    'use_unified_attribution_setting' : 'true',
    &quot;action_breakdowns&quot;: &quot;action_type&quot;,
}


r = requests.get(url = url, params= params )
print(r.url)

if r.status_code != 200:
    print(&quot;something went wrong :&quot;,r.text)
    assert r.status_code == 200
else:
    content = r.text
    content_json = json.loads(content)
    print(content_json)&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;size18&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;1572&quot; data-origin-height=&quot;253&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9RZD1/btsHpK2FwlR/yA46qsF5XakOQLEmEBkxWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9RZD1/btsHpK2FwlR/yA46qsF5XakOQLEmEBkxWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9RZD1/btsHpK2FwlR/yA46qsF5XakOQLEmEBkxWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9RZD1%2FbtsHpK2FwlR%2FyA46qsF5XakOQLEmEBkxWK%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;1572&quot; height=&quot;253&quot; data-origin-width=&quot;1572&quot; data-origin-height=&quot;253&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;그런데 fields에 conversions 관련 metrics들은 넣어주었음에도 불구하고 출력이 안되어서&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;추후에 확인해야할 내용이다ㅜ&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Request를 써서 직접 호출하지 않고 SDK를 써서 라이브러리로 호출하는 방법은 아래 링크를 참고하면 될 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://developers.facebook.com/docs/business-sdk/getting-started/#meta-business-sdk&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developers.facebook.com/docs/business-sdk/getting-started/#meta-business-sdk&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1715688870470&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;시작하기 - Meta Business SDK - 문서 - Meta for Developers&quot; data-og-description=&quot;Meta Business SDK 시작하기 이 문서에서는 Meta Business SDK를 설치하고 해당 설치를 테스트하는 방법을 설명합니다. SDK는 Java, JavaScript, PHP, Python 및 Ruby에서 사용 가능합니다. 마케팅 API가 이미 설치되&quot; data-og-host=&quot;developers.facebook.com&quot; data-og-source-url=&quot;https://developers.facebook.com/docs/business-sdk/getting-started/#meta-business-sdk&quot; data-og-url=&quot;https://developers.facebook.com/docs/business-sdk/getting-started/#meta-business-sdk&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://developers.facebook.com/docs/business-sdk/getting-started/#meta-business-sdk&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers.facebook.com/docs/business-sdk/getting-started/#meta-business-sdk&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;시작하기 - Meta Business SDK - 문서 - Meta for Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Meta Business SDK 시작하기 이 문서에서는 Meta Business SDK를 설치하고 해당 설치를 테스트하는 방법을 설명합니다. SDK는 Java, JavaScript, PHP, Python 및 Ruby에서 사용 가능합니다. 마케팅 API가 이미 설치되&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers.facebook.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;niniz&quot; data-emoticon-name=&quot;002&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/002.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/002.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>Python/API Connect</category>
      <category>facebook API</category>
      <category>meta ad api</category>
      <category>meta 광고</category>
      <category>metaapi</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/122</guid>
      <comments>https://milkyspace.tistory.com/122#entry122comment</comments>
      <pubDate>Mon, 13 May 2024 22:11:16 +0900</pubDate>
    </item>
    <item>
      <title>Google Analystic4(GA4) API 연결 (GCP 환경)</title>
      <link>https://milkyspace.tistory.com/121</link>
      <description>&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;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이번 프로젝트에서 GCP 환경에서 GA4의 데이터를 불러와야하는 작업이 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;데이터 ETL 파이프라인을 개발하고 대시보드까지 구축해야하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;As-Is에서는 대시보드를 lookerstudio로 썼기 때문에 바로 커넥터를 사용해서 연결을 했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;To-Be 환경은 태블로 서버를 GCP Instance에 구축할 것이라 GA의 API를 사용해서&amp;nbsp; 데이터를 적재할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;우선 GCP 환경이기 때문에 프로젝트를 생성해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;만약 프로젝트부터 생성해야한다면 &lt;a href=&quot;https://console.cloud.google.com/welcome&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;여기&lt;/a&gt;를 통해 생성하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. GA API enable&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;먼저 생성한 프로젝트에서 GA의 API를 사용할 수 있도록 API를 enable 해주어야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[API 및 서비스] &amp;rarr; [라이브러리]&lt;/b&gt;에서 GA 관련 API를 선택한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;혹은 아래 링크를&amp;nbsp; 통해 접속해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://console.cloud.google.com/apis/library?supportedpurview=project&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://console.cloud.google.com/apis/library?supportedpurview=project&lt;/a&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;2004&quot; data-origin-height=&quot;515&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hmzu1/btsG2XhSALa/8UGSEVhs7vZ7oKH0H0hrwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hmzu1/btsG2XhSALa/8UGSEVhs7vZ7oKH0H0hrwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hmzu1/btsG2XhSALa/8UGSEVhs7vZ7oKH0H0hrwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHmzu1%2FbtsG2XhSALa%2F8UGSEVhs7vZ7oKH0H0hrwk%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;2004&quot; height=&quot;515&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;515&quot;/&gt;&lt;/span&gt;&lt;/figure&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;우선 나는 제일&amp;nbsp; 먼저 보이는 API를 선택했는데 내가 전처리해야 될 데이터가 더&amp;nbsp; 있어서 다음 API를 추가로 사용해주었다.&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;1224&quot; data-origin-height=&quot;564&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vh4VN/btsG2mhJSqV/uvCC5CdLKMvLvPJ5EhRdV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vh4VN/btsG2mhJSqV/uvCC5CdLKMvLvPJ5EhRdV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vh4VN/btsG2mhJSqV/uvCC5CdLKMvLvPJ5EhRdV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvh4VN%2FbtsG2mhJSqV%2FuvCC5CdLKMvLvPJ5EhRdV0%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;678&quot; height=&quot;312&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;564&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. IAM Service Account 생성&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음으로는 API를 호출할 서비스 계정을 생성해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;서비스 계정으로 인증키를 생성하고 이 키를 이용해 서버 간의 인증을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[IAM &amp;amp; Admin] &lt;b&gt;&amp;rarr;&lt;/b&gt; [Service Accounts]&lt;/b&gt;를 선택한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1492&quot; data-origin-height=&quot;479&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWUxi9/btsG6hLXZFh/0udE0MPIchCoYmuMRZuFIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWUxi9/btsG6hLXZFh/0udE0MPIchCoYmuMRZuFIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWUxi9/btsG6hLXZFh/0udE0MPIchCoYmuMRZuFIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWUxi9%2FbtsG6hLXZFh%2F0udE0MPIchCoYmuMRZuFIk%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;785&quot; height=&quot;252&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;479&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음과 같이 account ID만 넣어주면 특별한 설정없이 생성은 빠르게 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #2a2a2a; text-align: start;&quot;&gt;&lt;span&gt;그러면 &lt;/span&gt;~@~iam.gserviceaccount.com 이라는 계정이 만들어지고 이 계정이 앞으로 API 서비스를 이용할 때 사용할 계정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;995&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ch7sMd/btsG5kbFFkH/ukKSWSgI5kQld0K8ITz4O0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ch7sMd/btsG5kbFFkH/ukKSWSgI5kQld0K8ITz4O0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ch7sMd/btsG5kbFFkH/ukKSWSgI5kQld0K8ITz4O0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fch7sMd%2FbtsG5kbFFkH%2FukKSWSgI5kQld0K8ITz4O0%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;760&quot; height=&quot;560&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;995&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;생성한 서비스 계정을 선택하고 &lt;b&gt;[KEYS]&lt;/b&gt; 항목으로 들어가면 키를 생성할 수 있는 화면이 뜬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;2004&quot; data-origin-height=&quot;517&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BEm6D/btsG48PZ1VR/IyplSwtJBk1w2nKQ5BbKrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BEm6D/btsG48PZ1VR/IyplSwtJBk1w2nKQ5BbKrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BEm6D/btsG48PZ1VR/IyplSwtJBk1w2nKQ5BbKrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBEm6D%2FbtsG48PZ1VR%2FIyplSwtJBk1w2nKQ5BbKrk%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;2004&quot; height=&quot;517&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;517&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;어떤 방식으로 키를 생성할건지를 묻는 팝업이 뜨는데 JSON을 선택해주면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;887&quot; data-origin-height=&quot;624&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHoBSg/btsG4hmcMkg/lFjxrD5mr58zCvpTHMxee1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHoBSg/btsG4hmcMkg/lFjxrD5mr58zCvpTHMxee1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHoBSg/btsG4hmcMkg/lFjxrD5mr58zCvpTHMxee1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHoBSg%2FbtsG4hmcMkg%2FlFjxrD5mr58zCvpTHMxee1%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;535&quot; height=&quot;376&quot; data-origin-width=&quot;887&quot; data-origin-height=&quot;624&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음처럼 키가 생성된 것을 볼 수 있고 바로 JSON 형태로 파일이 다운받아지는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 파일은 키를 생성할 때 &lt;b&gt;한 번만 생성&lt;/b&gt;되기 때문에 잘 보관을 해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1267&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TTVU0/btsG54MRiO0/2OU6dK4t4jw2RwQeZToTD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TTVU0/btsG54MRiO0/2OU6dK4t4jw2RwQeZToTD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TTVU0/btsG54MRiO0/2OU6dK4t4jw2RwQeZToTD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTTVU0%2FbtsG54MRiO0%2F2OU6dK4t4jw2RwQeZToTD1%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;1267&quot; height=&quot;224&quot; data-origin-width=&quot;1267&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. GA에 Service Account 권한 추가&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;이제 GCP 계정에서 API 호출할 준비는 끝났고&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;데이터를 불러올 GA에 위에서 생성한 서비스 계정에 권한을 부여해주어야 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;기존에 권한을 받았다고 하더라도 우리가 통신할 계정은 서비스 계정이기 때문에&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #2a2a2a; text-align: start;&quot;&gt;&lt;b&gt;~@~iam.gserviceaccount.com 이 계정에 최소 Read 권한&lt;/b&gt;을 주어야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #2a2a2a; text-align: start;&quot;&gt;권한을 주지 않으면 데이터를 읽을 수가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #2a2a2a; text-align: start;&quot;&gt;관리자 권한으로 GA를 접속한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #2a2a2a; text-align: start;&quot;&gt;다음과 같이 Admin 페이지로 들어가서 계정 엑세스 관리를 클릭한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1862&quot; data-origin-height=&quot;689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csKML9/btsG4W3fH5g/xTRukwG3KYRe9AUHYSv3a0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csKML9/btsG4W3fH5g/xTRukwG3KYRe9AUHYSv3a0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csKML9/btsG4W3fH5g/xTRukwG3KYRe9AUHYSv3a0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsKML9%2FbtsG4W3fH5g%2FxTRukwG3KYRe9AUHYSv3a0%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;779&quot; height=&quot;288&quot; data-origin-width=&quot;1862&quot; data-origin-height=&quot;689&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #2a2a2a; text-align: start;&quot;&gt;오른쪽 상단에 사용자 추가를 선택하고 위에서 생성한 서비스 계정을 추가해준다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #2a2a2a; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;353&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBFLH5/btsG4iZJP5R/Lc93GlshLo5wcsnzO8YhPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBFLH5/btsG4iZJP5R/Lc93GlshLo5wcsnzO8YhPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBFLH5/btsG4iZJP5R/Lc93GlshLo5wcsnzO8YhPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBFLH5%2FbtsG4iZJP5R%2FLc93GlshLo5wcsnzO8YhPK%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;2004&quot; height=&quot;353&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;353&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;권한은 뷰어 이상만 주면 된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;몇 번 강조하지만 꼭 서비스 계정( &lt;b&gt;~@~iam.gserviceaccount.com&lt;/b&gt;)에 부여해주어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;1069&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EUGbq/btsG5BRLDyC/jduPTo1LccKAKBOO9lJhy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EUGbq/btsG5BRLDyC/jduPTo1LccKAKBOO9lJhy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EUGbq/btsG5BRLDyC/jduPTo1LccKAKBOO9lJhy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEUGbq%2FbtsG5BRLDyC%2FjduPTo1LccKAKBOO9lJhy0%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;823&quot; height=&quot;439&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;1069&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. Python으로 API 호출&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 파이썬으로 API를&amp;nbsp; 호출해보는 간단한 코드를 실행시켜 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아래에 지표들이 여러 개 나오는데 google docs를 찾아보면서 하면 조금 더 이해가 편할 것 같다!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://developers.google.com/analytics/devguides/reporting/data/v1/api-schema?hl=ko#metrics&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developers.google.com/analytics/devguides/reporting/data/v1/api-schema?hl=ko#metrics&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1714476334452&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import os

from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.analytics.data_v1beta.types import (
    DateRange,
    Dimension,
    Metric,
    RunReportRequest,
)

os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'GCP-Keyfile.json'

property_id=&quot;GA4-PROPERTY-ID&quot;
client = BetaAnalyticsDataClient()

request = RunReportRequest(
    property=f&quot;properties/{property_id}&quot;,
    dimensions=[Dimension(name=&quot;city&quot;)],
    metrics=[Metric(name=&quot;activeUsers&quot;)],
    date_ranges=[DateRange(start_date=&quot;2024-04-01&quot;, end_date=&quot;today&quot;)],
)
response = client.run_report(request)

print(&quot;Report result:&quot;)
for row in response.rows:
    print(row.dimension_values[0].value, row.metric_values[0].value)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;GOOGLE_APPLICATION_CREDENTIALS에는 2번에서 서비스 계정을 생성하고 다운로드 받은 Key Json 파일의 이름을 넣어주면 된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;property_id는&amp;nbsp;GA로 가서 보면,,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;보안 때문에 다 가려져서 안 보이기는 하는데 App 이름 밑에 숫자로 된 App ID가 있을 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&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;618&quot; data-origin-height=&quot;737&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/euPggY/btsG2ofxMIO/cjlo3AAjbb8SegSVqdblgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/euPggY/btsG2ofxMIO/cjlo3AAjbb8SegSVqdblgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/euPggY/btsG2ofxMIO/cjlo3AAjbb8SegSVqdblgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeuPggY%2FbtsG2ofxMIO%2Fcjlo3AAjbb8SegSVqdblgK%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;425&quot; height=&quot;507&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;737&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위 코드는 단순하게 Dimension을 City로 주고 활성 유저수를 Metrics로 주고 조회하는 코드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;691&quot; data-origin-height=&quot;684&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfXXnP/btsG6hd884A/Ea8nqV9h4WeUd28HdFIa20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfXXnP/btsG6hd884A/Ea8nqV9h4WeUd28HdFIa20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfXXnP/btsG6hd884A/Ea8nqV9h4WeUd28HdFIa20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfXXnP%2FbtsG6hd884A%2FEa8nqV9h4WeUd28HdFIa20%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;471&quot; height=&quot;466&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;684&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;API의 Metrics나 Dimension은 여러 개를 넣고 호출해도 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1714476956470&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;request = RunReportRequest(
    property=f&quot;properties/{property_id}&quot;,
    dimensions=[
        Dimension(name=&quot;pagePath&quot;),
        Dimension(name=&quot;country&quot;), 
        Dimension(name=&quot;deviceCategory&quot;), 
    ],
    metrics=[
        Metric(name=&quot;totalUsers&quot;),
        Metric(name=&quot;sessions&quot;),
        Metric(name=&quot;screenPageViews&quot;),
        Metric(name=&quot;bounceRate&quot;),
    ],
    date_ranges=[DateRange(start_date='2024-04-01', end_date='2024-04-30')],
     dimension_filter=FilterExpression(
             filter=Filter(
                 field_name=&quot;pagePath&quot;,
                 string_filter=Filter.StringFilter(value=&quot;/tistory&quot;, 
                                                   match_type=Filter.StringFilter.MatchType.CONTAINS),
             )
         )
)


# run request
response = client.run_report(request)

data = []

for row in response.rows:
    dimension_values = [value.value for value in row.dimension_values]
    metric_values = [value.value for value in row.metric_values]
    data.append(dimension_values + metric_values)

columns = [dimension.name for dimension in response.dimension_headers] + [metric.name for metric in response.metric_headers]

df = pd.DataFrame(data, columns=columns)&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;위 코드는 여러 개의 Metrics, Dimension&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 filter로 원하는 조건만 추출할 수 있게 작성한 코드이다.&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;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;niniz&quot; data-emoticon-name=&quot;010&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/010.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/010.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>Python/API Connect</category>
      <category>ga api</category>
      <category>ga api filter</category>
      <category>ga api metrics 여러 개</category>
      <category>ga api 가이드</category>
      <category>ga4</category>
      <category>ga4 gcp</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/121</guid>
      <comments>https://milkyspace.tistory.com/121#entry121comment</comments>
      <pubDate>Tue, 30 Apr 2024 20:41:41 +0900</pubDate>
    </item>
    <item>
      <title>[Python] URL encoding (request 파라미터 ASCII 변환)</title>
      <link>https://milkyspace.tistory.com/120</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;요즘 LinkedIn Ads API를 통해 ETL 로직을 개발하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그런데 LinkedIn Ads의 API는 정말 당황스럽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;docs도 잘 되어있지 않고 호출할 파라미터들은 중구난방이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;원하는 정보를 얻으려면 호출의 호출의 호출을 통해서 얻을 수 있었다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 무엇보다 request params들이 꼭 특수문자로&quot;만&quot; 들어와야지 호출이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(근데 campaign 관련 urn 파라미터는 아스키코드로&quot;만&quot; 들어와야지 호출가능 .. ㅎ)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그렇지 않으면 400(Bad Request) 오류가 떨어진다.&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;1586&quot; data-origin-height=&quot;989&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCw8EF/btsF5EiHoCt/uK9Z2VWaTkPIDdzsRsTOx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCw8EF/btsF5EiHoCt/uK9Z2VWaTkPIDdzsRsTOx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCw8EF/btsF5EiHoCt/uK9Z2VWaTkPIDdzsRsTOx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCw8EF%2FbtsF5EiHoCt%2FuK9Z2VWaTkPIDdzsRsTOx1%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;813&quot; height=&quot;507&quot; data-origin-width=&quot;1586&quot; data-origin-height=&quot;989&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그래서 해결 방법을 찾은게 바로 &lt;b&gt;urllib.parse 모듈&lt;/b&gt;의 &lt;b&gt;urlencode&lt;/b&gt; 함수를 써서 특수문자들이&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아스키 코드가 아닌 특수문자 그대로 처리되게&amp;nbsp; 예외처리를 해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;urlencode 함수는 &lt;span&gt;str&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;이나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;bytes&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;객체를 포함할 수 있는 매핑 객체나 두 요소 튜플의 시퀀스를 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd; color: #ef5369;&quot;&gt;퍼센트 인코딩&lt;/span&gt;된 ASCII 텍스트 문자열로 변환&lt;/b&gt;해준다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;이 때 결과 문자열을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;urlopen()&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수를 사용하여 POST 연산을 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;data&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;로 사용하려면, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;바이트열로 인코딩해야 하고 그렇지 않으면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;TypeError&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;가 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span&gt;  &lt;b&gt;퍼센트 인코딩이란?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;br /&gt;URL 인코딩은 퍼센트 인코딩이라고도 불리며 URL에 문자를 표현하는 문자 인코딩 방법&lt;/span&gt;&lt;br /&gt;&lt;span&gt;알파벳이나 숫자 등 몇몇 문자를 제외한 나머지는 1바이트 단위로 묶인 16진수(ASCII)로 인코딩하는 방식&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt; &lt;b&gt;&lt;span&gt; 해주어야하는 이유&lt;/span&gt;?&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;GET 방식을 통해 HTTP 요청을 할 때 쿼리 파라미터가 붙는 경우가 생기는데 URL은 ASCII 코드값만 사용된다. &lt;br /&gt;이 쿼리 파라미터에 한글이 포함될 경우, ASCII 코드만으로 표현을 할 수 없어서 인코딩을 해야한다. &lt;br /&gt;호출하는 API마다 쿼리 파라미터에 한글 문자 그대로를 지원하는 경우도 있지만 그렇지 않은 경우도 있으므로 &lt;br /&gt;미리 인코딩을 거친 형식으로 전송하는 것이 바람직하다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;사용 방법은 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1711624491205&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;urllib.parse.urlencode(query, doseq=False, safe='', 
                encoding=None, errors=None, quote_via=quote_plus)&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;size18&quot;&gt;위 코드에서 query만 required 값이라 변환대상만 넣어주어도 되고&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;나의 경우 ASCII로의 변경을 막아야해서 &lt;b&gt;safe 파라미터에 변환하지 않을 특수문자들을 넣어주었다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;파라미터 값이 괄호, 컴마, 콜론, 등호 등등이 있어서 해당하는 값들은 모두 넣어주었다.&lt;/p&gt;
&lt;pre id=&quot;code_1711624655492&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;campaigngroup_params = urllib.parse.urlencode(campaigngroup_params, safe='#\':()+=%,')&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;1592&quot; data-origin-height=&quot;655&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sDqv1/btsF7xwjnqp/cHSJeKVboZSh8o3KKJjzGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sDqv1/btsF7xwjnqp/cHSJeKVboZSh8o3KKJjzGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sDqv1/btsF7xwjnqp/cHSJeKVboZSh8o3KKJjzGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsDqv1%2FbtsF7xwjnqp%2FcHSJeKVboZSh8o3KKJjzGK%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;1592&quot; height=&quot;655&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;655&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 호출을&amp;nbsp; 다시 한 결과 response code가 200으로 잘 호출이 되었고 원하는 resonse 값도 얻을 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Postman에는 저런 값들이 인코딩이 잘되어서 오류가 발생하지 않았는데 파이썬으로 호출할 때 발생하였고&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;오류를 잘 해결해서 API도 잘 불러왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python/요약 정리</category>
      <category>request 파라미터</category>
      <category>urlencode</category>
      <category>urllib.parse</category>
      <category>url인코딩</category>
      <category>아스키코드</category>
      <category>특수문자아스키</category>
      <category>특수문자인코딩</category>
      <category>퍼센트인코딩</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/120</guid>
      <comments>https://milkyspace.tistory.com/120#entry120comment</comments>
      <pubDate>Tue, 26 Mar 2024 21:10:31 +0900</pubDate>
    </item>
    <item>
      <title>  [LinkedIn Ads] Advertising API 호출하기!</title>
      <link>https://milkyspace.tistory.com/119</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;LinkedIn의 Ads 쪽 데이터를 API로 호출해서 적재하는 파이프라인을 만들려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;API 호출을 단순 Auth로 하면 될 줄 알았는데 생각보다 복잡한 절차가 있어서 정리하려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. LinkedIn Developers에서 App 생성&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;601&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Niptr/btsFK9IKXVm/rISBTqiKH3tevQYlxvzeK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Niptr/btsFK9IKXVm/rISBTqiKH3tevQYlxvzeK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Niptr/btsFK9IKXVm/rISBTqiKH3tevQYlxvzeK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNiptr%2FbtsFK9IKXVm%2FrISBTqiKH3tevQYlxvzeK1%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;2004&quot; height=&quot;601&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;601&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;LinkedIn API를 연동하기 위해서는 LinkedIn Developers(&lt;a href=&quot;https://developer.linkedin.com/&quot;&gt;https://developer.linkedin.com/&lt;/a&gt;)에서 app을 생성 해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1108&quot; data-origin-height=&quot;1129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dTwUv9/btsFK7xnaOj/WBSnhrhDsJRkT1f1ElAXL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dTwUv9/btsFK7xnaOj/WBSnhrhDsJRkT1f1ElAXL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dTwUv9/btsFK7xnaOj/WBSnhrhDsJRkT1f1ElAXL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdTwUv9%2FbtsFK7xnaOj%2FWBSnhrhDsJRkT1f1ElAXL0%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;802&quot; height=&quot;817&quot; data-origin-width=&quot;1108&quot; data-origin-height=&quot;1129&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;앱의 이름과 LinkedIn Page, 그리고 로고 이미지를 넣고 앱을 생성하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;앱은 바로 생성이 되고 내가 필요한 &lt;b&gt;Advertising API&lt;/b&gt;를 Request해야하는데 블락이 되어 있다.&lt;br /&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;1460&quot; data-origin-height=&quot;733&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WZGAR/btsFJ7EEqht/ONpZOJQBpkmZXTWvBz6eSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WZGAR/btsFJ7EEqht/ONpZOJQBpkmZXTWvBz6eSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WZGAR/btsFJ7EEqht/ONpZOJQBpkmZXTWvBz6eSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWZGAR%2FbtsFJ7EEqht%2FONpZOJQBpkmZXTWvBz6eSK%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;772&quot; height=&quot;388&quot; data-origin-width=&quot;1460&quot; data-origin-height=&quot;733&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;앱을 생성하면서 넣어주었던 회사의 LinkedIn 계정 담당자가 승인을 해주어야 API를 요청할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;계정 담당자가 승인할 수 있는 URL을 전달해주어야 하는데 URL 생성 방법은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[설정]&lt;/b&gt; 탭으로 가서 Verify를 클릭&lt;br /&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;950&quot; data-origin-height=&quot;477&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqO38P/btsFIyiJiUa/DO0jILhsCEHNKAuIDQgBj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqO38P/btsFIyiJiUa/DO0jILhsCEHNKAuIDQgBj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqO38P/btsFIyiJiUa/DO0jILhsCEHNKAuIDQgBj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqO38P%2FbtsFIyiJiUa%2FDO0jILhsCEHNKAuIDQgBj0%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;768&quot; height=&quot;386&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;477&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Verification URL 에서&lt;/b&gt; URL 생성을 클릭해주면 URL이 생성이 되고 이를 복사해서 LinkedIn 계정 담당자에게 전달을 하면 된다.&lt;br /&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;938&quot; data-origin-height=&quot;793&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kSkzN/btsFIwSHErN/kBO2oKGZMGx1kBNxVftZKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kSkzN/btsFIwSHErN/kBO2oKGZMGx1kBNxVftZKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kSkzN/btsFIwSHErN/kBO2oKGZMGx1kBNxVftZKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkSkzN%2FbtsFIwSHErN%2FkBO2oKGZMGx1kBNxVftZKK%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;704&quot; height=&quot;595&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;793&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;URL은 30일 동안 유효하고 시간이 지나면 URL을 다시 생성해서 전달해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. Advertising API 권한 요청&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;회사와 연결이 되면 [&lt;b&gt;제품&lt;/b&gt;] 탭으로 가서 Advertising API에 대해 권한을 요청한다.&lt;br /&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;1458&quot; data-origin-height=&quot;557&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTlTvq/btsFJyJlgMR/M5RE2TD2R7l4pH35dcGOPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTlTvq/btsFJyJlgMR/M5RE2TD2R7l4pH35dcGOPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTlTvq/btsFJyJlgMR/M5RE2TD2R7l4pH35dcGOPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTlTvq%2FbtsFJyJlgMR%2FM5RE2TD2R7l4pH35dcGOPK%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;1458&quot; height=&quot;557&quot; data-origin-width=&quot;1458&quot; data-origin-height=&quot;557&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;권한을 요청하면 다음과 같은 팝업이 뜨고 동의한다는 내용에 체크를 해주면 신청이 완료된다.&lt;br /&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;698&quot; data-origin-height=&quot;704&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UQ14f/btsFJ2KcCDd/KeUqPTSaOuX85cNmk2OHcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UQ14f/btsFJ2KcCDd/KeUqPTSaOuX85cNmk2OHcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UQ14f/btsFJ2KcCDd/KeUqPTSaOuX85cNmk2OHcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUQ14f%2FbtsFJ2KcCDd%2FKeUqPTSaOuX85cNmk2OHcK%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;389&quot; height=&quot;392&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;704&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;권한 요청을 하면 다음과 같이 뜨고 시간이 좀 지나면 액세스를 요청하는 form 링크가 뜬다.&lt;br /&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;970&quot; data-origin-height=&quot;564&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zgWep/btsFJ3ClY3V/3MVWWtIMuCW7hOY7KtX7y0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zgWep/btsFJ3ClY3V/3MVWWtIMuCW7hOY7KtX7y0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zgWep/btsFJ3ClY3V/3MVWWtIMuCW7hOY7KtX7y0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzgWep%2FbtsFJ3ClY3V%2F3MVWWtIMuCW7hOY7KtX7y0%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;970&quot; height=&quot;564&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;564&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ejin9/btsFHrEpHtc/KTKqTGTteiXGjknXk1KCZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ejin9/btsFHrEpHtc/KTKqTGTteiXGjknXk1KCZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ejin9/btsFHrEpHtc/KTKqTGTteiXGjknXk1KCZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEjin9%2FbtsFHrEpHtc%2FKTKqTGTteiXGjknXk1KCZK%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;948&quot; height=&quot;375&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;form을 작성하고 요청을 제출하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4페이지까지 있고 누락되는 경우 API 허용이 거절된다고 하니 잘 써야 할 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;승인까지는 하루 정도가 걸린다고 한다.&amp;nbsp;&lt;br /&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;1046&quot; data-origin-height=&quot;1129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mRwWu/btsFHrj5uQq/vDoW7FheV5zexnS4sKg850/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mRwWu/btsFHrj5uQq/vDoW7FheV5zexnS4sKg850/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mRwWu/btsFHrj5uQq/vDoW7FheV5zexnS4sKg850/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmRwWu%2FbtsFHrj5uQq%2FvDoW7FheV5zexnS4sKg850%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;660&quot; height=&quot;712&quot; data-origin-width=&quot;1046&quot; data-origin-height=&quot;1129&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;길게는 하루 정도가 소요된다고 했는데 나의 경우는 약 10분..? 정도 뒤에 다음과 같은 화답 메일이 왔다.&amp;nbsp;&lt;br /&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;1218&quot; data-origin-height=&quot;839&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0ka6z/btsFO0EHag3/DVLKzlw3aK6Ze24d0R7lBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0ka6z/btsFO0EHag3/DVLKzlw3aK6Ze24d0R7lBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0ka6z/btsFO0EHag3/DVLKzlw3aK6Ze24d0R7lBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0ka6z%2FbtsFO0EHag3%2FDVLKzlw3aK6Ze24d0R7lBk%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;668&quot; height=&quot;460&quot; data-origin-width=&quot;1218&quot; data-origin-height=&quot;839&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2-1. Advertising&amp;nbsp;API에 광고 계정 추가(선택 사항)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;광고 계정을 추가하는 단계이다. 해당 작업은 optional로 추가하긴 했는데 차이점을 잘 못느끼겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(만약 나중에 차이점을 발견하면 추가로 기재해두겠습니다..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;form 작성을 완료한 Advertising&amp;nbsp;API에서 &lt;b&gt;View Ad Account&lt;/b&gt;를 클릭한다.&lt;br /&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;950&quot; data-origin-height=&quot;403&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3bWoT/btsFMzvbG3v/diTDgo9QjfomEdKfoaWeP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3bWoT/btsFMzvbG3v/diTDgo9QjfomEdKfoaWeP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3bWoT/btsFMzvbG3v/diTDgo9QjfomEdKfoaWeP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3bWoT%2FbtsFMzvbG3v%2FdiTDgo9QjfomEdKfoaWeP1%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;808&quot; height=&quot;343&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;403&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그러면 Ad 계정이 비어있고 &lt;b&gt;Add&amp;nbsp;&lt;/b&gt; &lt;b&gt;Ad Account&amp;nbsp;&lt;/b&gt;버튼이 있고 이를 눌러주고 Ad Account Number을 넣어주면 된다.&lt;br /&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;967&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/19V0m/btsFMrcYP3v/8W675mOc0UqbEKCZwk04PK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/19V0m/btsFMrcYP3v/8W675mOc0UqbEKCZwk04PK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/19V0m/btsFMrcYP3v/8W675mOc0UqbEKCZwk04PK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F19V0m%2FbtsFMrcYP3v%2F8W675mOc0UqbEKCZwk04PK%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;724&quot; height=&quot;431&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이 Number는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;a style=&quot;color: #0070d1; text-align: start;&quot; href=&quot;https://www.linkedin.com/campaignmanager/accounts&quot;&gt;캠페인 매니저&lt;/a&gt;&lt;/b&gt;에 있는 Ad Account Number을 넣어주면 된다.&lt;br /&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;403&quot; data-origin-height=&quot;553&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d0Ir75/btsFLPd3Eot/YpW4jkCAXYXk1LmVUsXlx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d0Ir75/btsFLPd3Eot/YpW4jkCAXYXk1LmVUsXlx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d0Ir75/btsFLPd3Eot/YpW4jkCAXYXk1LmVUsXlx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd0Ir75%2FbtsFLPd3Eot%2FYpW4jkCAXYXk1LmVUsXlx0%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;329&quot; height=&quot;451&quot; data-origin-width=&quot;403&quot; data-origin-height=&quot;553&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;get_access_token&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt;3. Postman으로 액세스 토큰 생성&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://www.linkedin.com/developers/apps/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;&lt;b&gt;LinkedIn Developer Portal&lt;/b&gt;&lt;/b&gt;&lt;/a&gt;로 이동해서 Auth에 있는 Client ID와 Client Secret를 확인한다.&lt;br /&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;1174&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bislqq/btsFOYmAE7K/VgEbOww2jMZmnyKKFHO6z0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bislqq/btsFOYmAE7K/VgEbOww2jMZmnyKKFHO6z0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bislqq/btsFOYmAE7K/VgEbOww2jMZmnyKKFHO6z0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbislqq%2FbtsFOYmAE7K%2FVgEbOww2jMZmnyKKFHO6z0%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;710&quot; height=&quot;318&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;526&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 바로 밑에 카드에서 OAuth 2.0 Setting로 가서 URL을 추가해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음과 같이 연필 모양을 클릭하면 Add redirect URL이 뜨고 추가할 수 있다.&lt;br /&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;1194&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d8sZxh/btsFNlC4kXD/cTJaIP7kGbSm3qJz5RKmF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d8sZxh/btsFNlC4kXD/cTJaIP7kGbSm3qJz5RKmF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d8sZxh/btsFNlC4kXD/cTJaIP7kGbSm3qJz5RKmF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd8sZxh%2FbtsFNlC4kXD%2FcTJaIP7kGbSm3qJz5RKmF1%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;782&quot; height=&quot;312&quot; data-origin-width=&quot;1194&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;620&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XjMzs/btsFLT1PvUi/53INKXA0bxLcnMqJlQWef0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XjMzs/btsFLT1PvUi/53INKXA0bxLcnMqJlQWef0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XjMzs/btsFLT1PvUi/53INKXA0bxLcnMqJlQWef0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXjMzs%2FbtsFLT1PvUi%2F53INKXA0bxLcnMqJlQWef0%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;789&quot; height=&quot;403&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;620&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음과 같이 두 개의 URL을 추가해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(사실 browser이 들어있는 URL만 추가해주어도 되는데 공식 Docs에서 두 개를 넣어주었길래 다 넣었당..)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;https://oauth.pstmn.io/v1/browser-callback&lt;/li&gt;
&lt;li&gt;https://oauth.pstmn.io/v1/callback&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by55rT/btsFODXhWvI/FtOAPYw0Vlr4AGPRAqKUZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by55rT/btsFODXhWvI/FtOAPYw0Vlr4AGPRAqKUZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by55rT/btsFODXhWvI/FtOAPYw0Vlr4AGPRAqKUZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby55rT%2FbtsFODXhWvI%2FFtOAPYw0Vlr4AGPRAqKUZK%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;789&quot; height=&quot;333&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 Postman을 열고 Auth 탭으로 이동하고 Type을 &lt;b&gt;OAuth 2.0&lt;/b&gt;으로 변경해준다.&lt;br /&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;1349&quot; data-origin-height=&quot;730&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zNdIJ/btsFNuGIhL5/o1cXuFChk4BA8Miej0k3w1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zNdIJ/btsFNuGIhL5/o1cXuFChk4BA8Miej0k3w1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zNdIJ/btsFNuGIhL5/o1cXuFChk4BA8Miej0k3w1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzNdIJ%2FbtsFNuGIhL5%2Fo1cXuFChk4BA8Miej0k3w1%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;792&quot; height=&quot;429&quot; data-origin-width=&quot;1349&quot; data-origin-height=&quot;730&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;새로운 토큰을 생성해야 하는데 토큰 생성 관련 정보를 아래와 같이 입력해주고 &lt;b&gt;Get New Access Token&lt;/b&gt;을 클릭해준다.&lt;br /&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;823&quot; data-origin-height=&quot;826&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ma8Ck/btsFLsJ7FjL/YKForx2XsQYnnLKvoFqbI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ma8Ck/btsFLsJ7FjL/YKForx2XsQYnnLKvoFqbI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ma8Ck/btsFLsJ7FjL/YKForx2XsQYnnLKvoFqbI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fma8Ck%2FbtsFLsJ7FjL%2FYKForx2XsQYnnLKvoFqbI0%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;703&quot; height=&quot;706&quot; data-origin-width=&quot;823&quot; data-origin-height=&quot;826&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Grant Type = Authorization Code&lt;/li&gt;
&lt;li&gt;Callback URL = https://oauth.pstmn.io/v1/browser-callback&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 80.814%; height: 77px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span&gt;&lt;b&gt;주의&lt;/b&gt;!!&amp;nbsp;&lt;br /&gt;여기서 Callback Url을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #161616;&quot;&gt;&lt;a href=&quot;https://oauth.pstmn.io/v1/callback&quot;&gt;https://oauth.pstmn.io/v1/callback&lt;/a&gt;로 해주면 &lt;b&gt;반드시 밑에 있는 Authorize using browser을 체크!!&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Auth URL = &lt;a href=&quot;https://www.linkedin.com/oauth/v2/authorization&quot;&gt;https://www.linkedin.com/oauth/v2/authorization&lt;/a&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/li&gt;
&lt;li&gt;Access Token URL = &lt;a href=&quot;https://www.linkedin.com/oauth/v2/accessToken&quot;&gt;https://www.linkedin.com/oauth/v2/accessToken&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Client ID = {Copy this from the &amp;ldquo;Auth&amp;rdquo; tab in the developer portal}&lt;/li&gt;
&lt;li&gt;Client Secret = {Copy this from the &amp;ldquo;Auth&amp;rdquo; tab in the developer portal}&lt;/li&gt;
&lt;li&gt;State = 공백&lt;/li&gt;
&lt;li&gt;Client Authentication = Send client credentials in body&lt;/li&gt;
&lt;li&gt;Scope = r_ads_reporting,r_organization_social,rw_organization_admin,r_ads,r_basicprofile,r_organization_admin&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;Scope안에 있는 값은 개발자 포털에서 OAuth 2.0 scopes 참조하여 입력 (아래 리스트 참조)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&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;1062&quot; data-origin-height=&quot;1129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxGWsZ/btsFMCljOFl/TsYHnffNGaYPrU1RoYCCc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxGWsZ/btsFMCljOFl/TsYHnffNGaYPrU1RoYCCc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxGWsZ/btsFMCljOFl/TsYHnffNGaYPrU1RoYCCc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdxGWsZ%2FbtsFMCljOFl%2FTsYHnffNGaYPrU1RoYCCc0%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;649&quot; height=&quot;690&quot; data-origin-width=&quot;1062&quot; data-origin-height=&quot;1129&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;거의 다 끝났습니다 !!!!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;토큰을 생성하면 browser에서 잠시 확인을 하고 다음과 같은 LinkedIn 팝업이 뜬다.&lt;br /&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;1658&quot; data-origin-height=&quot;820&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqn1J0/btsFLUsP4UJ/mQaX3W3WJZ1cw3tqxv3XDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqn1J0/btsFLUsP4UJ/mQaX3W3WJZ1cw3tqxv3XDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqn1J0/btsFLUsP4UJ/mQaX3W3WJZ1cw3tqxv3XDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcqn1J0%2FbtsFLUsP4UJ%2FmQaX3W3WJZ1cw3tqxv3XDK%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;1658&quot; height=&quot;820&quot; data-origin-width=&quot;1658&quot; data-origin-height=&quot;820&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 LinkedIn 계정을 입력하면 승인을 요청한다는 팝업이 또 뜨고 이를 허용해주면 성공적으로 Auth 는 끝난다.&lt;br /&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;747&quot; data-origin-height=&quot;742&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vR7Sd/btsFLunGycB/qGiBloLaKaSW9d5wAQMpB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vR7Sd/btsFLunGycB/qGiBloLaKaSW9d5wAQMpB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vR7Sd/btsFLunGycB/qGiBloLaKaSW9d5wAQMpB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvR7Sd%2FbtsFLunGycB%2FqGiBloLaKaSW9d5wAQMpB0%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;747&quot; height=&quot;742&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;742&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 단순한 연동 테스트를 하기 위해서 다음 API를 호출해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URI :&amp;nbsp;&lt;span style=&quot;color: #dd1144;&quot;&gt;&lt;a href=&quot;https://api.linkedin.com/v2/me&quot;&gt;https://api.linkedin.com/v2/me&lt;/a&gt; &lt;/span&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;1064&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J6mQS/btsFOd5NIp0/moSw66kKQlJy7wOwvhnCaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J6mQS/btsFOd5NIp0/moSw66kKQlJy7wOwvhnCaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J6mQS/btsFOd5NIp0/moSw66kKQlJy7wOwvhnCaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ6mQS%2FbtsFOd5NIp0%2FmoSw66kKQlJy7wOwvhnCaK%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;1064&quot; height=&quot;634&quot; data-origin-width=&quot;1064&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;나의 정보를 호출하는 API이고 아주 성공적으로 Response를 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음에는 캠페인정보나 필요한 코드들로 API를 연동하는 테스트 코드를 추가할 예정이다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Python/API Connect</category>
      <category>ads API</category>
      <category>LinkedIn</category>
      <category>linkedin ads</category>
      <category>linkedin adversiting API</category>
      <category>LinkedIn OAuth</category>
      <category>OAuth 2.0</category>
      <category>Postman OAuth 2.0</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/119</guid>
      <comments>https://milkyspace.tistory.com/119#entry119comment</comments>
      <pubDate>Tue, 12 Mar 2024 17:38:05 +0900</pubDate>
    </item>
    <item>
      <title>[Python] AWS Glue에서 비동기 처리 (concurrent.futures)</title>
      <link>https://milkyspace.tistory.com/118</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;◎ concurrent.furue 모듈&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;기존에 파이썬에서는 스레드를 구현하려면 threading 모듈을 사용하고 멀티 프로세스 프로그램을 구현하려면 multiprocessing 모듈을 사용해야 했었다.&amp;nbsp;하지만 3.2 버전부터는 concurrent.futures&amp;nbsp;모듈이 도입되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;concurrent.futures 모듈은 비동기적으로 callable을 실행하는 고수준 인터페이스를 제공하기 때문에 &lt;br /&gt;이 모듈을 사용하면 같은 규칙으로 스레드와 멀티 프로세스 코드를 더 쉽게 작성할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Executor&lt;br /&gt;ThreadPoolExecutor &lt;br /&gt;ProcessPoolExecutor&lt;/li&gt;
&lt;li&gt;Future&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&amp;middot; Executor 클래스&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Executor 클래스는 풀 기반으로 작업을 관리하고 비동기적으로 호출을 실행하는 메서드를 제공하는 &lt;br /&gt;추상 클래스다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;초기화 시에 몇 개의 worker가 사용될 것 인지를 정해주면 전달되는 작업들을 큐에 넣고 worker pool에서 &lt;br /&gt;사용 가능한 worker로 하여금 작업을 처리하게 한다. 직접 사용해서는 안되며, 구체적인 하위 클래스를 통해 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Executor의 서브 클래스는 스레드를 사용해서 비동기 호출을 실행할 것인가(&lt;span style=&quot;background-color: #dddddd; color: #ef5369;&quot;&gt;&lt;b&gt;ThreadPoolExecutor&lt;/b&gt;&lt;/span&gt;), &lt;br /&gt;별도의 프로세스를 사용해서 비동기 호출을 실행할 것인가(&lt;span style=&quot;background-color: #dddddd; color: #ef5369;&quot;&gt;&lt;b&gt;ProcessPoolExecutor&lt;/b&gt;&lt;/span&gt;)에 따라 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1) ThreadPoolExecutor&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스레드를 사용하여 작업을 비동기적으로 실행&lt;/li&gt;
&lt;li&gt;쓰레드는 경량이므로 작업 전환 비용이 낮음&lt;/li&gt;
&lt;li&gt;주로 I/O 바운드 작업(예: 데이터베이스 쿼리, 파일 I/O, 네트워크 호출)에 적합&lt;/li&gt;
&lt;li&gt;동일한 프로세스 내에서 스레드를 사용하기 때문에 데이터 공유가 쉽고 오버헤드가 적음&lt;/li&gt;
&lt;li&gt;대기 시간을 줄이고 리소스 사용을 줄일 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2) ProcessPoolExecutor&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스를 사용하여 작업을 비동기적으로 실행&lt;/li&gt;
&lt;li&gt;각 프로세스는 독립적인 메모리 공간을 가지므로 CPU 및 메모리 자원을 더 많이 사용&lt;/li&gt;
&lt;li&gt;CPU 바운드 작업(예: 계산 집약적인 작업)에 적합&lt;/li&gt;
&lt;li&gt;여러 CPU 코어에서 병렬로 작업을 수행할 수 있음&lt;/li&gt;
&lt;li&gt;메모리를 공유하지 않으므로 데이터 공유가 어렵고 통신 비용이 더 듦&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[코드 예시]&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;queries = [Query1, Query2]

start = time.time()

# Query Execution
def execute_query(query_string, database, output_location):
    client = boto3.client('athena', region_name='ap-northeast-2')
    query_start = client.start_query_execution(
        QueryString=query_string,
        QueryExecutionContext={'Database': database},
        ResultConfiguration={'OutputLocation': output_location}
    )
    return query_start
    

with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
# with concurrent.futures.ProcessPoolExecutor(max_workers=2) as executor:
    
    for query in queries:
        executor.submit(execute_query, query, 'db', 's3://temp/')

end = time.time()
&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;size18&quot;&gt;AWS Glue에서 수행한 코드 중의 일부인데 DynamoDB에서 2개의 쿼리를 불러와서 ThreadPool, ProcessPool로 각각 비동기로 처리한 코드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;데이터의 건수는 약 10만건, 테이블의 컬럼 수는 30개 정도이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;쿼리는 left join, full join이 있는 조금 복잡한 쿼리이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;[수행 결과]&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;ThreadPoolExecutor 수행시간 : 132.19272017s&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;ProcessPoolExecutor 수행시간 : 163.20456743s&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;단순 테스트 결과는 위와 같이 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;I/O가 많은 쿼리에는 ThreadPool을 사용해서 Glue Job를 만들어야겠다!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;추가로 Executor 관련 함수와 future 클래스도 곧 내용 정리해서 올릴 예정이다.&lt;/p&gt;</description>
      <category>Python/요약 정리</category>
      <category>AWS Glue 비동기</category>
      <category>concurrent.furue</category>
      <category>executor</category>
      <category>Glue 병렬처리</category>
      <category>processpool</category>
      <category>ThreadPool</category>
      <category>스레드풀</category>
      <category>파이썬 비동기</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/118</guid>
      <comments>https://milkyspace.tistory.com/118#entry118comment</comments>
      <pubDate>Wed, 7 Feb 2024 19:41:56 +0900</pubDate>
    </item>
    <item>
      <title>[GSC] Google Search Console 리디렉션 오류 해결</title>
      <link>https://milkyspace.tistory.com/117</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;티스토리에 쓴 블로그 글을 GSC(Google Search Console)에 등록하려고 봤더니&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1144&quot; data-origin-height=&quot;925&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tVWCw/btsDxzRBYlU/j18LcMwsMxNPI27DKrz0k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tVWCw/btsDxzRBYlU/j18LcMwsMxNPI27DKrz0k1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tVWCw/btsDxzRBYlU/j18LcMwsMxNPI27DKrz0k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtVWCw%2FbtsDxzRBYlU%2Fj18LcMwsMxNPI27DKrz0k1%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;719&quot; height=&quot;581&quot; data-origin-width=&quot;1144&quot; data-origin-height=&quot;925&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이러한 이유는 별도의 모바일 URL이 있는 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;각 데스크톱 URL의 모바일 사용자를 적절한 모바일 URL로 리디렉션 해줘야하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;티스토리에서는 &lt;b&gt;모바일 접속 시 자동으로 모바일 웹으로 전환&lt;/b&gt;되기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;889&quot; data-origin-height=&quot;143&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nCxDG/btsDARQVpdL/kZ6I0ACAUA9xVFJUt2WEgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nCxDG/btsDARQVpdL/kZ6I0ACAUA9xVFJUt2WEgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nCxDG/btsDARQVpdL/kZ6I0ACAUA9xVFJUt2WEgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnCxDG%2FbtsDARQVpdL%2FkZ6I0ACAUA9xVFJUt2WEgK%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;889&quot; height=&quot;143&quot; data-origin-width=&quot;889&quot; data-origin-height=&quot;143&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그래서 해결 방법은 티스토리의 모바일 웹 자동 연결을 해제하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;방법은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;먼저 티스토리에 로그인 하여 &lt;b&gt;[블로그 관리 홈] -&amp;gt;&lt;/b&gt; &lt;b&gt;[꾸미기] -&amp;gt; [모바일]&amp;nbsp;&lt;/b&gt;으로 가서&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;1406&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mwsUd/btsDuUaPG1m/JUK5SK307UjTsD4ZWK09g1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mwsUd/btsDuUaPG1m/JUK5SK307UjTsD4ZWK09g1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mwsUd/btsDuUaPG1m/JUK5SK307UjTsD4ZWK09g1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmwsUd%2FbtsDuUaPG1m%2FJUK5SK307UjTsD4ZWK09g1%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;1406&quot; height=&quot;263&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변경을 하고 다시 GSC로 와서 &lt;b&gt;실시간 테스트&lt;/b&gt;를 클릭하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이전과는 다르게 URL을 Google에 등록할 수 있음 표시로 변경이 되게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그리고 &lt;b&gt;색인 생성 요청&lt;/b&gt;을 클릭해주면 색인 생성이 된 것을 확인 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;681&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bN78Qq/btsDxApmhoA/ogybUk1SfoICnqBi9JWsO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bN78Qq/btsDxApmhoA/ogybUk1SfoICnqBi9JWsO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bN78Qq/btsDxApmhoA/ogybUk1SfoICnqBi9JWsO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbN78Qq%2FbtsDxApmhoA%2FogybUk1SfoICnqBi9JWsO0%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;2004&quot; height=&quot;681&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;681&quot;/&gt;&lt;/span&gt;&lt;/figure&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;나의 경우는 시간이 오래걸리긴 했지만 약 한 달만에 리디렉션 오류가 모두 통과해서 영향 받는 페이지가 0이 되었다!!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;851&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyEsO2/btsENSny1Iy/iAGZfvtQ7SjtOfVHEafXz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyEsO2/btsENSny1Iy/iAGZfvtQ7SjtOfVHEafXz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyEsO2/btsENSny1Iy/iAGZfvtQ7SjtOfVHEafXz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyEsO2%2FbtsENSny1Iy%2FiAGZfvtQ7SjtOfVHEafXz1%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;2004&quot; height=&quot;851&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;851&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>데이터 분석/관련 내용</category>
      <category>GSC</category>
      <category>gsc url 등록</category>
      <category>gsc 리디렉션 오류</category>
      <category>gsc 색인생성</category>
      <category>리디렉션</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/117</guid>
      <comments>https://milkyspace.tistory.com/117#entry117comment</comments>
      <pubDate>Tue, 16 Jan 2024 18:30:02 +0900</pubDate>
    </item>
    <item>
      <title>[Pandas] 데이터프레임 컬럼 SHA256으로 암호화하기</title>
      <link>https://milkyspace.tistory.com/116</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;● SHA-256이란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SHA는 &lt;span style=&quot;color: #343434; text-align: start;&quot;&gt;Secure Hash Algorithm를 의미하고&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SHA-256은 &lt;span style=&quot;color: #343434; text-align: start;&quot;&gt;메시지, 파일, 혹은 데이터 무결성 검증에 널리 사용되는 암호화 해싱 알고리즘(함수)이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #343434; text-align: start;&quot;&gt;변환하기를 원하는 문자들을 256 bit 길이의 key로 변환하며 SHA-256을 사용하면 문자가 조금만 바뀌어도 해시값이 완전히 변한다.&lt;/span&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;span style=&quot;color: #343434; text-align: start;&quot;&gt;공백 하나 느낌표 하나 등만 들어가도 완전히 다른 값으로 암호화되기 때문에 원본 데이터가 중요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;● 사용법&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1704708544962&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import hashlib
import pandas as pd

df = pd.read_excel('hash.xlsx')
df['8digit'] = df['8digit'].astype('str').str.zfill(10)
df&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;span style=&quot;color: #343434; text-align: start;&quot;&gt;우선 해시할 데이터를 불러온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #343434; text-align: start;&quot;&gt;나는 판다스를 사용해서 데이터프레임에 적용시킬 것이기 때문에 데이터 프레임을 만들어주고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #343434; text-align: start;&quot;&gt;끝에 8자리만 해시 해주기 위해 비어있는 자리수는 0으로 채워주기 위해 zfill 함수를 사용했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1704708650424&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df[&quot;hash256&quot;] = df['8digit'].apply(lambda x: hashlib.sha256(str(x).encode()).hexdigest()).str.upper()
df[&quot;hash512&quot;] = df['8digit'].apply(lambda x: hashlib.sha512(str(x).encode()).hexdigest()).str.upper()&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;그리고 해시할 컬럼을 lambda를 이용해서 sha256 알고리즘을 적용시켜주고 데이터 프레임에 해시한 컬럼을 추가해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 대문자로 사용할 것이라서 upper 함수를 이용해서 대문자화 해주었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;323&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7boGF/btsDfptMhDN/FtkNxxwgPPywqgFR99GTa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7boGF/btsDfptMhDN/FtkNxxwgPPywqgFR99GTa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7boGF/btsDfptMhDN/FtkNxxwgPPywqgFR99GTa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7boGF%2FbtsDfptMhDN%2FFtkNxxwgPPywqgFR99GTa1%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;845&quot; height=&quot;323&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;323&quot;/&gt;&lt;/span&gt;&lt;/figure&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;다음과 같이 SHA-256과 SHA-512로 해시된 것을 확인할 수 있다.&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;&lt;/p&gt;</description>
      <category>Python/요약 정리</category>
      <category>Lambda</category>
      <category>sha256</category>
      <category>파이썬 SHA256</category>
      <category>판다스 SHA256</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/116</guid>
      <comments>https://milkyspace.tistory.com/116#entry116comment</comments>
      <pubDate>Mon, 8 Jan 2024 19:18:52 +0900</pubDate>
    </item>
    <item>
      <title>[Pandas] 데이터프레임 컬럼 순서 변경</title>
      <link>https://milkyspace.tistory.com/115</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1699879976985&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;[Pandas] 데이터프레임 groupby로 연산된 컬럼 추가 (transform)&quot; data-og-description=&quot;요즘에 지하철 데이터를 가지고 토이 프로젝트를 진행해보려고 서울시에서 제공하는 오픈 API를 써서 데이터를 수집하고 있다. daily로 역, 호선 별 지하철 승하차 인구 데이터를 불러왔는데 이 &quot; data-og-host=&quot;milkyspace.tistory.com&quot; data-og-source-url=&quot;https://milkyspace.tistory.com/114&quot; data-og-url=&quot;https://milkyspace.tistory.com/114&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/B1al0/hyUu4tr13i/ziFF9bYXTUsPGWc4HxHIVk/img.png?width=725&amp;amp;height=521&amp;amp;face=0_0_725_521,https://scrap.kakaocdn.net/dn/Pd19O/hyUu6dKHu7/M7Gp8wpKHdrw8EkKwv8aWK/img.png?width=725&amp;amp;height=521&amp;amp;face=0_0_725_521,https://scrap.kakaocdn.net/dn/m9NEE/hyUu0EBnLI/08gl7WkQIiGPQdE0jAd8Dk/img.png?width=725&amp;amp;height=521&amp;amp;face=0_0_725_521&quot;&gt;&lt;a href=&quot;https://milkyspace.tistory.com/114&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://milkyspace.tistory.com/114&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/B1al0/hyUu4tr13i/ziFF9bYXTUsPGWc4HxHIVk/img.png?width=725&amp;amp;height=521&amp;amp;face=0_0_725_521,https://scrap.kakaocdn.net/dn/Pd19O/hyUu6dKHu7/M7Gp8wpKHdrw8EkKwv8aWK/img.png?width=725&amp;amp;height=521&amp;amp;face=0_0_725_521,https://scrap.kakaocdn.net/dn/m9NEE/hyUu0EBnLI/08gl7WkQIiGPQdE0jAd8Dk/img.png?width=725&amp;amp;height=521&amp;amp;face=0_0_725_521');&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;[Pandas] 데이터프레임 groupby로 연산된 컬럼 추가 (transform)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;요즘에 지하철 데이터를 가지고 토이 프로젝트를 진행해보려고 서울시에서 제공하는 오픈 API를 써서 데이터를 수집하고 있다. daily로 역, 호선 별 지하철 승하차 인구 데이터를 불러왔는데 이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;milkyspace.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 글에서 groupby, transform으로 연산된 컬럼을 추가하였다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 컬럼 순서를 직접 입력&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 직관적이고 컬럼이 적을 때 사용할 수 있는 방법이다.&lt;/p&gt;
&lt;pre id=&quot;code_1699880234006&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df = df[['USE_MON', 'LINE_NUM', 'SUB_STA_NM', 'FOUR_RIDE_NUM', 'FOUR_ALIGHT_NUM' ,'SUM_RIDE', 'SUM_ALIGHT']]
df&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;699&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/suQKb/btsAeBkB1rF/SlPNzqxEdjyRad73z9Qgkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/suQKb/btsAeBkB1rF/SlPNzqxEdjyRad73z9Qgkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/suQKb/btsAeBkB1rF/SlPNzqxEdjyRad73z9Qgkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsuQKb%2FbtsAeBkB1rF%2FSlPNzqxEdjyRad73z9Qgkk%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;699&quot; height=&quot;381&quot; data-origin-width=&quot;699&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;/figure&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;하지만 .... 이 데이터프레임의 컬럼 갯수는 54개이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;405&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cV6Lly/btsAjjDwV4C/f6KOquK9DuxljEAZKa3hCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cV6Lly/btsAjjDwV4C/f6KOquK9DuxljEAZKa3hCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cV6Lly/btsAjjDwV4C/f6KOquK9DuxljEAZKa3hCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcV6Lly%2FbtsAjjDwV4C%2Ff6KOquK9DuxljEAZKa3hCk%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;405&quot; height=&quot;482&quot; data-origin-width=&quot;405&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;/figure&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;하나씩 직접 입력하려면 .......&amp;nbsp; ㅈㅈ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. slice 이용하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 다른 방법은 컬럼을 리스트로 만들어서 순서를 바꿀 컬럼을 A리스트로 만들고 이 컬럼을 제외한 컬럼을 B 리스트로 만든 뒤에 B + A로 순서를 재배치하여 컬럼순서를 변경하는 방법이다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwFo4V/btsAaN0cdWT/b3DACTQtx7hFfc7GZXXNA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwFo4V/btsAaN0cdWT/b3DACTQtx7hFfc7GZXXNA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwFo4V/btsAaN0cdWT/b3DACTQtx7hFfc7GZXXNA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwFo4V%2FbtsAaN0cdWT%2Fb3DACTQtx7hFfc7GZXXNA0%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;499&quot; height=&quot;311&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;311&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 순서를 변경할 컬럼만 리스트로 만들어준다.&lt;/p&gt;
&lt;pre id=&quot;code_1699880811861&quot; class=&quot;stylus&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;a = df.columns[-3:-2].to_list()
print('a : ', a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;groovy&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;code&gt;a :  ['WORK_DT']&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;
&lt;pre id=&quot;code_1699880863670&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ex_a = df.drop(columns = df.columns[[-3]]).columns[:].to_list()
#  ==   ex_a = df.drop(['WORK_DT'], axis=1).columns[:].to_list()
print('ex_a : ', ex_a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;ex_a :  ['USE_MON', 'LINE_NUM', 'SUB_STA_NM', 'FOUR_RIDE_NUM', 'FOUR_ALIGHT_NUM',  ... 'THREE_RIDE_NUM', 'THREE_ALIGHT_NUM', 'SUM_RIDE', 'SUM_ALIGHT']&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;마지막으로 a 리스트를 ex_a 리스트 뒤에 붙여주어 컬럼의 순서를 변경한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699881000462&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;reorder = ex_a + a
print('reorder : ', reorder)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;python&quot; style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;reorder :  ['USE_MON', 'LINE_NUM', 'SUB_STA_NM', 'FOUR_RIDE_NUM', 'FOUR_ALIGHT_NUM', ... 'THREE_RIDE_NUM', 'THREE_ALIGHT_NUM', 'SUM_RIDE', 'SUM_ALIGHT', 'WORK_DT']&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;컬럼 리스트를 확인하면 a리스트(WORK_DT)가 가장 뒤로 위치해있는 것을 확인 할 수 있다.&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;pre id=&quot;code_1699881064470&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;a = df.columns[-3:-2].to_list()

ex_a = df.drop(columns = df.columns[[-3]]).columns[:].to_list()
#  ==   ex_a = df.drop(['WORK_DT'], axis=1).columns[:].to_list()

reorder = ex_a + a

df = df[reorder]
df&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;626&quot; data-origin-height=&quot;363&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/epUr9c/btsAiEHWLjY/oaPCRkWwOaSXomL7DtqN80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/epUr9c/btsAiEHWLjY/oaPCRkWwOaSXomL7DtqN80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/epUr9c/btsAiEHWLjY/oaPCRkWwOaSXomL7DtqN80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FepUr9c%2FbtsAiEHWLjY%2FoaPCRkWwOaSXomL7DtqN80%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;626&quot; height=&quot;363&quot; data-origin-width=&quot;626&quot; data-origin-height=&quot;363&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Python/요약 정리</category>
      <category>pandas 컬럼 순서 변경</category>
      <category>컬럼 삭제</category>
      <category>컬럼 순서 변경</category>
      <category>컬럼 재배치</category>
      <author>밀뿌</author>
      <guid isPermaLink="true">https://milkyspace.tistory.com/115</guid>
      <comments>https://milkyspace.tistory.com/115#entry115comment</comments>
      <pubDate>Mon, 13 Nov 2023 22:13:53 +0900</pubDate>
    </item>
  </channel>
</rss>