<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Explore, Dream, Discover</title>
        <description></description>
        <link>https://0leaf.github.io/</link>
        <atom:link href="https://0leaf.github.io feed.xml" rel="self" type="application/rss+xml" />
        <pubDate>Wed, 28 May 2025 12:24:21 +0000</pubDate>
        <lastBuildDate>Wed, 28 May 2025 12:24:21 +0000</lastBuildDate>
        <generator>Jekyll v3.10.0</generator>
        
        <item>
            <title>redis - sharding</title>
            <description>&lt;h1 id=&quot;tl-dr&quot;&gt;TL; DR&lt;/h1&gt;
&lt;p&gt;Sharding은 수평분할과 관련된 아키텍쳐 패턴입니다.
수평 확장과 단일 장애점(SPOF) 문제를 개선하기에 용이하지만, 그만큼 올바르게 동작하도록 구성하려면 많은 비용과 노력이 필요합니다.&lt;/p&gt;
&lt;h1 id=&quot;what-is-sharding&quot;&gt;What is Sharding?&lt;/h1&gt;
&lt;p&gt;각 파티션이 동일한 스키마와 열을 갖지만 그 데이터인 행은 다르게 나누어 갖습니다.
&lt;img src=&quot;https://i.imgur.com/8nXGQga.png&quot; alt=&quot;&quot; /&gt;
위 그림이 이 내용을 쉽게 설명하고 있는데, Sharding은 Horizontal Partitions 방식으로 데이터를 나누어 저장하는 것을 의미합니다.&lt;/p&gt;

&lt;h1 id=&quot;pros--cons&quot;&gt;Pros &amp;amp; Cons&lt;/h1&gt;
&lt;h2 id=&quot;pros&quot;&gt;Pros&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Scale out에 용이합니다.&lt;/li&gt;
  &lt;li&gt;큰 테이블을 여러개로 샤딩하면 쿼리 성능이 올라갈 수 있습니다.&lt;/li&gt;
  &lt;li&gt;특정 Sharding된 영역에 문제 생긴다고 해도, 전체 서비스 장애가 발생하는 것을 막을 수 있습니다.
    &lt;h2 id=&quot;cons&quot;&gt;Cons&lt;/h2&gt;
  &lt;/li&gt;
  &lt;li&gt;Sharding을 제대로 구현하고 적용하는데 어려움이 많습니다. 잘못 구성하게 되면 데이터 손실등이 발생할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;샤딩 알고리즘 등에 따라 샤드가 불균해질 수 있고 이를 관리해줘야 할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;샤딩된 구조를 단일 아키텍쳐로 돌리기 어렵습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;sharding-strategies&quot;&gt;Sharding Strategies&lt;/h1&gt;
&lt;h3 id=&quot;키-기반-샤딩key-based-sharding&quot;&gt;키 기반 샤딩(Key-based Sharding)&lt;/h3&gt;
&lt;p&gt;• &lt;strong&gt;설명&lt;/strong&gt;: 각 데이터 항목에 대해 특정 키(예: 해시 함수 결과)를 사용하여 샤드를 결정합니다.
• &lt;strong&gt;특징&lt;/strong&gt;: 해시 함수에 의해 고르게 분포되도록 설계되어 있어, 모든 샤드에 걸쳐 데이터가 균등하게 분포됩니다.&lt;/p&gt;
&lt;h3 id=&quot;범위-기반-샤딩range-based-sharding&quot;&gt;범위 기반 샤딩(Range-based Sharding)&lt;/h3&gt;
&lt;p&gt;• &lt;strong&gt;설명&lt;/strong&gt;: 특정 범위의 값을 기반으로 데이터를 샤드에 분할합니다.
• &lt;strong&gt;특징&lt;/strong&gt;: 연속적인 데이터 범위가 같은 샤드에 저장되므로, 특정 범위의 데이터를 조회할 때 효율적입니다.&lt;/p&gt;
&lt;h3 id=&quot;디렉토리-기반-샤딩directory-based-sharding&quot;&gt;디렉토리 기반 샤딩(Directory-based Sharding)&lt;/h3&gt;
&lt;p&gt;• &lt;strong&gt;설명&lt;/strong&gt;: 샤딩 디렉토리라는 매핑 테이블을 사용하여 데이터 항목이 어떤 샤드에 있는지 관리합니다.
• &lt;strong&gt;특징&lt;/strong&gt;: 유연하지만 디렉토리 테이블을 관리하기 위한 오버헤드가 발생할 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;https://www.digitalocean.com/community/tutorials/understanding-database-sharding&lt;/li&gt;
&lt;/ul&gt;
</description>
            <pubDate>Sun, 07 Jul 2024 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/redis/sharding/</link>
            <guid isPermaLink="true">https://0leaf.github.io/redis/sharding/</guid>
            
            <category>Sharding</category>
            
        
            <category>Redis</category>
            
        </item>
        
        <item>
            <title>redis - hashtag</title>
            <description>&lt;h1 id=&quot;tldr&quot;&gt;TL;DR&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;redis cluster mode에서 MGET으로 데이터를 가져오려면, 저장할때 key에 hashtag인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{}&lt;/code&gt;를 포함해주어야 합니다.
    &lt;h1 id=&quot;hashslot&quot;&gt;Hashslot&lt;/h1&gt;
    &lt;blockquote&gt;
      &lt;p&gt;CROSSSLOT Keys in request don’t hash to the same slot&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;위와 같은 에러 메세지를 받았다면, cluster mode로 실행중인 redis에 &lt;a href=&quot;https://redis.io/docs/latest/commands/mget/&quot;&gt;MGET&lt;/a&gt;등으로 한번에 많은 요청을 받으려고 시도 할 때 발생합니다.
&lt;a href=&quot;https://repost.aws/knowledge-center/elasticache-crossslot-keys-error-redis&quot;&gt;aws 질문글&lt;/a&gt; 중에 관련된 내용이 있는데, 문제를 해결하기 위해서 키 내에 hashslot 명시하는 기준인 hashtag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{}&lt;/code&gt; 를 포함하면 됩니다.
하지만, 기본적으로 cluster mode에서 hashslot이 저장되는 방식에 대한 이해를 바탕으로 hashslot을 설정하는 것이 좋습니다.&lt;/p&gt;

&lt;p&gt;아래와 같은 key를 예시로 들어봅니다.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. categories:movies:{1}:name
2. categories:{movies}:1:name
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;cluster mode의 경우 hashslot을 n개의 shard로 나누어 관리하므로 같은 공간에 저장되는 것이 좋습니다. 담고자 하는 정보가 동일한 hashslot에 묶여 함께 저장되길 바라는 곳에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{}&lt;/code&gt;를 포함해야 합니다.&lt;/p&gt;

&lt;p&gt;따라서, 특정 영화의 여러 속성을 한 번에 가져오는 경우가 더 일반적이라면 첫 번째 구조를 추천합니다.
그러나 범주 내의 여러 영화를 한 번에 가져오는 경우가 더 일반적이라면 두 번째 구조를 사용할 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;refrences&quot;&gt;Refrences&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;https://redis.io/docs/latest/develop/use/keyspace/&lt;/li&gt;
  &lt;li&gt;https://repost.aws/knowledge-center/elasticache-crossslot-keys-error-redis&lt;/li&gt;
  &lt;li&gt;https://redis.io/docs/latest/operate/oss_and_stack/reference/cluster-spec/&lt;/li&gt;
&lt;/ul&gt;

</description>
            <pubDate>Sun, 07 Jul 2024 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/redis/redis-hashslot/</link>
            <guid isPermaLink="true">https://0leaf.github.io/redis/redis-hashslot/</guid>
            
            <category>Redis</category>
            
            <category>Key</category>
            
            <category>Hashtag</category>
            
        
            <category>Redis</category>
            
        </item>
        
        <item>
            <title>go-redis - go-redis v9 에서 hash 타입을 다루는 방법</title>
            <description>&lt;h1 id=&quot;tldr&quot;&gt;TL;DR&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;go-reds v9 버전부터
    &lt;ul&gt;
      &lt;li&gt;hashset을 저장할때 interface로 전달하지 않고 type 을 전달해도 저장됩니다.&lt;/li&gt;
      &lt;li&gt;역직렬화 과정에서도 scan을 통해 HGetAll, MGet 등을 type으로 unmarshal 할 수 있습니다.
        &lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;
        &lt;p&gt;go-redis/v9 버전 이상에서 사용 가능한 기능들을 발견하여, 용례를 정리하고 성능 등 문제가 없는지 비교해봅니다.&lt;/p&gt;
        &lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;
        &lt;h3 id=&quot;go-redisv8-이하&quot;&gt;go-redis/v8 이하&lt;/h3&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;HashSet
    &lt;ul&gt;
      &lt;li&gt;map interface를 만들어서 저장해야 한다.&lt;/li&gt;
      &lt;li&gt;type을 만들어서 전달할 경우 아래의 에러 메세지를 받는다.
        &lt;ul&gt;
          &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redis: can&apos;t marshal main.User (implement encoding.BinaryMarshaler)&lt;/code&gt;
```go&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;func populateDataV8(rdb *redisv8.Client, n int) {
	for i := 1; i &amp;lt;= n; i++ {
		user := User{
			Name:    fmt.Sprintf(“User%d”, i),
			Age:     20 + (i % 30),
			Email:   fmt.Sprintf(“user%d@example.com”, i),
			Country: “Country” + strconv.Itoa(i%10),
		}&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	userMap := map[string]interface{}{
		&quot;name&quot;:    user.Name,
		&quot;age&quot;:     user.Age,
		&quot;email&quot;:   user.Email,
		&quot;country&quot;: user.Country,
	}

	err := rdb.HSet(ctx, fmt.Sprintf(&quot;user:%d&quot;, i), userMap).Err()
	if err != nil {
		log.Fatalf(&quot;Failed to set user %d: %v&quot;, i, err)
	}
} }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
- HGetAll
	- map interface로 전달받은 값을 map을 참조하여 결과를 구성
```go
func fetchDataV8(rdb *redisv8.Client, n int) {
	for i := 1; i &amp;lt;= n; i++ {
		fields, err := rdb.HGetAll(ctx, fmt.Sprintf(&quot;user:%d&quot;, i)).Result()
		if err != nil {
			log.Fatalf(&quot;Failed to get user %d: %v&quot;, i, err)
		}

		var user User
		user.Name = fields[&quot;name&quot;]
		user.Age, _ = strconv.Atoi(fields[&quot;age&quot;])
		user.Email = fields[&quot;email&quot;]
		user.Country = fields[&quot;country&quot;]
		// Print for debug purpose, comment out during benchmarking
		// fmt.Printf(&quot;user:%d - %+v\n&quot;, i, user)
	}
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;go-redisv9-이상&quot;&gt;go-redis/v9 이상&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;HashSet
    &lt;ul&gt;
      &lt;li&gt;type으로 생성된 결과를 그대로 전달해도 저장된다.&lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;string, int 여러 타입이 섞여 전달 될 수 있다.
```go
  for i := 1; i &amp;lt;= n; i++ {
  user := User{
      Name:    fmt.Sprintf(“User%d”, i),
      Age:     20 + (i % 30),
      Email:   fmt.Sprintf(“user%d@example.com”, i),
      Country: “Country” + strconv.Itoa(i%10),
  }&lt;/p&gt;

        &lt;p&gt;err := rdb.HSet(ctx, fmt.Sprintf(“user:%d”, i), user).Err()
  if err != nil {
      log.Fatalf(“Failed to set user %d: %v”, i, err)
  }
  }&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- HGetAll
	- Scan 을 통해 타입에 맞도록 결과를 unmarshal 한다.
```go

func fetchDataV9(rdb *redisv9.Client, n int) {
	for i := 1; i &amp;lt;= n; i++ {
		res := rdb.HGetAll(ctx, fmt.Sprintf(&quot;user:%d&quot;, i))

		var user User
		if err := res.Scan(&amp;amp;user); err != nil {
			log.Fatalf(&quot;Failed to get user %d: %v&quot;, i, err)
		}
		// Print for debug purpose, comment out during benchmarking
		// fmt.Printf(&quot;user:%d - %+v\n&quot;, i, user)
	}
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;benchmark&quot;&gt;Benchmark&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;go-redis v8, v9의 hash저장, 조회 관련된 operation 을 수행하는 동작을 테스트한 결과는 아래와 같습니다.&lt;/li&gt;
  &lt;li&gt;v9이 v8에 비해 성능면에서는 다소 느려진 점이 있으나, 무시해도 될만한 수준의 차이입니다.
    &lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RUN&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;BenchmarkPopulateDataV8&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkPopulateDataV8&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkPopulateDataV8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;            &lt;span class=&quot;m&quot;&gt;20&lt;/span&gt;          &lt;span class=&quot;m&quot;&gt;57818098&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;           &lt;span class=&quot;m&quot;&gt;99482&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;       &lt;span class=&quot;m&quot;&gt;2010&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allocs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RUN&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;BenchmarkPopulateDataV9&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkPopulateDataV9&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkPopulateDataV9&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;            &lt;span class=&quot;m&quot;&gt;21&lt;/span&gt;          &lt;span class=&quot;m&quot;&gt;67450760&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;           &lt;span class=&quot;m&quot;&gt;69820&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;       &lt;span class=&quot;m&quot;&gt;2213&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allocs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RUN&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;BenchmarkFetchDataV8&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkFetchDataV8&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkFetchDataV8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;               &lt;span class=&quot;m&quot;&gt;18&lt;/span&gt;          &lt;span class=&quot;m&quot;&gt;60724053&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;           &lt;span class=&quot;m&quot;&gt;67652&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;       &lt;span class=&quot;m&quot;&gt;1716&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allocs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RUN&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;BenchmarkFetchDataV9&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkFetchDataV9&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkFetchDataV9&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;               &lt;span class=&quot;m&quot;&gt;18&lt;/span&gt;          &lt;span class=&quot;m&quot;&gt;62911891&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;           &lt;span class=&quot;m&quot;&gt;71903&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;       &lt;span class=&quot;m&quot;&gt;2030&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allocs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;redis에 데이터를 저장할때, type을 지정해두고 값을 저장, 조회한다면 가독성과 코드 구조가 많이 개선될 수 있을 것 같습니다.
무조건 버전을 올리기보다, 필요한 기능으로 적용이 필요할때 올리면 좋을 것 같습니다.&lt;/p&gt;
&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/redis/go-redis/issues/672&quot;&gt;https://github.com/redis/go-redis/issues/672&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;https://github.com/redis/go-redis/blob/f8cbf483f4a193d441fac2cf14be3d84783848c6/example_test.go#L281&lt;/li&gt;
  &lt;li&gt;https://github.com/redis/go-redis/discussions/2454&lt;/li&gt;
  &lt;li&gt;https://github.com/redis/go-redis&lt;/li&gt;
&lt;/ul&gt;
</description>
            <pubDate>Sun, 07 Jul 2024 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/redis/go-redis-new-method-for-storing-and-retrieving-hash-type/</link>
            <guid isPermaLink="true">https://0leaf.github.io/redis/go-redis-new-method-for-storing-and-retrieving-hash-type/</guid>
            
            <category>Redis</category>
            
            <category>Go-redis</category>
            
        
            <category>Redis</category>
            
        </item>
        
        <item>
            <title>redis - cluster mode</title>
            <description>&lt;p&gt;redis cluster mode에 대해 이해하고, 현재 구성된 redis 환경 정보를 확인하는 방법에 대해 알아봅니다.&lt;/p&gt;

&lt;h2 id=&quot;what-is-cluster-mode&quot;&gt;What is Cluster Mode?&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;p&gt;redis 클러스터는 단순히 &lt;a href=&quot;https://www.digitalocean.com/community/tutorials/understanding-database-sharding&quot;&gt;데이터 분할 전략 입니다.&lt;/a&gt; 여러 redis 노드에 걸쳐 데이터를 자동으로 분할합니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;redis는 주노드(primary node)와 복제 노드(replica node)로 구성하는 것이 일반적이며, 이런 구성을 shard
로 여러 벌 준비하여 data partitioning이 될 수 있는 구성이 클러스터 모드(cluster mode) 입니다.&lt;/p&gt;

&lt;p&gt;shading으로 데이터는 수평분할 어 저장됨에 따라 scale out, 단일 장애 지점(SPOF) 개선, 성능 향상 등의 이점을 얻을 수 있으며, 클러스터 구조에 따라 복잡성이 증가할 수 있으므로 상황에 따라 적절한 구조를 선택하는 것이 필요합니다.
&lt;img src=&quot;https://i.imgur.com/435CqKW.png&quot; alt=&quot;&quot; /&gt;
(출처:&lt;a href=&quot;https://aws.amazon.com/ko/blogs/database/work-with-cluster-mode-on-amazon-elasticache-for-redis/&quot;&gt;How to work with Cluster Mode on Amazon ElastiCache for Redis&lt;/a&gt;)
&lt;img src=&quot;https://i.imgur.com/cQ60lqb.png&quot; alt=&quot;&quot; /&gt;aws article &lt;a href=&quot;https://aws.amazon.com/ko/blogs/database/work-with-cluster-mode-on-amazon-elasticache-for-redis/&quot;&gt;How to work with Cluster Mode on Amazon ElastiCache for Redis&lt;/a&gt;에서 다루고 있는 용어와 &lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/&quot;&gt;redis.io 문서&lt;/a&gt;에서 표현되는 용어가 미묘하게 다르지만, 위 이미지와 같이 비슷한 구조로 나누어 설명하고 있는것을 알 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;redis-mode-별-차이-비교&quot;&gt;Redis Mode 별 차이 비교&lt;/h2&gt;
&lt;p&gt;aws article에서 각 mode별 구성에 대해 잘 정리한 표가 있어서 가져왔습니다. 앞서 언급한 내용과 같이 각각의 모드는 redis.io에서 언급하고 있는 standalone, sentienl, cluster mode와 유사한 범주로 언급하고 있음을 알 수 있습니다. 
&lt;img src=&quot;https://i.imgur.com/UKhYAt4.png&quot; alt=&quot;&quot; /&gt;
(출처:&lt;a href=&quot;https://aws.amazon.com/ko/blogs/database/work-with-cluster-mode-on-amazon-elasticache-for-redis/&quot;&gt;How to work with Cluster Mode on Amazon ElastiCache for Redis&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;수평 확장을 통해 성능상의 이점 등을 얻기 위해선 결국 data partitioning을 통한 sharding이 되어야 하는데, redis의 경우 hashslot을 통해 파티셔닝을 처리하는 것을 아래 그림에서 설명하고 있습니다.
&lt;img src=&quot;https://i.imgur.com/PwcCqGW.png&quot; alt=&quot;&quot; /&gt;
(출처:&lt;a href=&quot;https://aws.amazon.com/ko/blogs/database/work-with-cluster-mode-on-amazon-elasticache-for-redis/&quot;&gt;How to work with Cluster Mode on Amazon ElastiCache for Redis&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;따라서 aws managed 서비스인 elastiCache를 사용하든 별도로 구성된 cluster mode를 사용하든 현재 구성된 클러스터 구조를 확인하고 이해하고 있어야 sharding을 통해 얻을수 있는 이점과, 관리 포인트를 이해하고 주의할 수 있을 것 입니다.&lt;/p&gt;

&lt;h1 id=&quot;redis-cli로-cluster-mode-환경-살펴보기&quot;&gt;redis-cli로 cluster mode 환경 살펴보기&lt;/h1&gt;
&lt;p&gt;redis-cli를 설치하려면 환경에 맞게 &lt;a href=&quot;https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/&quot;&gt;링크&lt;/a&gt; 에서 확인하고 설치해줍니다.&lt;/p&gt;

&lt;p&gt;현재 실행된 환경을 확인하는 방법은 다음과 같습니다.&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Connect to Redis server&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;redis-cli &lt;span class=&quot;nt&quot;&gt;-h&lt;/span&gt; 127.0.0.1 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 6379
&lt;span class=&quot;c&quot;&gt;# Check if cluster mode is enabled&lt;/span&gt;
CONFIG GET cluster-enabled
&lt;span class=&quot;c&quot;&gt;# Get all configuration settings&lt;/span&gt;
CONFIG GET &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Get cluster nodes information&lt;/span&gt;
CLUSTER NODES
&lt;span class=&quot;c&quot;&gt;# Get cluster info&lt;/span&gt;
CLUSTER INFO
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;standalone 모드로 실행한 경우 아래와 같이 표시됩니다.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;127.0.0.1:6379&amp;gt; CONFIG GET cluster-enabled
1) &quot;cluster-enabled&quot;
2) &quot;no&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;aws elastiCache로 redis cluster를 구성한 경우 아래와 같은 방법으로 정보를 확인할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;xxx.cache.amazonaws.com:6379&amp;gt; CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:2
cluster_size:1
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;xxx.cache.amazonaws.com:6379&amp;gt; CLUSTER NODES
{slave-node-id} 192.168.xxx.xxx:6379@1122 slave {master-node-id} 0 1720327133306 5 connected
{master-node-id} 192.168.xxx.xxx:6379@1122 myself,master - 0 1700412779000 5 connected 0-16383
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;https://aws.amazon.com/ko/blogs/database/work-with-cluster-mode-on-amazon-elasticache-for-redis/&lt;/li&gt;
  &lt;li&gt;https://ot-container-kit.github.io/redis-operator/guide/setup.html?ref=breezymind.com#redis-cluster&lt;/li&gt;
  &lt;li&gt;https://www.digitalocean.com/community/tutorials/understanding-database-sharding&lt;/li&gt;
&lt;/ul&gt;
</description>
            <pubDate>Sat, 06 Jul 2024 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/redis/redis-cluster-mode/</link>
            <guid isPermaLink="true">https://0leaf.github.io/redis/redis-cluster-mode/</guid>
            
            <category>Redis</category>
            
            <category>Redis-Cluster</category>
            
        
            <category>Redis</category>
            
        </item>
        
        <item>
            <title>redis - key rules</title>
            <description>&lt;h2 id=&quot;tl-dr&quot;&gt;TL; DR&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;계층 구조를 표현하기 위한 delimiter를 정합니다 (“:”)&lt;/li&gt;
  &lt;li&gt;쉽게 이해 가능하기 위한 길이로 key를 구성합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;keyspace&quot;&gt;Keyspace&lt;/h2&gt;

&lt;p&gt;Redis 키는 binary safe합니다. 즉, “foo”와 같은 문자열부터 JPEG 파일의 내용까지 모든 바이너리 시퀀스를 키로 사용할 수 있으며, 빈 문자열도 유효한 키입니다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;매우 길거나, 짧은 키는 좋지 않습니다.
    &lt;ul&gt;
      &lt;li&gt;“user:1000:followers”와 “u1000flw”를 비교하자면 “user:1000:followers” 이 더 나은 옵션이며 적절한 키 길이의 균형을 잡는것이 필요합니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;스키마를 고수하려고 노력하세요.
    &lt;ul&gt;
      &lt;li&gt;예를 들어 “object-type:id”는 “user:1000”처럼 좋은 아이디어입니다. .이나 -는 “comment:4321:reply.to” 또는 “comment:4321:reply-to”처럼 여러 단어로 구성된 필드에 자주 사용될 수 있습니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;허용되는 최대 키 크기는 512MB입니다.&lt;/li&gt;
&lt;/ul&gt;
</description>
            <pubDate>Sun, 30 Jun 2024 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/redis/redis-key-rules/</link>
            <guid isPermaLink="true">https://0leaf.github.io/redis/redis-key-rules/</guid>
            
            <category>Redis</category>
            
            <category>Key</category>
            
            <category>Convention</category>
            
        
            <category>Redis</category>
            
        </item>
        
        <item>
            <title>Kong Gateway 4. Kong Auth Plugin 연동하기</title>
            <description>&lt;p&gt;Kong, Plugin, Authorization에 대한 설명 및 구성 과정을 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;kong-gateway-4-kong-auth-plugin-연동&quot;&gt;Kong Gateway #4 Kong Auth Plugin 연동&lt;/h1&gt;

&lt;h1 id=&quot;0-들어가기-전에&quot;&gt;0. 들어가기 전에&lt;/h1&gt;

&lt;p&gt;kong gateway는 기본적으로 인증 관련된 플러그인들을 기본적으로 제공합니다. 인증 및 인가에 대해서 간단히 알아보고 kong이 제공하는 몇가지 인증 플러그인들을 사용해보고 그 과정을 기술해보려고 합니다. consumer나 upstream 등을 상세하게 설정할 수 있으나, 본 글에서는 사용법과 과정을 살펴보는 것이 주된 목적이므로 자세한 과정을 생략함을 말씀드립니다.&lt;/p&gt;

&lt;h1 id=&quot;1-authentication인증-vs-authorization인가&quot;&gt;1. Authentication(인증) vs Authorization(인가)&lt;/h1&gt;

&lt;p&gt;인증과 인가에 대한 용어는 많이들 헷갈리곤 합니다. 주로 인증을 이야기할때 인가를 포함하여 이야기하는 경우가 많은 것 같습니다. 따라서 조금 헷갈리시는 분들은 &lt;a href=&quot;https://www.okta.com/identity-101/authentication-vs-authorization/&quot;&gt;링크&lt;/a&gt; 글을 읽어보시면 이해하시는데 많은 도움이 될 것 같습니다.&lt;/p&gt;

&lt;p&gt;이 글에서는 간단한 이해를 돕기 위해 짧은 설명을 덧붙이도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881195-dea0b835-2785-4c57-a36c-4a2d8cbeab79.png&quot; alt=&quot;Untitled&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Authentication(인증)은 회원 로그인과 같은 절차를 통해 해당 사용자에 대한 신원 확인을 하는 과정을 의미합니다. 보통 Google의 로그인 화면과 같이 사용자의 정보를 바탕으로 접근 가능한 사용자인지를 인증합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881199-79d08c02-87a1-4600-a48d-d0fe8443fef6.png&quot; alt=&quot;Untitled 1&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Authorization(인가)은 인증 과정에서 해당  어느 기능들을 사용할 수 있는지에 대한 권한을 확인하고 인가하는 과정을 의미합니다.&lt;/p&gt;

&lt;h1 id=&quot;2-인증-및-인가-과정&quot;&gt;2. 인증 및 인가 과정&lt;/h1&gt;

&lt;p&gt;여러 인증 방식중에 풍부한 스펙을 가진 OAuth2.0을 설명하기 위한 &lt;a href=&quot;https://developer.okta.com/blog/2017/06/21/what-the-heck-is-oauth&quot;&gt;글&lt;/a&gt;에 포함된 그림 중 일부를 발췌해 설명하도록 하겠습니다. 참고로 OAuth2.0은 여러 grant type에 따라 인증 절차가 다양합니다. 이에 대해서는 자세히 다루지 않고 생략하며, 조금 추상적인 단계로 설명을 이어나가보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881404-cacb843d-d0d2-4ca4-ae3a-4c3069bf81e9.png&quot; alt=&quot;Untitled 2&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;최종 목적은 Client가 ResourceServer에 접근하는 것이 목표이며, 이를 위해 Resource Server에 접근을 하기 위한 필수 조건인 token을 발급받는 과정이 필요합니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;1,2번 과정을 통해 client는 로그인 혹은 사용자 정보를 통해 인증을 진행합니다. [인증]&lt;/li&gt;
  &lt;li&gt;3번 과정을 통해 인증이 성공할 경우, ResourceOwner(사용자) 에게 특정 권한에 허용해도 괜찮은지 허락을 구합니다. [인가]&lt;/li&gt;
  &lt;li&gt;4번 과정으로 client에게 Resource에 접근 가능한 토큰을 부여합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;위 흐름은 대략적인 내용이고, 인증 유형에 따라 달라지는 내용이라고 할 수 있습니다. 하지만 추상화된 단계로 살펴보면 client는 인증 서버에게 “로그인” 과 같은 절차를 통해 사용자 정보를 전달하고 유효한 사용자 정보라면&lt;/p&gt;

&lt;p&gt;해당 사용자가 어떤 리소스에 접근 가능한지를 인가하는 과정을 거쳐 토큰을 받습니다.&lt;/p&gt;

&lt;p&gt;그리고 그 토큰은 Resource Server에 접근 가능하기 위한 필수 요건이 됩니다.&lt;/p&gt;

&lt;p&gt;이 과정은 OAuth에 대한 인증/인가 과정이며, 인증 유형에 따라 조금씩 다를 수 있다는 것을 다시 한번 말씀드립니다.&lt;/p&gt;

&lt;p&gt;이후 살펴볼 플러그인 테스트는 kong에 사용자 인증 정보를 미리 등록시켜놓고 (ID/PW, API Key 등) API 서비스와 연동시키는 과정과 clinet가 해당 인증 정보를 바탕으로 요청하는 방법에 대해서 기술하려고 합니다.&lt;/p&gt;

&lt;h1 id=&quot;3-인증-플러그인-종류&quot;&gt;3. 인증 플러그인 종류&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881410-fe442a45-b527-45ee-9f67-02e80509e3a5.png&quot; alt=&quot;Untitled 3&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 사진은 konga 에서 캡쳐한 사진으로 kong에서 기본적으로 제공하는 Authentication 플러그인들을 보여줍니다. 이 중에 몇가지를 선택하여 사용하는 과정을 다뤄보겠습니다.&lt;/p&gt;

&lt;p&gt;더 많은 플러그인들은 &lt;a href=&quot;https://docs.konghq.com/hub/&quot;&gt;공식 홈페이지 플러그인 리스트&lt;/a&gt; 에서 확인 가능하며, 이후 다른 글에서 custom plugin 등을 구성하고 연동하는 과정도 다뤄보도록 하겠습니다.&lt;/p&gt;

&lt;h1 id=&quot;4-기본-제공-플러그인-연동&quot;&gt;4. 기본 제공 플러그인 연동&lt;/h1&gt;

&lt;h2 id=&quot;41-사용할-예제-및-준비&quot;&gt;4.1. 사용할 예제 및 준비&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881413-e0b98698-2212-41cb-b670-b645c6b34c8a.png&quot; alt=&quot;Untitled 4&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이전 글에서도 사용했던 이미지를 가져왔습니다. 보통은 api gateway 내부의 upstream 서버로 요청하는 시나리오가 적당하지만, 기능을 테스트 하는것에 목적을 두기 위해 쉬운 예제로 google.com, naver.com. daum.net으로 요청하는 API를 두고 설명해보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://0leaf.github.io/kong/Kong-Gateway-2-Kong-on-kubernetes-(Kong,Konga)/#6-api-%EC%84%A4%EC%A0%95-%ED%85%8C%EC%8A%A4%ED%8A%B8&quot;&gt;konga를 통해 API Routing 구성 글&lt;/a&gt; 를 참고하시면 기본 설정을 마치실 수 있습니다.&lt;/p&gt;

&lt;p&gt;또한 &lt;a href=&quot;https://0leaf.github.io/kong/Kong-Gateway-3-Kong-Admin-%EC%9C%BC%EB%A1%9C-API-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0/&quot;&gt;Kong admin API로도 구성&lt;/a&gt;할 수 있지만, 이해를 돕기 위해 Konga 툴로 이용해 진행하는 과정을 기술하겠습니다.&lt;/p&gt;

&lt;p&gt;아래 절차들은 konga 화면에서 Routes - Plugins 화면에서 플러그인들을 추가할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881415-bb981972-5d81-47f2-ba17-6fa49cc36bd0.png&quot; alt=&quot;Untitled 5&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;또한 인증 과정은 앞서 말씀드린 내용처럼 요청자의 신원을 확인할 수 있어야 하는데, 예상되는 요청자를 Consumer를 통해 등록할 수 있습니다. 예를들어 G 라는 Consumer를 등록해놓으면, G만 Google 에 요청할 수 있도록 token을 발급해주는 과정을 말합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881417-41bd6a7b-c9dc-418f-945b-cfa848fbe229.png&quot; alt=&quot;Untitled 6&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 사진처럼 G, K, N Consumer를 미리 구성해둡니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881419-78410fce-2cfc-4c18-a386-d401ecb68a63.png&quot; alt=&quot;Untitled 7&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;생성 후 해당 Consumer에게 적용할 Credentials를 설정할 수 있는데, 이 글에선 Basic, API Keys, HMAC 을 각각 Naver, Kakao, Google에 적용해보도록 할 예정입니다.&lt;/p&gt;

&lt;h2 id=&quot;42-인증-유형별-요청-방법&quot;&gt;4.2. 인증 유형별 요청 방법&lt;/h2&gt;

&lt;p&gt;인증 플러그인들을 원하는 서비스에 붙일 경우 client가 요청하는 방법들이 각각 다릅니다. 이후 단계를 진행하기에 앞서 각 인증별로 정보를 전달하는 방법을 참고하시면 좋을 것 같습니다.&lt;/p&gt;

&lt;h3 id=&quot;basic-auth&quot;&gt;&lt;a href=&quot;https://docs.konghq.com/hub/kong-inc/basic-auth/&quot;&gt;basic-auth&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;header 방식 - ex) Authorization: Basic dGVzdDphc2Rm&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.blitter.se/utils/basic-authentication-header-generator&quot;&gt;basic auth header generator&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;key-auth&quot;&gt;&lt;a href=&quot;https://docs.konghq.com/hub/kong-inc/key-auth-enc/#upstream-headers&quot;&gt;key-auth&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;query param 방식 등 - ex) ?apikey=dGVzdDphc2Rm&lt;/p&gt;

&lt;h3 id=&quot;hmac-auth&quot;&gt;&lt;a href=&quot;https://docs.konghq.com/hub/kong-inc/hmac-auth&quot;&gt;hmac-auth&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;header 방식 - ex) Authorization : hmac username=”hmac-test”,algorithm=”hmac-sha1”,headers=”X-Date”,signature=”089b8fcf36ce5bae9ccea9ad588609964a640f2e”&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.freeformatter.com/hmac-generator.html&quot;&gt;hmac auth header generator&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;jwt&quot;&gt;&lt;a href=&quot;https://docs.konghq.com/hub/kong-inc/jwt&quot;&gt;jwt&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;header 방식 - ex) Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9….&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://jwt.io/&quot;&gt;jwt auth header generator&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;oauth2&quot;&gt;&lt;a href=&quot;https://docs.konghq.com/hub/kong-inc/oauth2&quot;&gt;oauth2&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;header 및 query param 방식&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://konghq.com/blog/kong-gateway-oauth2/&quot;&gt;https://konghq.com/blog/kong-gateway-oauth2/&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;43-basic-auth-테스트&quot;&gt;4.3 Basic Auth 테스트&lt;/h2&gt;

&lt;p&gt;아래 절차대로 N 이라는 consumer가 Naver라는 서비스에 요청하기 위한 기본 설정을 하도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;Consumers → N → Credentials → Basic → Create Credentials&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881420-5cdc5425-b013-4c96-b3ec-2c6f7a76cdb6.png&quot; alt=&quot;Untitled 8&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위와 같이 입력해줍니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881421-e7f7deeb-2b67-4311-a902-e27843378721.png&quot; alt=&quot;Untitled 9&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Naver service에 가서 플러그인을 설정해주고, Eligible consumers 도 확인해줍니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881422-74088ec8-b2cb-49af-8ee4-84a743ba4399.png&quot; alt=&quot;Untitled 10&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881423-207b3d84-233d-47e9-a5f1-873e6d4e59ce.png&quot; alt=&quot;Untitled 11&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이렇게 설정된 API로 요청해보도록 합니다.&lt;/p&gt;

&lt;p&gt;요청&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;kong address&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/naver
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;응답&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;message&quot;&lt;/span&gt;:&lt;span class=&quot;s2&quot;&gt;&quot;Unauthorized&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://www.blitter.se/utils/basic-authentication-header-generator&quot;&gt;basic auth header generator&lt;/a&gt;  사이트에서 Authorization 헤더에 포함시킬 정보를 생성해보도록 합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881425-67cbe733-0aca-4a56-870f-c7594d8edaf1.png&quot; alt=&quot;Untitled 12&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;요청&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;kong address&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/naver &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Authorization: Basic bmF2ZXItdGVzdDoxMjM0&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;응답&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;&lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&amp;lt;title&amp;gt;301 Moved Permanently&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;center&amp;gt;&amp;lt;h1&amp;gt;301 Moved Permanently&amp;lt;/h1&amp;gt;&amp;lt;/center&amp;gt;
&amp;lt;hr&amp;gt;&amp;lt;center&amp;gt; NWS &amp;lt;/center&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;44-api-key-테스트&quot;&gt;4.4 API Key 테스트&lt;/h2&gt;

&lt;p&gt;아래 절차대로 K 이라는 consumer가 Kakao라는 서비스에 요청하기 위한 기본 설정을 하도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;Consumers → K → Credentials → API Keys→ Create Credentials&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881428-1f3393b1-ca29-460d-a895-10bd6e533ee9.png&quot; alt=&quot;Untitled 13&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881429-a45d4805-35cf-4646-b39e-86dac958cc59.png&quot; alt=&quot;Untitled 14&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881430-d20abd0d-41fb-4715-b600-2198b3d5beac.png&quot; alt=&quot;Untitled 15&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;플러그인을 붙일때 아무 값도 입력하지 않으면 다음 정보가 기본으로 입력됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881431-4fdbcf7e-d5e8-4afd-8756-796ec241ce52.png&quot; alt=&quot;Untitled 16&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881432-c33c18c6-ff18-4bf1-b97a-0e6d69bce316.png&quot; alt=&quot;Untitled 17&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;요청&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;kong address&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/kakao
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;응답&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;message&quot;&lt;/span&gt;:&lt;span class=&quot;s2&quot;&gt;&quot;No API key found in request&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;요청&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;kong address&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/kakao?apikey&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;test-api-key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;응답&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;DOCTYPE HTML PUBLIC &lt;span class=&quot;s2&quot;&gt;&quot;-//IETF//DTD HTML 2.0//EN&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&amp;lt;html&amp;gt;&amp;lt;&lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&amp;lt;title&amp;gt;302 Found&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Found&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;The document has moved &amp;lt;a &lt;span class=&quot;nv&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://www.daum.net/?apikey=test-api-key&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;here&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;45-hmac-테스트&quot;&gt;4.5 HMAC 테스트&lt;/h2&gt;

&lt;p&gt;아래 절차대로 G 이라는 consumer가 Google라는 서비스에 요청하기 위한 기본 설정을 하도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;Consumers → G → Credentials → HMAC → Create Credentials&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881433-f9065095-0aca-49eb-9993-d660edb4d664.png&quot; alt=&quot;Untitled 18&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881434-065825c6-c4e1-4e27-86d6-42c627c91b71.png&quot; alt=&quot;Untitled 19&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;
&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881435-61fd7500-f966-4349-afc4-a7c141183e25.png&quot; alt=&quot;Untitled 20&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;플러그인을 붙일때 아무 값도 입력하지 않으면 다음 정보가 기본으로 입력됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881436-f3ff9735-6d6e-49d1-9f42-a348da5e0bc9.png&quot; alt=&quot;Untitled 21&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881437-0ba0e8fa-2ba5-46ae-8fd9-a009c8e96eb7.png&quot; alt=&quot;Untitled 22&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.freeformatter.com/hmac-generator.html&quot;&gt;hmac auth header generator&lt;/a&gt; 사이트에서 Authorization 헤더에 포함시킬 정보를 생성해보도록 합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6061207/133881439-6161c12e-092a-4219-bd53-2cb65928a19c.png&quot; alt=&quot;Untitled 23&quot; class=&quot;align-center&quot; width=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;요청&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;kong address&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/google
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;응답&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;message&quot;&lt;/span&gt;:&lt;span class=&quot;s2&quot;&gt;&quot;Unauthorized&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;요청&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;kong address&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/google &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Authorization : hmac username=&quot;hmac-test&quot;,algorithm=&quot;hmac-sha1&quot;,headers=&quot;X-Date&quot;,signature=&quot;089b8fcf36ce5bae9ccea9ad588609964a640f2e&quot;&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;응답&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;meta http-equiv&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;content-type&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text/html;charset=utf-8&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&amp;lt;TITLE&amp;gt;301 Moved&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY&amp;gt;
&amp;lt;H1&amp;gt;301 Moved&amp;lt;/H1&amp;gt;
The document has moved
&amp;lt;A &lt;span class=&quot;nv&quot;&gt;HREF&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://www.google.com/&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;here&amp;lt;/A&amp;gt;.
&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;5-정리&quot;&gt;5. 정리&lt;/h1&gt;

&lt;p&gt;인증/인가 과정은 OpenAPI로 구성하거나 client들에게 제한된 기능을 제공해야 할 경우 필수적인 요소입니다.&lt;/p&gt;

&lt;p&gt;또한 Resource Server나 API Server에 접근 가능한 token/API Key 등이 유출되면 비용을 지불하지 않고 요청하거나 예상되지 않은 경로 등으로 API를 요청할 수 있게 되어 보안상 문제가 발생합니다.&lt;/p&gt;

&lt;p&gt;따라서 보다 안정된 유형의 인증 서비스를 제공하려고 한다면 고정된 API Key 등으로 client에게 제공하기 보다, 토큰의 발급/갱신/삭제 등을 처리하는 인증/인가 기능이 필요합니다.&lt;/p&gt;

&lt;p&gt;기회가 된다면 다음 글에서 custom plugin 구성과 안정화된 인증을 적용해보는 과정을 기술해보도록 하겠습니다.&lt;/p&gt;

&lt;h1 id=&quot;6-참고&quot;&gt;6. 참고&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://howtogapps.com/google-script-authorization-review-and-accept-the-permission-guide/&quot;&gt;https://howtogapps.com/google-script-authorization-review-and-accept-the-permission-guide/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://developer.okta.com/blog/2017/06/21/what-the-heck-is-oauth&quot;&gt;https://developer.okta.com/blog/2017/06/21/what-the-heck-is-oauth&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.konghq.com/hub/&quot;&gt;https://docs.konghq.com/hub/&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Sat, 18 Sep 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/kong/Kong-Gateway-4-Kong-Plugin-Auth-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0/</link>
            <guid isPermaLink="true">https://0leaf.github.io/kong/Kong-Gateway-4-Kong-Plugin-Auth-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0/</guid>
            
            <category>Kong</category>
            
            <category>Auth</category>
            
        
            <category>Kong</category>
            
        </item>
        
        <item>
            <title>ArgoCD 2. ArgoCD Slack Notification</title>
            <description>&lt;p&gt;Argocd Slack Notification 구성 과정을 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;0-들어가기-전에&quot;&gt;0. 들어가기 전에&lt;/h1&gt;

&lt;p&gt;ArgoCD 구성 이후 Sync 동작이 완료되거나 문제가 있을 경우 Slack으로 notification을 전달하고 싶었습니다. 하지만 &lt;a href=&quot;https://argocd-notifications.readthedocs.io/en/stable/services/slack/&quot;&gt;공식 가이드&lt;/a&gt; 대로 진행하니 잘 동작하지 않았습니다. 꽤 불필요한 시간을 소비했고, 다시 정리하면서 문제를 해결하고 과정을 기록하고자 합니다.&lt;/p&gt;

&lt;p&gt;또한 ArgoCD 공식 notifiaction 이외에도 &lt;a href=&quot;https://argoproj.github.io/argo-cd/operator-manual/notifications/&quot;&gt;ArgoCD 가 제안하는 다른 방식&lt;/a&gt;으로도 notification을 구성할 수 있습니다.&lt;/p&gt;

&lt;p&gt;가장 star 수가 많은 kubewatch로 K8S deploy 상태를 확인하여 slack webhook으로 전달하는 것은 어렵지 않게 성공할 수 있었으나, argo sync의 성공 여부를 판단하여 notification을 주고 싶었기 때문에 ArgoCD 공식 notification을 다시 짚어보기로 결정했습니다.&lt;/p&gt;

&lt;h1 id=&quot;1-문제의-발생&quot;&gt;1. 문제의 발생&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://argocd-notifications.readthedocs.io/en/stable/services/slack/&quot;&gt;공식 가이드&lt;/a&gt; 대로 notification을 구성하니 잘 동작하지 않았습니다. 다시 천천히 문서를 살펴보니 &lt;a href=&quot;https://argocd-notifications.readthedocs.io/en/stable/&quot;&gt;helm 설치 관련된 내용&lt;/a&gt;이 하단부에 있었습니다. 이 글에 따르면 아래와 같이 helm v3으로 notification을 쉽게 구성할 수 있다고 가이드하고 있지만 결과는 잘 동작하지 않습니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;helm repo add argo https://argoproj.github.io/argo-helm
helm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;argo/argocd-notifications &lt;span class=&quot;nt&quot;&gt;--generate-name&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--set&lt;/span&gt; triggers[0].name&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;on-sync-succeeded &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--set&lt;/span&gt; triggers[0].enabled&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--set&lt;/span&gt; secret.notifiers.slack.enabled&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--set&lt;/span&gt; secret.notifiers.slack.token&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;my-token&amp;gt;

Error: YAML parse error on argocd-notifications/templates/configmap.yaml: error converting YAML to JSON: yaml: line 15: did not find expected key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/argoproj/argo-helm/issues/616&quot;&gt;https://github.com/argoproj/argo-helm/issues/616&lt;/a&gt; 이 글에도 같은 문제가 있는데 글 작성 기준으로 해결되지 않은 상태로 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;2-처음부터-짚어보기&quot;&gt;2. 처음부터 짚어보기&lt;/h1&gt;

&lt;h2 id=&quot;21-slack-봇-생성&quot;&gt;2.1 slack 봇 생성&lt;/h2&gt;

&lt;p&gt;공식 가이드 문서에도 이부분은 잘 나와있지만 지금 글 쓰는 시점에서의 slack api 화면 구성과 약간 다르기 때문에 몇가지 부분만 캡쳐한 내용을 올립니다. 하지만 가이드 문서 내용에 이슈는 없습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://api.slack.com/apps?new_app=1&quot;&gt;https://api.slack.com/apps?new_app=1&lt;/a&gt; 화면으로 가서 아래와 같은 과정을 거칩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/126030806-5381b7a7-88f3-4772-93d0-e8f02819f908.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;

&lt;p&gt;app 생성하는 화면이 변경되었습니다. (21.07.17 기준) 이후에도 변경될 수 있지만 참고로 봐주시기 바랍니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/126030799-22338bd8-758d-457f-971f-76036e1d3663.png&quot; alt=&quot;Untitled 1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Scopes는 필요하다고 생각되는 권한을 부여했고 OAuth Token 보면 공식 가이드는 xoxp로 시작하는데 xoxb로 생성되고 있으며 Bot Token Scopes로 권한을 주면 됩니다.&lt;/p&gt;

&lt;p&gt;이렇게 권한을 부여한 뒤 &lt;strong&gt;원하는 workspace 및 channel로 Install 해줍니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/126030801-40093a3f-2481-4335-be4b-775ffc47aa4c.png&quot; alt=&quot;Untitled 2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;slack 내 Integrations에 해당 앱이 추가되어 있지 않으면 알림이 오지 않습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;22-kubernetes에-notifier-및-template-설치하기&quot;&gt;2.2 Kubernetes에 notifier 및 template 설치하기&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://argocd-notifications.readthedocs.io/en/stable/services/slack/&quot;&gt;공식 가이드&lt;/a&gt; 대로도 해보고 여러 글들을 찾아서 다 해봤는데, 정말 많은 시행착오 끝에 아래 내용으로 알람이 오는것을 확인했으며, &lt;a href=&quot;https://argocd-notifications.readthedocs.io/en/stable/&quot;&gt;설치&lt;/a&gt;와 관련된 글은 링크를 확인하시기 바랍니다.&lt;/p&gt;

&lt;p&gt;주의할점은 a&lt;strong&gt;rgocd가 설치된 namespace와 똑같은 공간에 notifier와 template 등을 설치&lt;/strong&gt;하셔야 합니다.&lt;/p&gt;

&lt;h3 id=&quot;221-argocd-notifications-secretyaml-신규-생성&quot;&gt;2.2.1 argocd-notifications-secret.yaml (신규 생성)&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apiVersion: v1
kind: Secret
metadata:
  name: argocd-notifications-secret
stringData:
  notifiers.yaml: |
    slack:
      token: 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;slack token은 앞서 발급받은 xoxb로 시작하는 oauth token을 입력합니다. (  까지 지워야 합니다.)&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl apply &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; argocd-notifications-secret.yaml &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; argocd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;222-notificationyaml&quot;&gt;2.2.2 notification.yaml&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl apply &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; argocd &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/argoproj-labs/argocd-notifications/release-1.0/manifests/install.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;공식 가이드에선 위 내용을 바로 apply 하라고 나오는데, 반영 후 아래 내용을 추가해도 좋고 제가 수정 반영해놓은 &lt;strong&gt;반영된 전체 yaml 파일&lt;/strong&gt;을 복사하셔서 apply 해도 됩니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: argocd-notifications-cm
data:
  config.yaml: |
    triggers:
      - name: on-sync-succeeded
        enabled: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;반영된 전체 yaml 파일&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apiVersion: v1
kind: ServiceAccount
metadata:
  name: argocd-notifications-controller
&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: argocd-notifications-controller
rules:
- apiGroups:
  - argoproj.io
  resources:
  - applications
  - appprojects
  verbs:
  - get
  - list
  - watch
  - update
  - patch
- apiGroups:
  - &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;
  resources:
  - secrets
  - configmaps
  verbs:
  - get
  - list
  - watch
&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: argocd-notifications-controller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: argocd-notifications-controller
subjects:
- kind: ServiceAccount
  name: argocd-notifications-controller
&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;
apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: argocd-notifications-cm
data:
  config.yaml: |
    triggers:
      - name: on-sync-succeeded
        enabled: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;
apiVersion: v1
kind: Secret
metadata:
  name: argocd-notifications-secret
&lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;: Opaque
&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: argocd-notifications-controller-metrics
  name: argocd-notifications-controller-metrics
spec:
  ports:
  - name: metrics
    port: 9001
    protocol: TCP
    targetPort: 9001
  selector:
    app.kubernetes.io/name: argocd-notifications-controller
&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;
apiVersion: apps/v1
kind: Deployment
metadata:
  name: argocd-notifications-controller
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: argocd-notifications-controller
  strategy:
    &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;: Recreate
  template:
    metadata:
      labels:
        app.kubernetes.io/name: argocd-notifications-controller
    spec:
      containers:
      - &lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt;:
        - /app/argocd-notifications-backend
        - controller
        image: argoprojlabs/argocd-notifications:v1.0.2
        imagePullPolicy: Always
        name: argocd-notifications-controller
        volumeMounts:
        - mountPath: /app/config/tls
          name: tls-certs
        workingDir: /app
      securityContext:
        runAsNonRoot: &lt;span class=&quot;nb&quot;&gt;true
      &lt;/span&gt;serviceAccountName: argocd-notifications-controller
      volumes:
      - configMap:
          name: argocd-tls-certs-cm
        name: tls-certs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl apply &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; notification.yaml &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; argocd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;223-templatesyaml&quot;&gt;2.2.3 templates.yaml&lt;/h3&gt;

&lt;p&gt;공식 가이드에선 위 내용을 바로 apply 하라고 합니다. 위 내용을 내려받으면 특정 조건에서 동작할 메세지 등이 정의된 내용을 확인할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl apply &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; argocd &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/argoproj-labs/argocd-notifications/release-1.0/catalog/install.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 내용을 내려받은 yaml 파일&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apiVersion: v1
data:
  template.app-deployed: |
    email:
      subject: New version of an application  is up and running.
    message: |
      :white_check_mark: Application  is now running new version of deployments manifests.
    slack:
      attachments: |
        &lt;span class=&quot;o&quot;&gt;[{&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;title_link&quot;&lt;/span&gt;:&lt;span class=&quot;s2&quot;&gt;&quot;/applications/&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;color&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;#18be52&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;fields&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Sync Status&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Repository&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Revision&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
          
          ,
          ,
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
          
          &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}]&lt;/span&gt;
  template.app-health-degraded: |
    email:
      subject: Application  has degraded.
    message: |
      :exclamation: Application  has degraded.
      Application details: /applications/.
    slack:
      attachments: |-
        &lt;span class=&quot;o&quot;&gt;[{&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;title_link&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;/applications/&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;color&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;#f4c030&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;fields&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Sync Status&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Repository&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
          
          ,
          ,
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
          
          &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}]&lt;/span&gt;
  template.app-sync-failed: |
    email:
      subject: Failed to &lt;span class=&quot;nb&quot;&gt;sync &lt;/span&gt;application &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
    message: |
      :exclamation:  The &lt;span class=&quot;nb&quot;&gt;sync &lt;/span&gt;operation of application  has failed at  with the following error: 
      Sync operation details are available at: /applications/?operation&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
    slack:
      attachments: |-
        &lt;span class=&quot;o&quot;&gt;[{&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;title_link&quot;&lt;/span&gt;:&lt;span class=&quot;s2&quot;&gt;&quot;/applications/&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;color&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;#E96D76&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;fields&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Sync Status&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Repository&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
          
          ,
          ,
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
          
          &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}]&lt;/span&gt;
  template.app-sync-running: |
    email:
      subject: Start syncing application &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
    message: |
      The &lt;span class=&quot;nb&quot;&gt;sync &lt;/span&gt;operation of application  has started at &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
      Sync operation details are available at: /applications/?operation&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
    slack:
      attachments: |-
        &lt;span class=&quot;o&quot;&gt;[{&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;title_link&quot;&lt;/span&gt;:&lt;span class=&quot;s2&quot;&gt;&quot;/applications/&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;color&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;#0DADEA&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;fields&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Sync Status&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Repository&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
          
          ,
          ,
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
          
          &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}]&lt;/span&gt;
  template.app-sync-status-unknown: |
    email:
      subject: Application  &lt;span class=&quot;nb&quot;&gt;sync &lt;/span&gt;status is &lt;span class=&quot;s1&quot;&gt;&apos;Unknown&apos;&lt;/span&gt;
    message: |
      :exclamation: Application  &lt;span class=&quot;nb&quot;&gt;sync &lt;/span&gt;is &lt;span class=&quot;s1&quot;&gt;&apos;Unknown&apos;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
      Application details: /applications/.
      
      
          &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; 
      
      
    slack:
      attachments: |-
        &lt;span class=&quot;o&quot;&gt;[{&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;title_link&quot;&lt;/span&gt;:&lt;span class=&quot;s2&quot;&gt;&quot;/applications/&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;color&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;#E96D76&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;fields&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Sync Status&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Repository&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
          
          ,
          ,
          &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;short&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
          
          &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}]&lt;/span&gt;
  template.app-sync-succeeded: |
    email:
      subject: Application  has been successfully synced.
    message: |
      :white_check_mark: Application  has been successfully synced at &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
      Sync operation details are available at: /applications/?operation&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
    slack:
      attachments: &lt;span class=&quot;s2&quot;&gt;&quot;[{&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;title_link&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/applications/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;#18be52&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  {&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Sync Status&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;short&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: true&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  },&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  {&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Repository&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;short&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: true&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  }&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  ,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  ,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  {&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;short&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: true&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  }&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  ]&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;}]    &quot;&lt;/span&gt;
  trigger.on-deployed: |
    - description: Application is synced and healthy. Triggered once per commit.
      oncePer: app.status.sync.revision
      send:
      - app-deployed
      when: app.status.operationState.phase &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Succeeded&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; and app.status.health.status &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Healthy&apos;&lt;/span&gt;
  trigger.on-health-degraded: |
    - description: Application has degraded
      send:
      - app-health-degraded
      when: app.status.health.status &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Degraded&apos;&lt;/span&gt;
  trigger.on-sync-failed: |
    - description: Application syncing has failed
      send:
      - app-sync-failed
      when: app.status.operationState.phase &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Error&apos;&lt;/span&gt;, &lt;span class=&quot;s1&quot;&gt;&apos;Failed&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  trigger.on-sync-running: |
    - description: Application is being synced
      send:
      - app-sync-running
      when: app.status.operationState.phase &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Running&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  trigger.on-sync-status-unknown: |
    - description: Application status is &lt;span class=&quot;s1&quot;&gt;&apos;Unknown&apos;&lt;/span&gt;
      send:
      - app-sync-status-unknown
      when: app.status.sync.status &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Unknown&apos;&lt;/span&gt;
  trigger.on-sync-succeeded: |
    - description: Application syncing has succeeded
      send:
      - app-sync-succeeded
      when: app.status.operationState.phase &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Succeeded&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: argocd-notifications-cm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl apply &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; templates.yaml &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; argocd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;23-트리거-등록&quot;&gt;2.3 트리거 등록&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://argocd-notifications.readthedocs.io/en/stable/catalog/&quot;&gt;트리거&lt;/a&gt;들은 아래와 같은 종류들이 있고, 두가지 방법으로 등록 할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/126030802-11864e04-90d8-4ab8-9c13-947dca0a110a.png&quot; alt=&quot;Untitled 3&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
notifications.argoproj.io/subscribe.on-created.slack
notifications.argoproj.io/subscribe.on-delete.slack
notifications.argoproj.io/subscribe.on-deployed.slack
notifications.argoproj.io/subscribe.on-health-degraded.slack
notifications.argoproj.io/subscribe.on-sync-failed.slack
notifications.argoproj.io/subscribe.on-sync-running.slack
notifications.argoproj.io/subscribe.on-sync-status-unknown.slack
notifications.argoproj.io/subscribe.on-sync-succeeded.slack
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;231-kubectl-로-argo-app에-annotation을-추가하는-방법&quot;&gt;2.3.1 kubectl 로 argo app에 annotation을 추가하는 방법&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;app-name&amp;gt;, &amp;lt;notifications.argoproj.io/subscribe.on-sync-succeeded.slack&amp;gt;, &amp;lt;slack-channel-name&amp;gt; 를 각각 &amp;lt;&amp;gt; 빼고 원하는 값을 넣습니다.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl patch app &amp;lt;app-name&amp;gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; argocd &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;{&quot;metadata&quot;: {&quot;annotations&quot;: {&quot;&amp;lt;notifications.argoproj.io/subscribe.on-sync-succeeded.slack&amp;gt;&quot;:&quot;&amp;lt;slack-channel-name&amp;gt;&quot;}}}&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; merge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;232-argocd-admin-페이지에서-annotation을-추가하는-방법&quot;&gt;2.3.2 argocd admin 페이지에서 annotation을 추가하는 방법&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/126030803-b01ce6af-027e-4374-8a31-646b6205ad3e.png&quot; alt=&quot;Untitled 4&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;3-trouble-shooting&quot;&gt;3. Trouble shooting&lt;/h2&gt;

&lt;h3 id=&quot;31-argocd-notifications-controller-pod의-로그&quot;&gt;3.1 argocd-notifications-controller pod의 로그&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2021-07-13T07:40:48Z&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;info &lt;span class=&quot;nv&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Start processing&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;argocd/notifier
&lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2021-07-13T07:40:48Z&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;info &lt;span class=&quot;nv&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Trigger on-sync-succeeded result: [{[0].zxM90Et6k4Elb1-fHdjtDJq0xR0  [app-sync-succeeded] true}]&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;argocd/notifier
&lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2021-07-13T07:40:48Z&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;info &lt;span class=&quot;nv&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Sending notification about condition &apos;on-sync-succeeded.[0].zxM90Et6k4Elb1-fHdjtDJq0xR0&apos; to &apos;{slack notifier}&apos;&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;argocd/notifier
&lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2021-07-13T07:40:48Z&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;error &lt;span class=&quot;nv&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Failed to notify recipient {slack notifier} defined in app argocd/notifier: notification service &apos;slack&apos; is not supported&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;argocd/notifier
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 내용은 slack token / slack 채널에 bot 초대 / slack 채널명 상이 등과 관련 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;32-argocd-app이-보이지-않는-경우&quot;&gt;3.2 argocd app이 보이지 않는 경우&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl get app &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; argocd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;rancher 구성 혹은 다른 문제로 인해 위 결과가 표시되지 않을 경우, 2.3.1 트리거 방법을 사용할 수 없고&lt;/p&gt;

&lt;p&gt;2.3.2 방법으로 트리거를 등록해야 합니다.&lt;/p&gt;

&lt;h1 id=&quot;4-정리&quot;&gt;4. 정리&lt;/h1&gt;

&lt;p&gt;혹시 3. Trouble shooting 내용과 유사한 문제가 있거나, 의도한대로 notification 연동이 되지 않는다면 2. 처음부터 짚어보기 부분을 참고하시길 바랍니다. 가이드 문서가 여러군데로 나뉘어있고, 다른 글들에서도 조금씩 방법을 다르게 정리해 놓았는데, 위 방법으로 진행하고 나서 slack 알람이 오는 것을 확인하였습니다.&lt;/p&gt;

&lt;p&gt;혹시나 도저히 연동이 안되어서 스트레스 받는 분이 계시다면 &lt;a href=&quot;https://github.com/bitnami-labs/kubewatch&quot;&gt;kubewatch&lt;/a&gt;로 구성하는 것이 문제없이 연동되었습니다.&lt;/p&gt;

&lt;h1 id=&quot;5-참고자료&quot;&gt;5. 참고자료&lt;/h1&gt;

&lt;p&gt;https://argocd-notifications.readthedocs.io/en/stable/services/slack/&lt;/p&gt;
</description>
            <pubDate>Sat, 17 Jul 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/argocd/ArgoCD-2-Notification-slack/</link>
            <guid isPermaLink="true">https://0leaf.github.io/argocd/ArgoCD-2-Notification-slack/</guid>
            
            <category>ArgoCD</category>
            
            <category>CI/CD</category>
            
        
            <category>ArgoCD</category>
            
        </item>
        
        <item>
            <title>ArgoCD 1. ArgoCD 구성하기</title>
            <description>&lt;p&gt;Argocd 구성 과정을 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;0-들어가기-전에&quot;&gt;0. 들어가기 전에&lt;/h1&gt;

&lt;p&gt;계속해서 Kuberentes 내에서의 infra 구성에 대한 글을 정리하고 있습니다. 이번 글도 마찬가지이며 웹 상에 공식 페이지 및 많은 글들이 구성 방법에 대해 설명하고 있지만 하나 두개씩 가이드와 다르거나 동작하지 않는 경우들을 심심치 않게 볼 수 있었습니다.&lt;/p&gt;

&lt;p&gt;그러한 이유로 이 글을 작성하기로 마음먹은 이유도 있습니다. 혹시나 같은 경우를 겪는 누군가에게 도움이 되길 바라며 글을 시작하겠습니다.&lt;/p&gt;

&lt;p&gt;이 글은 DevOps, GitOps, Helm 및 Kustomize 등 manifest에 대한 전반에 대해 이해하고 있다고 가정하며 자세하게 다루지는 않으며, Kubernetes 환경에서 진행됨을 말씀드립니다.&lt;/p&gt;

&lt;h1 id=&quot;1-cd-in-devops&quot;&gt;1. CD in DevOps&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/126030458-fd1ef4b0-e287-44aa-b68c-23f50f16bbac.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://programmerblog.net/what-is-devop/&quot;&gt;https://programmerblog.net/what-is-devop/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.opsera.io/blog/top-25-devops-tools-that-you-need-to-know&quot;&gt;https://www.opsera.io/blog/top-25-devops-tools-that-you-need-to-know&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;위 그림에서 보이는 DevOps 과정 중에서 오른쪽에 붉게 표시된 argoCD를 이용해 CD를 구성하게 될 것입니다. 향후 기회가 된다면 CI까지 연동해 Dev Ops 전체 과정이 부드럽게 이어져 동작하는 것을 공유드릴 수 있으면 좋겠습니다.&lt;/p&gt;

&lt;h1 id=&quot;2-argocd&quot;&gt;2. ArgoCD&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://argoproj.github.io/argo-cd/&quot;&gt;공식 문서&lt;/a&gt;를 참고하면 ArgoCD에 대해 이렇게 설명하고 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Application definitions, configurations, and environments should be declarative and version controlled. Application deployment and lifecycle management should be automated, auditable, and easy to understand.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;정리해서 기술하자면 ArgoCD는 Devops과정 중 Kuberenetes 환경에서 Continuous Deploy 의 부분을 담당하는 도구라고 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;Helm 및 Kustomize 의 manifest 구성을 GitOps 저장소에 반영하면 ArgoCD가 변경점을 체크하여 Deploy를 자동으로 진행합니다. 언급된 내용처럼 직관적으로 Deployment와 Pod 등의 구성을 확인할 수 있고, rollback 등도 UI로 쉽게 진행할 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;3-cd-구성&quot;&gt;3. CD 구성&lt;/h1&gt;

&lt;h2 id=&quot;31-gitops-구성&quot;&gt;3.1 GitOps 구성&lt;/h2&gt;

&lt;p&gt;GitOps를 위해 Git repository가 필요합니다. GitOps 동작에 대한 내용은 &lt;a href=&quot;https://www.weave.works/blog/gitops-operations-by-pull-request&quot;&gt;weaveworks - Operations by Pull Request&lt;/a&gt;을 참고하시면 도움될 것 같습니다.&lt;/p&gt;

&lt;p&gt;Git 기반의 repository들을 GitOps로 활용할 수 있고, AWS code commit, Github 등 어느 것을 사용하더라도 argoCD와 연동할 수 있습니다.&lt;/p&gt;

&lt;p&gt;혹시 github를 사용하신다면, github repo를 하나 생성하고 테스트할 helm chart를 넣어둡니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/126030463-ea6140c6-e7ff-40e9-a11f-bcdefd9a1812.png&quot; alt=&quot;Untitled 1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;본 글의 내용을 모두 진행하게 되면 Kubernetes 로의 배포는 위와 같은 그림으로 진행될 것입니다. User가 PR 하는 내용은 helm 등으로 구성된 K8S 구성 manifest이며 PR 이후 argoCD가 변경점을 보고 있다가, K8S에 반영하게 됩니다.&lt;/p&gt;

&lt;h2 id=&quot;32-argocd-설치&quot;&gt;3.2 ArgoCD 설치&lt;/h2&gt;

&lt;p&gt;ArgoCD를 설치하는 과정은 &lt;a href=&quot;https://argoproj.github.io/argo-cd/getting_started/&quot;&gt;공식 홈페이지&lt;/a&gt;에 잘 기술되어 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;321-kubernetes에-argocd-설치&quot;&gt;3.2.1 Kubernetes에 ArgoCD 설치&lt;/h3&gt;

&lt;p&gt;설치&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl create namespace argocd
kubectl apply &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; argocd &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;외부에서 접근 가능하도록 Service type 변경 (node port 변경 후 port fowrding도 가능)&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl patch svc argocd-server &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; argocd &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;{&quot;spec&quot;: {&quot;type&quot;: &quot;LoadBalancer&quot;}}&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;322-admin-계정-설정&quot;&gt;3.2.2 admin 계정 설정&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;가이드에서 언급하고 있는대로 ArgoCD cli로 admin 계정 비밀번호를 설정하면 로그인 되지 않았습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;argoproj의 &lt;a href=&quot;https://github.com/argoproj/argo-cd/issues/829&quot;&gt;이슈&lt;/a&gt; 에서 이미 언급된 내용이 있고, password가 일치하지 않는 문제가 발생하였습니다.&lt;/p&gt;

&lt;p&gt;위 이슈의 내용 아래 명령으로 비밀번호를 변경할 수 있었고 (newpassword 부분을 원하는 것으로 변경), ArgoCD cli로 비밀번호만 변경할 목적이라면 사실 cli 설치 자체가 필요하지 않다고 생각되어 본 글에선 생략합니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;kubectl patch secret &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; argocd argocd-secret &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;{&quot;stringData&quot;: { &quot;admin.password&quot;: &quot;&apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;htpasswd &lt;span class=&quot;nt&quot;&gt;-bnBC&lt;/span&gt; 10 &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt; newpassword | &lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;:\n&apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;&quot;}}&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;환경에 htpasswd 가 없는 경우 아래 명령으로 설치해줍니다. (ubuntu)&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;apache2-utils
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;4-argocd-살펴보기&quot;&gt;4. ArgoCD 살펴보기&lt;/h1&gt;

&lt;h2 id=&quot;41-argocd-접속&quot;&gt;4.1 ArgoCD 접속&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;kubectl get svc &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; argocd
NAME                                      TYPE           CLUSTER-IP       EXTERNAL-IP                                                                    PORT&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;S&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;                      AGE
argocd-dex-server                         ClusterIP      172.20.234.216   &amp;lt;none&amp;gt;                                                                         5556/TCP,5557/TCP,5558/TCP   44d
argocd-metrics                            ClusterIP      172.20.19.60     &amp;lt;none&amp;gt;                                                                         8082/TCP                     44d
argocd-notifications-controller-metrics   ClusterIP      172.20.34.41     &amp;lt;none&amp;gt;                                                                         9001/TCP                     3d20h
argocd-redis                              ClusterIP      172.20.246.35    &amp;lt;none&amp;gt;                                                                         6379/TCP                     44d
argocd-repo-server                        ClusterIP      172.20.119.15    &amp;lt;none&amp;gt;                                                                         8081/TCP,8084/TCP            44d
argocd-server                             LoadBalancer   172.20.138.97    xxx.ap-northeast-2.elb.amazonaws.com   80:30462/TCP,443:31008/TCP   44d
argocd-server-metrics                     ClusterIP      172.20.231.166   &amp;lt;none&amp;gt;                                                                         8083/TCP                     44d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;LoadBalancer 타입으로 변경한 경우 지정된 nlb 주소 (xxx.ap-northeast-2.elb.amazonaws.com) 로 브라우저에서 접속해봅니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/126030464-9ed58d8d-53a6-4a10-80da-bf3c97e232bf.png&quot; alt=&quot;Untitled 2&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;42-argo-app-구성&quot;&gt;4.2 Argo App 구성&lt;/h2&gt;

&lt;p&gt;앞 단계에서 설정한 admin 계정 정보를 넣습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/126030479-c76a5528-8318-48fc-8c85-6881f0c3daf4.png&quot; alt=&quot;Untitled 3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/126030486-659b9a16-9333-4c0f-9c1b-7004a588f89b.png&quot; alt=&quot;Untitled 4&quot; /&gt;&lt;/p&gt;

&lt;p&gt;접속해서 보이는 화면에서 helm 혹은 kustomize로 구성된 manifest가 존재하는 git repositiory를 등록 준 뒤 첫번째 탭을 선택하여 NewApp 버튼으로 연결된 repository의 helm chart를 연결합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/126030515-16fb6f1f-710c-4213-b23e-97836d316efe.gif&quot; alt=&quot;argocd-ui&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 gitops repository로 가서 values.yaml 등으로 원하는 부분을 변경 후 push 하면&lt;/p&gt;

&lt;p&gt;위 화면처럼 Sync 기능을 통해 gitops repository와 현재 클러스터의 차이를 확인하여 변경점이 있을 경우 gitops repository의 helm chart 구성을 바탕으로 배포하게 됩니다.&lt;/p&gt;

&lt;p&gt;해당 앱의 구조 파악 및 이전 버전으로의 rollback 등을 손쉽게 UI로 처리할 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;5-정리&quot;&gt;5. 정리&lt;/h1&gt;

&lt;p&gt;이번 글은 사실 많은 내용은 없습니다. 다만 공식 가이드에서 제공해준 내용대로 진행하다가 admin 계정 설정 부분에서 잘 안되었던 부분이 있어, 관련 내용을 기술하고자 ArgoCD와 관련된 내용도 일부 정리하게 되었습니다.&lt;/p&gt;

&lt;h1 id=&quot;6-참고자료&quot;&gt;6. 참고자료&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://argoproj.github.io/argo-cd/&quot;&gt;https://argoproj.github.io/argo-cd/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://programmerblog.net/what-is-devop/&quot;&gt;https://programmerblog.net/what-is-devop/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.opsera.io/blog/top-25-devops-tools-that-you-need-to-know&quot;&gt;https://www.opsera.io/blog/top-25-devops-tools-that-you-need-to-know&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Sat, 17 Jul 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/argocd/ArgoCD-1-ArgoCD-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0/</link>
            <guid isPermaLink="true">https://0leaf.github.io/argocd/ArgoCD-1-ArgoCD-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0/</guid>
            
            <category>ArgoCD</category>
            
            <category>CI/CD</category>
            
        
            <category>ArgoCD</category>
            
        </item>
        
        <item>
            <title>Kong Gateway 3. Kong Admin 으로 API 구성하기</title>
            <description>&lt;p&gt;Kong, Kong Admin에 대한 설명 및 구성 과정을 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;0-들어가기-전에&quot;&gt;0. 들어가기 전에&lt;/h1&gt;

&lt;p&gt;이전 장에서 Kong API Gateway와 Konga를 K8S에서 구성하여 API 간단히 테스트 해봤습니다. 하지만 Kong의 많은 기능들을 제대로 이해하기 위해 공식 문서를 통해 하나씩 살펴보는 것이 필요하겠다라는 생각이 들었습니다.&lt;/p&gt;

&lt;p&gt;아래 과정들은 konga를 설치하면 UI로 쉽게 구성할 수 있지만, konga를 사용하지 않는 경우도 있고, infra code로 관리하게 될 경우 기본이되는 REST 구성을 살펴보기 위해 Kong Admin API 를 통해 API 구성을 해본 과정을 기술합니다.&lt;/p&gt;

&lt;p&gt;혹시 Kong 환경이 구성되지 않으셨다면 &lt;a href=&quot;https://0leaf.github.io/kong/Kong-Gateway-2-Kong-on-kubernetes-(Kong,Konga)/&quot;&gt;이 글&lt;/a&gt;을 참고하시기 바랍니다.&lt;/p&gt;

&lt;h1 id=&quot;1-kong-gateway&quot;&gt;1. Kong Gateway&lt;/h1&gt;

&lt;p&gt;앞서 이야기한 내용처럼 Kong Gateway는 Nginx 기반으로 Gateway 기능을 수행하기 위한 목적으로 만들어 졌습니다. Kong은 Reverse Proxy로 많이 쓰이는 Nginx 위에 Lua 언어로 플러그인들이 구성되어 Reverse Proxy의 기능 외에도 API Gateway가 갖춰야 할 다양한 기능들을 제공합니다.&lt;/p&gt;

&lt;p&gt;Micro Service Architecture 로 시스템을 설계함에 있어 Kong은 다양한 plugin 구성으로 큰 장점을 가져올 수 있다고 말하고 있으며 Kong Gateway as a paragon of microservice architecture 라고 &lt;a href=&quot;https://docs.konghq.com/gateway-oss/&quot;&gt;kong 문서&lt;/a&gt;에서 이야기하고 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;2-getting-started-guide&quot;&gt;2. Getting Started Guide&lt;/h1&gt;

&lt;h2 id=&quot;21-overview&quot;&gt;2.1 Overview&lt;/h2&gt;

&lt;p&gt;kong gateway 서비스는 Enterprise와 OSS(OpenSource) 구성으로 나누어져 있습니다. 이 글에서 살펴볼 내용은 OSS 에 해당하는 부분입니다. 청록색 부분이 Enterprise Version의 기능을 의미하는데, Kong Manager같은 경우 &lt;a href=&quot;https://github.com/pantsel/konga&quot;&gt;Konga&lt;/a&gt; 라는 kong admin을 UI로 관리할 수 있는 open source 대체 툴이 존재합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185346-60477b80-e25f-11eb-9314-7328c8ca5e6a.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.konghq.com/getting-started-guide/2.4.x/overview/&quot;&gt;https://docs.konghq.com/getting-started-guide/2.4.x/overview/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;위 그림은 단순히 Kong에 대한 그림 뿐만 아니라 일반적인 API Gateway들의 특징들을 의미하기도 합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185350-64739900-e25f-11eb-8034-282a4417659b.png&quot; alt=&quot;Untitled 1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;API Client로부터 8000/8443 로 프록시된 포트로부터 요청을 받고 Backend API로 요청을 전달합니다. Admin의 경우 Restful 방식으로 여러 설정들을 구성할 수 있는데 helm으로 구성할 경우 기본적으로 8001로 expose 되어있습니다.&lt;/p&gt;

&lt;p&gt;따라서 &lt;strong&gt;kubectl get service 명령을 통해 port가 어떻게 포워딩 되어있는지 확인&lt;/strong&gt;하시길 바랍니다.&lt;/p&gt;

&lt;h2 id=&quot;22-prepare-to-administer&quot;&gt;2.2 Prepare to Administer&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.konghq.com/getting-started-guide/2.4.x/prepare/#verify-the-kong-gateway-configuration&quot;&gt;링크&lt;/a&gt; 의 원글을 실험해보면서 해당 과정을 조금 더 자세히 이해해보도록 하겠습니다.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;NAME&lt;/span&gt;                             &lt;span class=&quot;n&quot;&gt;TYPE&lt;/span&gt;           &lt;span class=&quot;n&quot;&gt;CLUSTER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IP&lt;/span&gt;       &lt;span class=&quot;n&quot;&gt;EXTERNAL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IP&lt;/span&gt;                                                                    &lt;span class=&quot;n&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;                                                    &lt;span class=&quot;n&quot;&gt;AGE&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;konga&lt;/span&gt;                            &lt;span class=&quot;n&quot;&gt;LoadBalancer&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;172&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;163&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;27&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;xxx1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;northeast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;elb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;amazonaws&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31458&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TCP&lt;/span&gt;                                               &lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kong&lt;/span&gt;                  &lt;span class=&quot;n&quot;&gt;LoadBalancer&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;172&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;244&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;82&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;xxx2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;northeast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;elb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;amazonaws&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31067&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TCP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32020&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TCP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8001&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31014&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TCP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8444&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31241&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TCP&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kong&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metrics&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;ClusterIP&lt;/span&gt;      &lt;span class=&quot;mi&quot;&gt;172&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;109&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;139&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;                                                                         &lt;span class=&quot;mi&quot;&gt;9119&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TCP&lt;/span&gt;                                                   &lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;postgresql&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;ClusterIP&lt;/span&gt;      &lt;span class=&quot;mi&quot;&gt;172&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;148&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;                                                                         &lt;span class=&quot;mi&quot;&gt;5432&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TCP&lt;/span&gt;                                                   &lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;postgresql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headless&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;ClusterIP&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;None&lt;/span&gt;             &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;                                                                         &lt;span class=&quot;mi&quot;&gt;5432&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TCP&lt;/span&gt;                                                   &lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;kubectl get svc -n default 명령을 통해 초기 kong, konga가 구성된 서비스들을 확인해볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;편의를 위해 konga, my-release-kong 두개를 LoadBalancer type으로 변경해 외부에서 요청할 수 있도록 LoadBalancer로 타입을 변경하여 elb를 붙였습니다.&lt;/p&gt;

&lt;p&gt;지금은 my-release-kong 만 살펴볼 예정인데, 포트를 보면 80:31067/TCP, 443:32020/TCP, 8001:31014/TCP, 8444:31241/TCP 가 포워딩 된 것을 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;이전 단계에서 언급했던 것 처럼 Admin은 8001, API 요청은 80(8000), 443(8443), 으로 요청을 받아주도록 구성되었습니다.&lt;/p&gt;

&lt;h3 id=&quot;221-admin-api-테스트&quot;&gt;2.2.1 Admin API 테스트&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185351-64739900-e25f-11eb-8eb9-d317ca3b03f5.png&quot; alt=&quot;Untitled 2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;공식 문서의 위 항목 중 여기서는 OSS의 Spec을 살펴 볼 것이므로 Using the Admin API를 선택합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; GET xxx2.ap-northeast-2.elb.amazonaws.com:8001
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;응답&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185352-650c2f80-e25f-11eb-9604-9c600cdbec2c.png&quot; alt=&quot;Untitled 3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 결과처럼 응답이 내려오는데 API Gateway 설정과 관련된 굉장히 많은 정보를 포함하고 있으므로 응답 전문은 생략합니다.&lt;/p&gt;

&lt;h2 id=&quot;23-expose-your-services&quot;&gt;2.3 Expose your Services&lt;/h2&gt;

&lt;p&gt;여기서 Service 와 Route라는 개념을 다룹니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Service is an entity representing an external upstream API or microservice.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Routes determine how (and if) requests are sent to their Services after they reach Kong Gateway.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;각각 정리된 내용을 살펴보면 Service는 upstream API 나 microservice 에 대한 정보를 포함하여 정의되고, Route는 그렇게 정의된 Service를 외부 요청으로부터 연결해준다고 불 수 있습니다.&lt;/p&gt;

&lt;p&gt;그런 이유로 구성 순서는 Service 정의 → Route 연결 이 됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185353-65a4c600-e25f-11eb-8925-c84e14652399.png&quot; alt=&quot;Untitled 4&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;231-add-a-service&quot;&gt;2.3.1 Add a Service&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185354-65a4c600-e25f-11eb-8e5a-e2df47802d36.png&quot; alt=&quot;Untitled 5&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Using the Admin API를 선택해서 Service 등록 과정을 살펴봅니다.&lt;/p&gt;

&lt;p&gt;조금 구성을 변경해서 google.com을 example_service의 이름을 갖는 서비스로 등록 해보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST http://xxx2.ap-northeast-2.elb.amazonaws.com:8001/services &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--data&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;example_service &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--data&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;https://google.com&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;port&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;example_service&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;client_certificate&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ca_certificates&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;write_timeout&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;60000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;connect_timeout&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;60000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tls_verify&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;protocol&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tls_verify_depth&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;host&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;google.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;created_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1623725919&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;retries&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;174a56d3-69b3-4211-afe2-e0405dc61ce4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;read_timeout&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;60000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;updated_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1623725919&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;232-add-a-route&quot;&gt;2.3.2 Add a Route&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185355-663d5c80-e25f-11eb-85aa-b3dc2f52b09d.png&quot; alt=&quot;Untitled 6&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Using the Admin API를 선택해서 Route 등록 과정을 살펴봅니다.&lt;/p&gt;

&lt;p&gt;여기서 살펴볼만한 점은 POST 주소를 보면 services/example_services/rotues
의 restful한 리소스 구조로 요청을 보내고 있는데, routes가 services 리소스에 종속되어 있음을 알 수 있습니다.&lt;/p&gt;

&lt;p&gt;또한 —data 옵션으로 ‘paths[]=/mock’ 를 주고 있는데 사용자가 Kong API Gateway를 통해 요청할 때 /mock 로 보내면 example_service로 연결함을 의미합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Route 등록&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST http://xxx2.ap-northeast-2.elb.amazonaws.com:8001/services/example_service/routes &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--data&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;paths[]=/mock&apos;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--data&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;mocking
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;mocking&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;paths&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/mock&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;methods&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;destinations&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;request_buffering&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;response_buffering&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;strip_path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;174a56d3-69b3-4211-afe2-e0405dc61ce4&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;https_redirect_status_code&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;426&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;preserve_host&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;protocols&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;regex_priority&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;path_handling&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;v0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;created_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1623726177&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;updated_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1623726177&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;headers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hosts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;81580cf8-3a6c-4b37-95df-5e810f41b07e&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;snis&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;sources&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;233-연결-확인&quot;&gt;2.3.3 연결 확인&lt;/h3&gt;

&lt;p&gt;아래 요청과 같이 보냅니다. 주의할 점은 저 처럼 helm으로 K8S 내 kong을 구성하면 기본으로 8000이 아니라 80으로 port forwarding 되어있습니다.&lt;/p&gt;

&lt;p&gt;또 이전 API 등록 예제는 Admin(8001)로 보냈는데, 등록이 완료된 이후로는 Kong API Gateway(80/8000)으로 보내고 있음을 알 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; GET http://xxx2.ap-northeast-2.elb.amazonaws.com:80/mock/request
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;HTTP/&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Not&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Found&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Content-Type:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;text/html;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;charset=UTF&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-8&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Content-Length:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1568&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Connection:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;keep-alive&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Referrer-Policy:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;no-referrer&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Date:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Tue,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Jun&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;03&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;08&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;GMT&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Alt-Svc:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;:443&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ma=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2592000&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,h&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3-29&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;:443&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ma=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2592000&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,h&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-T&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;051&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;:443&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ma=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2592000&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,h&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-Q&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;050&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;:443&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ma=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2592000&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,h&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-Q&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;046&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;:443&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ma=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2592000&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,h&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-Q&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;043&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;:443&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ma=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2592000&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,quic=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;:443&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ma=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2592000&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;v=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;46,43&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;X-Kong-Upstream-Latency:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;171&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;X-Kong-Proxy-Latency:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;109&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Via:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;kong/&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;!DOCTYPE&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;html&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;html&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;lang=en&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;meta&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;charset=utf&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;meta&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;name=viewport&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;initial-scale=1, minimum-scale=1, width=device-width&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;title&amp;gt;Error&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;(Not&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Found)!!&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;style&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;margin:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;padding:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;html,code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;font:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;arial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;sans-serif&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;background:#fff;color:#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;222&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;padding:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;margin:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;max-width:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;390&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px;min-height:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;180&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px;padding:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;background:url(//www.google.com/images/errors/robot.png)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;no-repeat;padding-right:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;205&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;margin:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px;overflow:hidden&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;color:#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;777&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;text-decoration:none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;border:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;@media&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;and&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;(max-width:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;772&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;background:none;margin-top:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;max-width:none;padding-right:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#logo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;background:url(//www.google.com/images/branding/googlelogo/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;x/googlelogo_color_&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;54&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;dp.png)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;no-repeat;margin-left:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-5&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;@media&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;only&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;and&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;(min-resolution:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;192&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;dpi)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#logo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;background:url(//www.google.com/images/branding/googlelogo/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;x/googlelogo_color_&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;54&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;dp.png)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;no-repeat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;%/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;x/googlelogo_color_&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;54&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;dp.png)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;@media&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;only&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;and&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;(-webkit-min-device-pixel-ratio:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#logo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;background:url(//www.google.com/images/branding/googlelogo/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;x/googlelogo_color_&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;54&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;dp.png)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;no-repeat;-webkit-background-size:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#logo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;display:inline-block;height:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;54&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px;width:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;href=//www.google.com/&amp;gt;&amp;lt;span&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;id=logo&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;aria-label=Google&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;p&amp;gt;&amp;lt;b&amp;gt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&amp;lt;/b&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;ins&amp;gt;That’s&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;an&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;error.&amp;lt;/ins&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;p&amp;gt;The&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;requested&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;code&amp;gt;/request&amp;lt;/code&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;was&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;found&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;server.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;ins&amp;gt;That’s&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;we&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;know.&amp;lt;/ins&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;구글로 부터 404 응답이 내려온 것을 확인할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;24-protect-your-services&quot;&gt;2.4 Protect your Services&lt;/h2&gt;

&lt;p&gt;이 장에서는 API Gateway의 기능 중 Rate limit 을 살펴보도록 합니다. 조금 당연한 이유일 수 있지만 원 글에서는 아래와 같이 Rate limit의 필요성을 설명하고 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Rate limiting protects the APIs from accidental or malicious overuse. Without rate limiting, each user may request as often as they like, which can lead to spikes of requests that starve other consumers. After rate limiting is enabled, API calls are limited to a fixed number of requests per second.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;쉽게 이아기해서 초당 요청 횟수를 제한하여 service가 예상된 요청에 대한 응답을 내려줄 수 있도록 제한하는 기능을 의미합니다.&lt;/p&gt;

&lt;h3 id=&quot;241-set-up-rate-limiting&quot;&gt;2.4.1 Set up Rate Limiting&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185356-66d5f300-e25f-11eb-8293-8978535d2378.png&quot; alt=&quot;Untitled 7&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 데이터 구성을 살펴보면, 분당 5회의 요청으로 제한하는 설정을 data로 주고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST http://xxx2.ap-northeast-2.elb.amazonaws.com:8001/plugins &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--data&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;rate-limiting &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--data&lt;/span&gt; config.minute&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;5 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--data&lt;/span&gt; config.policy&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rate-limiting&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;redis_database&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;redis_host&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;redis_port&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6379&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;redis_password&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;limit_by&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;consumer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;second&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;minute&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hour&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;day&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;year&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;year&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;policy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;local&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;fault_tolerant&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hide_client_headers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;header_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;redis_timeout&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;consumer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;created_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1623727072&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;a01a7967-c6aa-4168-83be-15654c333413&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;route&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;protocols&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;grpc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;grpcs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;242-validate-rate-limiting&quot;&gt;2.4.2 Validate Rate Limiting&lt;/h3&gt;

&lt;p&gt;분당 5회로 요청 제한이 설정되었으므로 간단하게 curl로 1분 내 5회 이상 요청을 해보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;여기서도 등록 이후에는 Admin(8001)이 아닌 API Gateway(80/8000)로 요청을 보내야 합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-X&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;http://xxx&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.elb.amazonaws.com:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/mock/request&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;API rate limit exceeded&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;25-improve-performance&quot;&gt;2.5 Improve Performance&lt;/h2&gt;

&lt;p&gt;이 장에서는 proxy caching 기능을 살펴봅니다. plugin 구성을 통해 쉽게 기능을 반영할 수 있습니다. proxy cache 기능이 무엇인지에 대해 아래와 같이 설명하고 있습니다&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Kong Gateway delivers fast performance through caching. The Proxy Caching plugin provides this fast performance using a reverse proxy cache implementation. It caches response entities based on the request method, configurable response code, content type, and can cache per Consumer or per API.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;쉽게 이야기하면 이전에 요청왔던 정보들을 기억하고 있다가 동일한 요청에 대해 Servce로 전달해 응답받을 필요가 없으므로 바로 사용자에게 내려주는 기능을 의미합니다.&lt;/p&gt;

&lt;h3 id=&quot;251-set-up-the-proxy-caching-plugin&quot;&gt;2.5.1 Set up the Proxy Caching plugin&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185357-66d5f300-e25f-11eb-94f6-c2619c4ba0d7.png&quot; alt=&quot;Untitled 8&quot; /&gt;&lt;/p&gt;

&lt;p&gt;내용을 살펴보면 30초간 TTL 구성동안 memory에 같은 요청이라면 저장 해두고 바로 응답으로 내려주도록 설정함을 알 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-X&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;http://a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9644&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;327&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4554813&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ee&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1e8-1978321371&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.elb.amazonaws.com:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8001&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/plugins&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--data&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;name=proxy-cache&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--data&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;config.content_type=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;application/json; charset=utf-8&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--data&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;config.cache_ttl=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--data&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;config.strategy=memory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;proxy-cache&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;content_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;application/json; charset=utf-8&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;vary_query_params&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cache_control&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;request_method&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;GET&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;HEAD&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;vary_headers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;response_code&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;301&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cache_ttl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;storage_ttl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;strategy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;memory&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;memory&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dictionary_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;kong_db_cache&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;consumer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;created_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1623727908&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;f5e6f07b-c6ca-45e2-9f3b-02af465b7130&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;route&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;protocols&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;grpc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;grpcs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;26-secure-services&quot;&gt;2.6 Secure Services&lt;/h2&gt;

&lt;p&gt;API Gateway의 기능중 중요한 역할을 하는 부분이기도 합니다. 주로 인증(Authentication) 과 관련된 기능을 의미합니다. 인증(Authentication)과 인가(Authorization)은 헷갈리지만 차이가 있는 개념입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185359-676e8980-e25f-11eb-9563-14e296dc5b77.png&quot; alt=&quot;Untitled 9&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.opennaru.com/opennaru-blog/jwt-json-web-token-with-microservice/&quot;&gt;http://www.opennaru.com/opennaru-blog/jwt-json-web-token-with-microservice/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;기본적으로 인증에 사용되는 방식은 아래와 같은 방법이 존재합니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Basic Authentication&lt;/li&gt;
  &lt;li&gt;Key Authentication&lt;/li&gt;
  &lt;li&gt;OAuth 2.0 Authentication&lt;/li&gt;
  &lt;li&gt;LDAP Authentication Advanced&lt;/li&gt;
  &lt;li&gt;OpenID Connect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;API Gateway에서 인증은 성공적으로 인증되지 않은 요청에 대해서 서비스로 요청을 전달하지 않습니다.&lt;/p&gt;

&lt;p&gt;여러 방법 중에 API Key 인증 방법을 예제로 다루고자 합니다.&lt;/p&gt;

&lt;h3 id=&quot;261-키-플러그인-등록&quot;&gt;2.6.1 키 플러그인 등록&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185360-676e8980-e25f-11eb-895c-38277a0ccfad.png&quot; alt=&quot;Untitled 10&quot; /&gt;&lt;/p&gt;

&lt;p&gt;key-auth의 플러그인을 등록하면, 키 사용자 등록 및 요청 처리를 별도로 해주지 않으면 아래 메시지로 요청에 대한 응답을 거부합니다.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;No API key found in request&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST http://a9644d2f327aa4554813ee01a9b4a1e8-1978321371.ap-northeast-2.elb.amazonaws.com:8001/routes/mocking/plugins &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--data&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;key-auth
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;protocols&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;grpc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;grpcs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;7581a3ae-7107-4361-8e32-c91f316214ff&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;created_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1623806947&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;route&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;81580cf8-3a6c-4b37-95df-5e810f41b07e&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;key_in_body&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;key_names&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;apikey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hide_credentials&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;run_on_preflight&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;key_in_header&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;key_in_query&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;key-auth&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;consumer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;262-키-사용자-등록&quot;&gt;2.6.2 키 사용자 등록&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185361-68072000-e25f-11eb-98e2-57e66441af31.png&quot; alt=&quot;Untitled 11&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST http://a9644d2f327aa4554813ee01a9b4a1e8-1978321371.ap-northeast-2.elb.amazonaws.com:8001/consumers/ &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--data&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;consumer &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--data&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;custom_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;consumer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;created_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1623806475&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;consumer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;48fe36d7-b463-466f-a2db-a61c5a6941b7&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;custom_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;consumer&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;263-api-키-등록&quot;&gt;2.6.3 API 키 등록&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185362-689fb680-e25f-11eb-8422-04aead57949f.png&quot; alt=&quot;Untitled 12&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 내용을 보면 key-auth는 RESTFul resource 구조 상 consumer에 종속되어 관리되는 것을 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-X&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;http://a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9644&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;327&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4554813&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ee&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1e8-1978321371&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.elb.amazonaws.com:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8001&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/consumers/consumer/key-auth&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--data&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;key=apikey&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;created_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1623807181&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;apikey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;consumer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;48fe36d7-b463-466f-a2db-a61c5a6941b7&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;4bd5a77c-bcd1-43d4-a738-f5aac2d348ce&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ttl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;264-api-키-반영-테스트&quot;&gt;2.6.4 API 키 반영 테스트&lt;/h3&gt;

&lt;p&gt;구성된 API Route 하단에 아래와 같은 파라미터로 API Key를 전달할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;/?apikey=apikey&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;키 포함되지 않은 요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;http://a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9644&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;327&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4554813&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ee&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1e8-1978321371&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.elb.amazonaws.com:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/mock&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;키 포함되지 않은 요청에 대한 응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;No API key found in request&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;키 포함 요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;http://a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9644&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;327&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4554813&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ee&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1e8-1978321371&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.elb.amazonaws.com:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/mock/?apikey=apikey&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;키 포함 요청에 대한 응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;meta&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;http-equiv=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;content-type&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text/html;charset=utf-8&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;TITLE&amp;gt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;301&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Moved&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;H&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;301&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Moved&amp;lt;/H&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;The&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;moved&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;A&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;HREF=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://www.google.com/?apikey=apikey&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;here&amp;lt;/A&amp;gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;google.com으로 요청하도록 api를 지정해두었기 때문에 성공적인 응답이 내려오는 것을 알 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;27-set-up-intelligent-load-balancing&quot;&gt;2.7 Set Up Intelligent Load Balancing&lt;/h1&gt;

&lt;p&gt;Load Balancing은 아래의 그림과 같이 같은 요청에 대해 부하를 분산하기 위해 사용됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185363-689fb680-e25f-11eb-82df-a7fabbfff57a.png&quot; alt=&quot;Untitled 13&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Load Balancing은 TCP/IP 레이어에 따라 가능한 기능들이 다른데,
Kubernetes에서 Service에서 Pod로 요청을 나누는 것은 L4 로드벨런서를 사용합니다.&lt;/p&gt;

&lt;p&gt;더 앞단에서 URL 요청에 의해 부하를 분산시킬 수 있는 Ingress라 통칭하는 것들은 L7 로드벨런서를 사용하는데, Kong Gateway는 L7 로드밸런서의 기능을 합니다.&lt;/p&gt;

&lt;h3 id=&quot;271-로드밸런서-구성-및-테스트&quot;&gt;2.7.1 로드밸런서 구성 및 테스트&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125185364-69384d00-e25f-11eb-8ea6-df182e4d2b63.png&quot; alt=&quot;Untitled 14&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 내용을 바탕으로 아래처럼 이전에 설정해둔 route 에 대해 google.com과 &lt;a href=&quot;http://naver.com&quot;&gt;naver.com&lt;/a&gt; 으로 로드벨런싱 하는 과정을 진행해봅니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;로드벨런서에 대한 upstream 생성&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-X&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;http://a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9644&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;327&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4554813&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ee&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1e8-1978321371&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.elb.amazonaws.com:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8001&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/upstreams&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--data&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;name=upstream&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;서비스에 생성한 upstream 연결&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-X&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;PATCH&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;http://a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9644&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;327&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4554813&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ee&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1e8-1978321371&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.elb.amazonaws.com:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8001&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/services/example_service&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--data&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;host=&apos;upstream&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;로드벨런서 taget 등록&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-X&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;http://a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9644&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;327&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4554813&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ee&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1e8-1978321371&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.elb.amazonaws.com:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8001&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/upstreams/upstream/targets&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--data&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;target=&apos;naver.com:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-X&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;http://a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9644&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;327&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4554813&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ee&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1e8-1978321371&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.elb.amazonaws.com:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8001&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/upstreams/upstream/targets&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--data&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;target=&apos;google.com:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;로드벨런싱 테스트&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; GET http://a9644d2f327aa4554813ee01a9b4a1e8-1978321371.ap-northeast-2.elb.amazonaws.com::8000/mock
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;3-정리&quot;&gt;3. 정리&lt;/h1&gt;

&lt;p&gt;본 글을 통해 Kong Admin으로 API를 구성하고, 그와 관련된 다양한 내용들을 살펴보았습니다. 기본적으로 제공해주는 플러그인들은 일반적인 경우를 위해 고려되었기 때문에 API Gateway에 대한 일반적인 이해를 바탕으로 필요한 경우 직접 플러그인을 구성하여 시스템을 설계할 수도 있어 보입니다.&lt;/p&gt;

&lt;p&gt;또한 Konga를 이용해 API를 구성하면 직관적으로 기능을 이해할 수 있지만, 모든 기능을 Konga를 통해 확인하기 어려운 부분이 있으므로, 실 서비스에 활용할 목적이라면 Kong Guide 문서를 모두 읽어보시길 권장드립니다.&lt;/p&gt;

&lt;h1 id=&quot;4-참고자료&quot;&gt;4. 참고자료&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/pantsel/konga&quot;&gt;https://github.com/pantsel/konga&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.konghq.com/getting-started-guide/2.4.x/overview/&quot;&gt;https://docs.konghq.com/getting-started-guide/2.4.x/overview/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.konghq.com/getting-started-guide/2.4.x/prepare/#verify-the-kong-gateway-configuration&quot;&gt;https://docs.konghq.com/getting-started-guide/2.4.x/prepare/#verify-the-kong-gateway-configuration&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.opennaru.com/opennaru-blog/jwt-json-web-token-with-microservice/&quot;&gt;http://www.opennaru.com/opennaru-blog/jwt-json-web-token-with-microservice/&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Sun, 11 Jul 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/kong/Kong-Gateway-3-Kong-Admin-%EC%9C%BC%EB%A1%9C-API-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0/</link>
            <guid isPermaLink="true">https://0leaf.github.io/kong/Kong-Gateway-3-Kong-Admin-%EC%9C%BC%EB%A1%9C-API-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0/</guid>
            
            <category>Kong</category>
            
            <category>Kong Admin</category>
            
        
            <category>Kong</category>
            
        </item>
        
        <item>
            <title>Kong Gateway 2. Kong on kubernetes  (Kong, Konga)</title>
            <description>&lt;p&gt;Kong, Konga에 대한 설명 및 구성 과정을 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;0-들어가기-전에&quot;&gt;0. 들어가기 전에&lt;/h1&gt;

&lt;p&gt;먼저 Kong API Gateway를 도입하기 전에 istio ingress 구성이나, nginx ingress 구성이 k8s 내에 완료되어 외부 요청에 대한 처리를 할 수 있음을 가정합니다. 특히 istio ingress로 구성되어 있는 상태를 기본으로 가정합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125184646-828aca80-e25a-11eb-9553-931cc05365c1.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/services-networking/ingress/&quot;&gt;https://kubernetes.io/ko/docs/concepts/services-networking/ingress/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125184648-86b6e800-e25a-11eb-8ee8-2590bcdb749e.png&quot; alt=&quot;Untitled 1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 그림은 각각 ngnix igress와 istio ingress 구성을 통해 외부 요청을 처리해주는 것을 표현합니다. 이러한 ingress들은 주로 resverse proxy의 기능을 하며 인증 등의 추가적인 기능을 위해 API Gateway가 필요할 경우 ingress 단 혹은 더 앞단에 이를 대체하는 API Gateway를 두고자 하며, 이를 Kong 으로 구성하고자 합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://istio.io/v1.9/docs/examples/virtual-machines/&quot;&gt;https://istio.io/v1.9/docs/examples/virtual-machines/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.nginx.com/blog/wait-which-nginx-ingress-controller-kubernetes-am-i-using/&quot;&gt;https://www.nginx.com/blog/wait-which-nginx-ingress-controller-kubernetes-am-i-using/&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;1-kong-on-kubernetes&quot;&gt;1. Kong on Kubernetes&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://istio.io/v1.9/docs/setup/getting-started/&quot;&gt;Istio 구성&lt;/a&gt;을 마친 kubernetes 환경에서 kong gateway로 ingress 기능을 처리하는 구조 및 설명이 &lt;a href=&quot;https://konghq.com/blog/kong-istio-setting-service-mesh-kubernetes-kiali-observability/&quot;&gt;다음 글&lt;/a&gt;에 잘 설명되어 있습니다.&lt;/p&gt;

&lt;p&gt;본 글에 내용중 아래 그림이 있는데 ingress의 역할을 하게 될 Kong API Gateway가 앞에서 요청을 받아주고, K8S 내의 서비스들로 Upstream 요청을 전달하게 될 것입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125184650-87e81500-e25a-11eb-8d61-11f03b66631f.png&quot; alt=&quot;Untitled 2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Isito 구성 과정에서 virtual service manifest 변경을 통해 routing을 설정하고 각 서비스로 요청을 전달했는데, Kong API Gateway로 구성하게 되면 직접 route 주소에 대해 service를 연결시킬 수 있습니다.&lt;/p&gt;

&lt;p&gt;또한 Konga라는 front web page를 통해 Kong Admin의 설정을 쉽게 변경할 수 있는데, 그 과정도 다루어 보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;아래 설치 환경은 ****Kubernetes 내 에서 진행됨을 말씀드립니다.&lt;/p&gt;

&lt;h1 id=&quot;2-kong&quot;&gt;2. Kong&lt;/h1&gt;

&lt;h2 id=&quot;21-kong&quot;&gt;2.1 Kong&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/Kong/kong&quot;&gt;링크&lt;/a&gt; 에서 kong에 대해 자세히 설명하고 있으며 API Gateway의 구현체입니다. 설명에 따르면 nginx 기반 lua plugin들로 그 기능들을 수행한다고 합니다. Kong API Gateway는 Enterprise 버전과, OSS(Open Source) 버전을 모두 제공하고 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Kong can help by acting as a gateway (or a sidecar) for microservices requests while providing load balancing, logging, authentication, rate-limiting, transformations, and more through plugins.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125184651-8880ab80-e25a-11eb-8214-547e72300772.png&quot; alt=&quot;Untitled 3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;설명에 따르면, load balancing, 로깅, 인증 등 API Gateway가 가져야할 기능들을 다양한 플러그인을 통해 제공할 수 있다고 합니다.&lt;/p&gt;

&lt;h2 id=&quot;22-kong-설치&quot;&gt;2.2 Kong 설치&lt;/h2&gt;

&lt;p&gt;기본적으로 공식 helm chart로 kong을 설치하게 되면 아래와 같은 방식으로 설치하도록 가이드하고 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;helm repo add kong https://charts.konghq.com
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;helm repo update

&lt;span class=&quot;c&quot;&gt;# Helm 2&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;helm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;kong/kong

&lt;span class=&quot;c&quot;&gt;# Helm 3&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;helm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;kong/kong &lt;span class=&quot;nt&quot;&gt;--generate-name&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--set&lt;/span&gt; ingressController.installCRDs&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/Kong/charts&quot;&gt;https://github.com/Kong/charts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;하지만 위 설정대로 진행하면 kong은 dbless 방식으로 뜨게 되고, 나중에 konga 툴로 service 나 route 등을 등록할 수 없게 됩니다. 따라서 &lt;a href=&quot;https://charts.bitnami.com/bitnami&quot;&gt;링크&lt;/a&gt;에서 구성된 kong chart는 default로 postgres db가 K8S 내에서 kong과 같이 뜨도록 구성되어 있습니다.&lt;/p&gt;

&lt;p&gt;물론 kong 공식 charts에서 yaml manifest를 변경함으로 db 구성을 지정할 수 있지만, 효율적인 과정을 위해 아래 내용으로 진행하도록 합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;kong 설치 진행 (with posgres)&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

helm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;kong &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;--set&lt;/span&gt; service.exposeAdmin&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;--set&lt;/span&gt; ingressController.installCRDs&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;--set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;kong &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
bitnami/kong
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://artifacthub.io/packages/helm/bitnami/kong&quot;&gt;링크&lt;/a&gt;에서 살펴보면, 여러가지 옵션을 변경할 수 있도록 문서화가 잘 되어있습니다.&lt;/p&gt;

&lt;p&gt;기본적으로 bitnami의 helm chart는 postrgres가 default로 설정되어 있기 때문에 위 구성대로 kong을 설치하게 되면 postgres db가 함께 뜨고, kong admin의 port는 expose 됩니다.&lt;/p&gt;

&lt;h1 id=&quot;3-konga&quot;&gt;3. Konga&lt;/h1&gt;

&lt;h2 id=&quot;31-konga&quot;&gt;3.1 Konga&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/pantsel/konga&quot;&gt;링크&lt;/a&gt;에서 konga에 대한 설명을 확인하실 수 있습니다. 기본적으로 kong은 API들을 구성할때 kong admin 주소로 rest 요청을 통해 설정합니다. 번거로운 작업이 될 수 있고 익숙하지 않은 사람에겐 불편한 작업이 됩니다.&lt;/p&gt;

&lt;p&gt;kong enterprise 버전에서는 admin page를 제공하는 것 같은데, open source 버전도 konga를 이용해 admin 페이지를 구성할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125184652-89194200-e25a-11eb-9035-96b00fbbf98f.png&quot; alt=&quot;Untitled 4&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Manage all Kong Admin API Objects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Import Consumers from remote sources (Databases, files, APIs etc.).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Manage multiple Kong Nodes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Backup, restore and migrate Kong Nodes using Snapshots.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Monitor Node and API states using health checks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Email &amp;amp; Slack notifications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Multiple users.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Easy database integration (MySQL, postgresSQL, MongoDB).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;32-konga-설치&quot;&gt;3.2 konga 설치&lt;/h2&gt;

&lt;p&gt;konga를 활용해서 다양한 설정을 적용하려면, &lt;strong&gt;Kong이 db와 함께 구성&lt;/strong&gt;되어 있어야 합니다. dbless로 구성될 경우 API 설정들의 조회는 가능하나, 추가/수정은 불가능합니다. 앞서 소개해드린 &lt;a href=&quot;https://artifacthub.io/packages/helm/bitnami/kong&quot;&gt;bitnami helm chart&lt;/a&gt;로 구성하면 자동으로 postgres db가 함께 구성되는데, 실제 서비스에 적용할 때는 안정적으로 구성된 db를 연동하는 것이 필요해 보입니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;konga 설치 진행&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;konga helm chart 주소에 있는 내용을 바탕으로 설치하고 repository에 있는 helm chart를 직접 설치합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/pantsel/konga&quot;&gt;https://github.com/pantsel/konga&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/pantsel/konga.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;konga/charts
helm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;konga konga/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;4-kong-konaga-연동&quot;&gt;4. Kong, Konaga 연동&lt;/h1&gt;

&lt;p&gt;kubectl get service 명령으로 아래와 같이 설치된 것을 확인하실 수 있습니다.&lt;/p&gt;

&lt;p&gt;여기서 저는 외부 접속을 허용하기 위해 kong, konga를 LoadBalancer Type 으로 변경했습니다.&lt;/p&gt;

&lt;p&gt;본 글에서 nlb 주소를 변경하였지만, 표시된 &lt;a href=&quot;http://xxx.ap-northeast-2.elb.amazonaws.com&quot;&gt;xxx.ap-northeast-2.elb.amazonaws.com&lt;/a&gt; 주소로 접속하시면 계정 생성 후 아래 화면을 보실 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;NAME                       TYPE           CLUSTER-IP       EXTERNAL-IP                                                                    PORT&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;S&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;                                                    AGE
kong                       LoadBalancer   172.20.249.30    xxx.ap-northeast-2.elb.amazonaws.com    80:32388/TCP,443:31964/TCP,8001:31018/TCP,8444:31915/TCP   17d
kong-metrics               ClusterIP      172.20.80.144    &amp;lt;none&amp;gt;                                                                         9119/TCP                                                   17d
kong-postgresql            ClusterIP      172.20.252.142   &amp;lt;none&amp;gt;                                                                         5432/TCP                                                   17d
kong-postgresql-headless   ClusterIP      None             &amp;lt;none&amp;gt;                                                                         5432/TCP                                                   17d
konga                      LoadBalancer   172.20.126.171   xxx.ap-northeast-2.elb.amazonaws.com   80:31741/TCP                                               17d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125184653-89b1d880-e25a-11eb-8311-70d86f339947.png&quot; alt=&quot;Untitled 5&quot; /&gt;&lt;/p&gt;

&lt;p&gt;APPLICATION-CONNECTIONS 페이지에서 위와 같이 kong admin 주소를 연결해주면 Kong API Gateway의 설정된 정보들을 읽을 수 있습니다.&lt;/p&gt;

&lt;p&gt;NLB로 public url 주소가 있는 경우 그 주소를 입력해도 되고, 같은 네트웍 상에서 구성되었다면 위와 같이 service 명으로도 연동 가능합니다.&lt;/p&gt;

&lt;h1 id=&quot;6-api-설정-테스트&quot;&gt;6. API 설정 테스트&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125184655-89b1d880-e25a-11eb-96bb-71c8255beb5a.png&quot; alt=&quot;Untitled 6&quot; /&gt;&lt;/p&gt;

&lt;p&gt;먼저 Kong API Gateway의 구성은 위 그림을 통해 보면 자세히 알 수 있습니다.&lt;/p&gt;

&lt;p&gt;간단한 API 들의 연동을 테스트 해보려고 하는데, 최소한으로 Service → Route 를 설정해야 합니다.&lt;/p&gt;

&lt;p&gt;뒤 내용에서 살펴보겠지만 Route는 Service에 종속되고, Consumer는 Route에 종속되는 형태로 구성됩니다.&lt;/p&gt;

&lt;p&gt;Konga를 설치하지 않았다면 REST 기반의 &lt;a href=&quot;https://docs.konghq.com/gateway-oss/2.4.x/admin-api/&quot;&gt;Admin API&lt;/a&gt; 로 구성하는 방법이 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125184656-8a4a6f00-e25a-11eb-8587-02433683ce03.png&quot; alt=&quot;Untitled 7&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Konga를 통해 위와 같은 구성의 포털로 호출하는 API를 설정하는 것을 살펴보도록 하겠습니다.&lt;/p&gt;

&lt;h2 id=&quot;61-service-구성&quot;&gt;6.1 Service 구성&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125184658-8a4a6f00-e25a-11eb-9d90-81cdcdf1ce60.png&quot; alt=&quot;Untitled 8&quot; /&gt;&lt;/p&gt;

&lt;p&gt;왼쪽 탭의 Services에서 ADD NEW SERVICE를 누르면 위 화면을 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;Url을 위와 같이 구성해주면, Host, Port, Path 등이 자동으로 들어가게 됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125184659-8ae30580-e25a-11eb-99d0-96cb39c06ecc.png&quot; alt=&quot;Untitled 9&quot; /&gt;&lt;/p&gt;

&lt;p&gt;생성된 google service를 선택하면 필요한 내용들이 자동으로 들어가있는 것을 볼 수 있고, 왼쪽 탭에 Routes와Plugins을 통해 Service에 Routes와 Plugins이 종속되어 있음을 확인할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;62-route-구성&quot;&gt;6.2 Route 구성&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125184660-8ae30580-e25a-11eb-9077-4c3599bf4297.png&quot; alt=&quot;Untitled 10&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 사용자가 호출할 때 http:&lt;a href=&quot;http://kong&quot;&gt;/&lt;/a&gt;/{kong address}/{route} 로 요청할 수 있도록 Routes를 구성해야 하는데, 왼쪽 탭의 Routes를 누르면 사진처럼 &lt;strong&gt;YOU CAN ONLY CREATE ROUTES FROM A SERVICE PAGE&lt;/strong&gt;라는 링크를 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;누르면 결국 6.1에서 봤던 서비스 화면으로 이동하게 됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125184662-8b7b9c00-e25a-11eb-9dfc-f7037b9bb873.png&quot; alt=&quot;Untitled 11&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125184663-8b7b9c00-e25a-11eb-92f3-c8cead540820.png&quot; alt=&quot;Untitled 12&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여러 설정을 구성할 수 있지만 테스트를 위해 붉게 표시된 부분들만 구성해주도록 합니다.&lt;/p&gt;

&lt;p&gt;Paths와 Meethods는 반드시 &lt;strong&gt;엔터 를 눌러서 회색 모양&lt;/strong&gt;으로 만들어주셔야 합니다.&lt;/p&gt;

&lt;p&gt;그렇지 않으면 설정이 저장되지 않습니다.&lt;/p&gt;

&lt;h2 id=&quot;63-consumer-구성&quot;&gt;6.3 Consumer 구성&lt;/h2&gt;

&lt;p&gt;6장 도입부 그림을 보면 consumer 구성을 볼 수 있는데, 인증 등의 처리를 위해 consumer를 구성할 수 있습니다. (특정 사람만 google로 요청할 수 있도록 인증/인가)&lt;/p&gt;

&lt;p&gt;하지만 이 글에선 기본적인 API 설정에 대해서만 다루는 것이 목표이기 때문에 본 글에서 consumer는 다루지 않도록 하며 기회가 되면 다른 chapter에서 다루어 보도록 하겠습니다.&lt;/p&gt;

&lt;h2 id=&quot;64-테스트&quot;&gt;6.4 테스트&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; GET &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;kong nlb address&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/google
curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; GET &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;kong nlb address&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/naver
curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; GET &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;kong nlb address&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/kakao
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;7-정리&quot;&gt;7. 정리&lt;/h1&gt;

&lt;p&gt;위 과정은 kong, konga 모두를 연동하고 다양한 실험을 진행한 후에 정리한 글입니다.&lt;/p&gt;

&lt;p&gt;여러 글을 참고하여 구성했으나, db없이 구성했다가 다시 삭제하고 등의 시행착오를 겪었습니다. 별 내용은 없고 helm chart에 대한 자세한 설명을 섞진 않았으나 실험을 진행하기에 알맞게 잘 구성된 helm chart와 과정을 소개하는 것과 직접 시도해보지 않고 해당 과정으로 어떤 식으로 진행되는 지를 공유드리는 것이 목적임을 밝힙니다.&lt;/p&gt;

&lt;h1 id=&quot;6-참고자료&quot;&gt;6. 참고자료&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/services-networking/ingress/&quot;&gt;https://kubernetes.io/ko/docs/concepts/services-networking/ingress/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://istio.io/v1.9/docs/examples/virtual-machines/&quot;&gt;https://istio.io/v1.9/docs/examples/virtual-machines/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.nginx.com/blog/wait-which-nginx-ingress-controller-kubernetes-am-i-using/&quot;&gt;https://www.nginx.com/blog/wait-which-nginx-ingress-controller-kubernetes-am-i-using/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/Kong/charts&quot;&gt;https://github.com/Kong/charts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/pantsel/konga&quot;&gt;https://github.com/pantsel/konga&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Sat, 10 Jul 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/kong/Kong-Gateway-2-Kong-on-kubernetes-(Kong,Konga)/</link>
            <guid isPermaLink="true">https://0leaf.github.io/kong/Kong-Gateway-2-Kong-on-kubernetes-(Kong,Konga)/</guid>
            
            <category>Kong</category>
            
            <category>Konga</category>
            
        
            <category>Kong</category>
            
        </item>
        
        <item>
            <title>Kong Gateway 1. API Gateway, Reverse Proxy, Ingress</title>
            <description>&lt;p&gt;API Gateway, Reverse Proxy, Ingress 에 대해 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;0-들어가기-전에&quot;&gt;0. 들어가기 전에&lt;/h1&gt;

&lt;p&gt;Kuberentes 기반 MSA 서비스를 구성함에 있어 Gateway와 Ingress 부분을 어떻게 구성할지 고민이 필요했습니다. 그 과정에서 Kong Gateway가 대안으로 고려되었는데, 그 전에 API Gateway, Reverse Proxy, Ingress 등의 기본적인 개념을 정리하고 넘어가기 위해 글을 정리합니다.&lt;/p&gt;

&lt;h1 id=&quot;1-api-gateway-reverse-proxy-ingress&quot;&gt;1. API Gateway, Reverse Proxy, Ingress&lt;/h1&gt;

&lt;p&gt;헷갈리는 개념은 명확하게 짚고 넘어가야 나중에 문제가 발생하지 않으므로, 이미 알고있는 내용이라도 공신력(?) 있는 정보를 바탕으로 정확하게 짚어보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;간단하게는 세 개념 모두 외부의 요청을 받아 내부의 서비스를 처리하는 기능을 합니다.&lt;/p&gt;

&lt;h2 id=&quot;1-api-gateway&quot;&gt;1. API Gateway&lt;/h2&gt;

&lt;p&gt;먼저 &lt;a href=&quot;https://en.wikipedia.org/wiki/API_management&quot;&gt;wiki&lt;/a&gt;에 관련된 내용을 참고해봅니다.&lt;/p&gt;

&lt;p&gt;아래 내용을 보면 API Gateway의 기능 중 일부를 자세히 설명하고 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;API frontend 역할을 하고, API 요청을 수신하고, 제한 및 보안 정책을 시행하고, 요청을 백엔드 서비스에 전달한 다음, 요청자에게 다시 응답을 전달하는 서버입니다.
게이트웨이에는 요청과 응답을 직접 조정 하고 수정 하는 변환 엔진이 포함되는 경우가 많습니다.
게이트웨이는 분석 데이터 수집 및 캐싱 제공과 같은 기능도 제공할 수 있습니다.
게이트웨이는 인증, 권한 부여, 보안, 감사 및 규정 준수를 지원하는 기능을 제공할 수 있습니다.
게이트웨이에는 요청과 응답을 직접 조정 하고 수정 하는 변환 엔진이 포함되는 경우가 많습니다.
리버스 프록시로 구현할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;이런 기능을 하는 API Gateway는 &lt;a href=&quot;https://aws.amazon.com/ko/api-gateway/&quot;&gt;AWS&lt;/a&gt; 나 &lt;a href=&quot;https://cloud.google.com/api-gateway&quot;&gt;GCP&lt;/a&gt; 등의 public cloud에서 console로 쉽게 구성하도록 제공하기도 하며, 서두에 언급한 &lt;a href=&quot;https://konghq.com/kong/&quot;&gt;Kong API Gateway&lt;/a&gt; 와 같이 open source로 구성된 프로젝트도 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125157471-22d2e780-e1a6-11eb-9888-cfe26fc89cff.png&quot; alt=&quot;image&quot; class=&quot;align-center&quot; max-width=&quot;50%&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;2-reverse-proxy&quot;&gt;2. Reverse Proxy&lt;/h2&gt;

&lt;p&gt;마찬가지로 &lt;a href=&quot;https://en.wikipedia.org/wiki/Reverse_proxy&quot;&gt;wiki&lt;/a&gt;에 관련된 내용을 참고해봅니다.&lt;/p&gt;

&lt;p&gt;아래 내용은 Reverse Proxy의 기능 중 일부를 설명하고 있는데 표현이 다르지만 사실 API Gateway에서 표현된 내용과 일치하는 부분들이 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;역방향 프록시를 다른 기술과 함께 사용하여 내부 서버 간의 로드 균형 을 조정 합니다.
역방향 프록시는 정적 콘텐츠 캐시를 유지할 수 있으므로 이러한 내부 서버와 내부 네트워크의 부하를 더욱 줄일 수 있습니다.
역방향 프록시가 클라이언트와 역방향 프록시 간의 통신 채널에 압축 또는 TLS 암호화 와 같은 기능을 추가하는 것도 일반적입니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;리버스 프록시 서버는 &lt;a href=&quot;https://en.wikipedia.org/wiki/Apache_HTTP_Server&quot;&gt;Apache&lt;/a&gt; , &lt;a href=&quot;https://en.wikipedia.org/wiki/Nginx&quot;&gt;Nginx&lt;/a&gt; 및 Caddy 와 같은 널리 사용되는 오픈 소스 웹 서버 에서 구현됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125157477-28c8c880-e1a6-11eb-97b2-0e2f5046e17e.png&quot; alt=&quot;image&quot; class=&quot;align-center&quot; max-width=&quot;50%&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;3-ingress&quot;&gt;3. Ingress&lt;/h2&gt;

&lt;p&gt;이번엔 kubernetes에서 자주 언급되는 용어인 &lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/services-networking/ingress/&quot;&gt;Ingress&lt;/a&gt;에 대한 내용을 살펴봅니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;클러스터 내의 서비스에 대한 외부 접근을 관리하는 API 오브젝트이며, 일반적으로 HTTP를 관리함.
인그레스는 부하 분산, SSL 종료, 명칭 기반의 가상 호스팅을 제공할 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ingress 역할을 하기 위해 nginx ingress, istio ingress 등의 구성으로 외부 요청을 내부로 전달하는 목적의 기능을 수행합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125157482-2fefd680-e1a6-11eb-8c6a-7d3950ca7b46.png&quot; alt=&quot;image&quot; class=&quot;align-center&quot; max-width=&quot;50%&quot; /&gt;&lt;/p&gt;

&lt;p&gt;kubernetes의 Ingress의 개념은 결국 API Gateway와 Reverse Proxy의 개념과 맞닿아 있습니다. 외부 요청을 받아 내부의 서비스로 전달하는 과정을 어떻게 구성할지 고민이 필요합니다.&lt;/p&gt;

&lt;h1 id=&quot;2-정리&quot;&gt;2. 정리&lt;/h1&gt;

&lt;p&gt;위 내용들을 살펴보면 외부 요청을 받아 내부의 서비스로 전달하는 목적에 대해 유사한 기능들을 설명하고 있습니다. 실제로 API Gateway가 Proxy보다 더 상위 개념이라고 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;간단한 서버 구성의 경우 외부의 호출을 처리하기 위해 nginx proxy 서버로 처리 가능합니다.&lt;/p&gt;

&lt;p&gt;다만, 서비스 영역이 커지면서 외부의 요청을 제한하거나 처리하기 위한 인증 등의 처리가 필요할 경우 앞단에 API Gateway로 통합된 기능을 처리하게 됩니다.&lt;/p&gt;

&lt;p&gt;실제로 앞서 언급된 Kong API Gateway는 개발 기반 자체가 nginx 위에서 lua로 개발된 plugin들의 구성으로 되어있다고 합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.akana.com/blog/api-proxy-vs-api-gateway&quot;&gt;akana 에서 작성한 글&lt;/a&gt;에 적당한 그림이 있어 첨부하여 이 글을 마무리하고자 합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/125157488-37af7b00-e1a6-11eb-8ecc-10c65ef3a042.png&quot; alt=&quot;image&quot; class=&quot;align-center&quot; max-width=&quot;50%&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;3-참고자료&quot;&gt;3. 참고자료&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/API_management&quot;&gt;https://en.wikipedia.org/wiki/API_management&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Reverse_proxy&quot;&gt;https://en.wikipedia.org/wiki/Reverse_proxy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/services-networking/ingress/&quot;&gt;https://kubernetes.io/ko/docs/concepts/services-networking/ingress/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.akana.com/blog/api-proxy-vs-api-gateway&quot;&gt;https://www.akana.com/blog/api-proxy-vs-api-gateway&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://hits.seeyoufarm.com&quot;&gt;&lt;img src=&quot;https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2F0leaf.github.io%2Fkong%2FKong-Gateway-1-API-Gateway-Reverse-Proxy-Ingress%2F&amp;amp;count_bg=%2379C83D&amp;amp;title_bg=%23555555&amp;amp;icon=&amp;amp;icon_color=%23E7E7E7&amp;amp;title=count&amp;amp;edge_flat=false&quot; alt=&quot;Hits&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Sat, 10 Jul 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/kong/Kong-Gateway-1-API-Gateway-Reverse-Proxy-Ingress/</link>
            <guid isPermaLink="true">https://0leaf.github.io/kong/Kong-Gateway-1-API-Gateway-Reverse-Proxy-Ingress/</guid>
            
            <category>Kong</category>
            
            <category>API Gateway</category>
            
            <category>Reverse Proxy</category>
            
            <category>Ingress</category>
            
        
            <category>Kong</category>
            
        </item>
        
        <item>
            <title>Python - WSGI 와 Flask 연동에 대한 필요성</title>
            <description>&lt;p&gt;본 글은 python 기반 Flask로 서버를 구성함에 있어 WSGI 와의 연동에 대한 필요성을 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;0-들어가기-전에&quot;&gt;0. 들어가기 전에&lt;/h1&gt;

&lt;p&gt;요즘 Tensorflow와 Torch 기반으로 모델 개발을 하시는 분들이 많은데 구축한 모델을 추론하는 서버를 서비스에 적용하거나 테스트할 목적으로 flask로 구성하는 경우가 많을 것입니다.&lt;/p&gt;

&lt;p&gt;물론 &lt;a href=&quot;https://www.tensorflow.org/tfx/serving/architecture?hl=ko&quot;&gt;TensorFlow serving&lt;/a&gt; 과 &lt;a href=&quot;https://pytorch.org/serve/&quot;&gt;Torch Serve&lt;/a&gt;에 대해서 다루는 글은 아니며, 딥러닝과 전혀 관계 없이 API 서버를 구성함에 있어 가벼움의 장점을 갖는 Flask로 많이 구성하시게 될 것입니다.&lt;/p&gt;

&lt;p&gt;python 기반의 프레임워크로 서버를 구성할 때 고민해야 할 포인트들이 많습니다. 그냥 python이 친숙하거나 쉽다고 Flask로 서버를 구성하여 실제 서비스 제공할 생각이라면 위험 할 수 있다고 생각합니다.&lt;/p&gt;

&lt;p&gt;그래서 두루뭉술한 개념들을 정리하고 고민해볼 포인트와 실험 해볼 포인트들을 정리하여 기술해보고자 합니다.&lt;/p&gt;

&lt;h1 id=&quot;1-서버-구성-비교-web-server--cgi--application-web-application-server&quot;&gt;1. 서버 구성 비교 (Web Server + CGI + Application, Web Application Server)&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/118359793-0fe5d180-b5c0-11eb-9879-dcf68da3e774.png&quot; alt=&quot;image&quot; class=&quot;align-center&quot; width=&quot;600&quot; height=&quot;330&quot; /&gt;&lt;/p&gt;

&lt;p&gt;본 글은 Web Server와 Web Application Server간의 차이 등을 다루고 자하는 글이 아니지만, 필요한 내용이 있어 간단한 그림을 준비했습니다. 더 자세한 구조 혹은 WAS, WebServer, CGI 등에 대해 잘 모르신다면 깊게 다룬 관련 글들이 많으므로 찾아보시길 권해드립니다. 두가지만 짧게 짚고 넘어가겠습니다.&lt;/p&gt;

&lt;h2 id=&quot;11-정적-웹서버-vs-동적-웹서버&quot;&gt;1.1. &lt;strong&gt;정적 웹서버 vs 동적 웹서버&lt;/strong&gt;&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;정적 웹서버 : 정적 웹 서버 혹은 스택은 HTTP 서버 (소프트웨어)가 있는 컴퓨터(하드웨어)로 구성되어 있습니다. 서버가 그 불려진 파일을 당신의 브라우저에게 전송하기 때문에 그것을 “정적”이라고 부릅니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;동적 웹서버 : 동적 웹 서버는 정적 웹 서버와 추가적인 소프트웨어(대부분 일반적인 &lt;strong&gt;애플리케이션 서버와 데이터베이스&lt;/strong&gt;)로 구성되어 있습니다. 애플리케이션 서버가 HTTP 서버를 통해 당신의 브라우저에게 불려진 파일들을 전송하기 전에, 애플리케이션 서버가 업데이트하기 때문에 이것을 동적이라고 부릅니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Learn/Common_questions/What_is_a_web_server&quot;&gt;mozilla&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;다시 말해서 html, javascript 만을 제공하는 정적 웹서버를 구성하고 싶다면 Flask로 띄울 필요가 없다&lt;/strong&gt;는 이야기 입니다.&lt;/p&gt;

&lt;p&gt;만약 &lt;strong&gt;db 연동이나 로직을 처리하는 application을 구성해야 하는 경우라면 그때 flask나 django가 필요&lt;/strong&gt;하다는 이야기 입니다.&lt;/p&gt;

&lt;h2 id=&quot;12-cgiwsgi는-왜-필요한가&quot;&gt;1.&lt;strong&gt;2. CGI/WSGI는 왜 필요한가?&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;CGI와 관련된 자세한 내용을 원하신다면 &lt;a href=&quot;https://docs.python.org/3.0/howto/webservers.html&quot;&gt;참고글&lt;/a&gt;을 한번 읽어보시길 권해드립니다. 여기서는 이해를 돕기 위해 쉽게 설명하고 넘어가도록 하겠습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;공용 게이트웨이 인터페이스(영어: Common Gateway Interface; CGI)는 웹 서버 상에서 사용자 프로그램을 동작시키기 위한 조합입니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EA%B3%B5%EC%9A%A9_%EA%B2%8C%EC%9D%B4%ED%8A%B8%EC%9B%A8%EC%9D%B4_%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4&quot;&gt;Wiki&lt;/a&gt;에 정리된 말 그대로 C로 만들어진 Ngnix Webserver 에서 다른 언어로 만들어진 application을 호출하고 그 결과를 사용자에게 전달하려면 중간에서의 처리를 담당하는 것이 필요하다고 생각 될 것 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;CGI를 사용하는 경우 : 클라이언트 -&amp;gt; 웹서버 -&amp;gt; CGI -&amp;gt; Application&lt;/li&gt;
  &lt;li&gt;WSGI를 사용하는 경우 : 클라이언트 -&amp;gt; 웹서버 -&amp;gt; WSGI (미들웨어) -&amp;gt; Application Server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WSGI는 Application Server를 연결해주는 미들웨어로서의 역할을 수행하며 그와 관련된 Python 계열의 WSGI는 gunicorn, uWSGI 등이 있으며 공식 문서를 보면 worker 기반으로 배포 시 서버를 효과적으로 구성할 수 있는 많은 옵션들을 제공해줍니다.&lt;/p&gt;

&lt;h2 id=&quot;13-flaskdjango-만-사용-한다는-것은&quot;&gt;1.3. Flask/django 만 사용 한다는 것은?&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/118359810-22f8a180-b5c0-11eb-98c8-69e47406c8c9.png&quot; alt=&quot;image&quot; class=&quot;align-center&quot; width=&quot;600&quot; height=&quot;250&quot; /&gt;&lt;/p&gt;

&lt;p&gt;flask/django만 이용해서 서버를 구성한다는 것은 사용자가 직접 Application Server로 호출 하게 한다는 의미라고 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;물론 flask가 정적 웹 서버를 제공하도록 만들 수도 있으니 그냥 저렇게 호출하면 안되냐고 생각하실 수 있는데, Web Server가 해주는 기능이 단순히 정적 웹 페이지를 내려주는 것만 하는 것이 아닙니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/Nginx&quot;&gt;nginx 기능&lt;/a&gt;을 보시면 로드 벨런싱부터 다른 많은 기능을 제공해 주고 있습니다. Flask만으로는 본래 웹서버가 처리해줘야 할 많은 기능들을 처리하기 어렵다는 이야기 입니다.&lt;/p&gt;

&lt;h1 id=&quot;2-flask는&quot;&gt;2. Flask는?&lt;/h1&gt;

&lt;p&gt;Flask는 python 기반 웹 애플리케이션 프레임워크이며 django와 달리 db와 같은 기능들을 자체 프레임워크에 포함하고 있지 않기 때문에 가볍습니다. 따라서 작은 프로젝트에서 부터 확장성이 필요한 여러 프로젝트까지 다양한 목적으로 많이 사용됩니다.&lt;/p&gt;

&lt;p&gt;개발 단계에서 Flask로 간단한 빌트인 서버를 띄울 수 있는데 실제 서비스 목적으로 배포해야 한다면 &lt;a href=&quot;https://flask.palletsprojects.com/en/1.1.x/quickstart/#a-minimal-application&quot;&gt;Flask 공식 글&lt;/a&gt;에서 WSGI를 붙여야 한다고 권장하고 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This launches a very simple builtin server, which is good enough for testing but probably not what you want to use in production. For deployment options see Deployment Options.
Flask’s built-in server is not suitable for production as it doesn’t scale well&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;flask app은 기본적으로 blocking 작업이 있을때 동기적으로 방식으로 동작하기 때문에 여러 요청이 있을 경우 순차적으로 응답합니다. File IO, 외부 API 호출, 딥러닝 모델 추론 등의 긴 연산 시간이 필요할 경우 WSGI와의 연동이 필요합니다.&lt;/p&gt;

&lt;h1 id=&quot;3-wsgi는&quot;&gt;3. WSGI는?&lt;/h1&gt;

&lt;p&gt;1번 항목에서 WSGI에 대한 언급을 조금 하긴 했는데, 이번 글에서는 대표적으로 많이 쓰이는 WSGI 중 uWSGI를 예를 들어서 정리해보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;uWSGI는 Nginx(Web Server)와 Flask를 연결해주는 인터페이스 역할 뿐만 아니라, &lt;a href=&quot;https://uwsgi-docs.readthedocs.io/en/latest/Options.html&quot;&gt;많은 기능&lt;/a&gt;을 제공하고 있습니다. 다른 WSGI들도 비슷한 기능들을 제공해주겠지만 각각의 비교는 이 글에&lt;/p&gt;

&lt;p&gt;서 다루지 않습니다.&lt;/p&gt;

&lt;p&gt;이 기능들 중에 Flask가진 단점 중 순차적 응답에 대한 문제를 multi process, thread 기반의 worker 방식으로 해결할 수 있습니다. 서버 구성 방식도 여러가지가 존재합니다.&lt;/p&gt;

&lt;p&gt;또한 Flask 서버에서 memory leak이 발생했을때 일정 메모리 이상 올라갈 경우 worker 를 재시작 하는 등의 옵션도 제공합니다. 이 문제와 관련해서는 &lt;a href=&quot;https://instagram-engineering.com/adaptive-process-and-memory-management-for-python-web-servers-15b0c410a043&quot;&gt;인스타그램&lt;/a&gt; 의 사례를 보면 이해가 됩니다.&lt;/p&gt;

&lt;p&gt;uWSGI와 Flask를 연동하여 서버를 구성하면 목적에 맞게 다양한 방식을 구성할 수 있습니다.&lt;/p&gt;

&lt;p&gt;prefork, lazyapp, emperor mode, zerg dance 등 시간이 되시면 &lt;a href=&quot;http://zarnovican.github.io/2016/02/15/uwsgi-graceful-reload/&quot;&gt;uWSGI 서버 배포 모드&lt;/a&gt; 글을 읽어보시면 각 모드에 대해 그림으로 이해하기 쉽게 설명해 놓았습니다.&lt;/p&gt;

&lt;p&gt;지금까지의 내용을 단순한 그림으로 정리하고 넘어가겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/118359812-2ab84600-b5c0-11eb-82ac-4b0c51c39517.png&quot; alt=&quot;image&quot; class=&quot;align-center&quot; width=&quot;600&quot; height=&quot;500&quot; /&gt;&lt;/p&gt;

&lt;p&gt;파란색 네모를 시간이 오래걸리는 요청이라고 생각하면 Flask로 직접 요청하는 것과 WSGI를 통해서 요청하는 것의 차이는 위의 모습으로 쉽게 이해할 수 있습니다. 물론 DB Connection이나 큰 딥러닝 모델을 물고 worker를 구성할 것인지 등의 구조는 서버 배포 모드 방식과 Application 코드 구성과 맞물려 있습니다.&lt;/p&gt;

&lt;p&gt;그림을 통해 보면 당연히 WSGI를 통해 요청하게 되면 시간이 많이 걸리는 요청에 대해 많은 사용자 트래픽을 효율적으로 처리할 수 있다는 것을 이해할 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;4-정리&quot;&gt;4. 정리&lt;/h1&gt;

&lt;p&gt;가벼운 마음으로 글을 작성하기 시작했는데 생각보다 하고싶은 말을 바로 적으려니 읽으시는 분의 배경 지식에 따라서 제 생각이 잘 전달되지 않을 것 같다고 생각했습니다. 원래는 flask에 대한 동시성 성능에 대한 테스트를 주로 다루려고 시작했던 글인데 관련된 개념 부터 정리하게 되었습니다. 이후 WSGI와 연관되는 내용들을 정리하고 공유드릴 수 있는 기회가 있으면 좋겠습니다.&lt;/p&gt;

&lt;h1 id=&quot;참고자료&quot;&gt;참고자료&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Learn/Common_questions/What_is_a_web_server&quot;&gt;https://developer.mozilla.org/ko/docs/Learn/Common_questions/What_is_a_web_server&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://flask.palletsprojects.com/en/1.1.x/quickstart/#a-minimal-application&quot;&gt;https://flask.palletsprojects.com/en/1.1.x/quickstart/#a-minimal-application&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.python.org/3.0/howto/webservers.html&quot;&gt;https://docs.python.org/3.0/howto/webservers.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://zarnovican.github.io/2016/02/15/uwsgi-graceful-reload/&quot;&gt;http://zarnovican.github.io/2016/02/15/uwsgi-graceful-reload/&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Sat, 15 May 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/python/WSGI%EC%99%80-Flask%EC%97%B0%EB%8F%99%EC%97%90-%EB%8C%80%ED%95%9C-%ED%95%84%EC%9A%94%EC%84%B1/</link>
            <guid isPermaLink="true">https://0leaf.github.io/python/WSGI%EC%99%80-Flask%EC%97%B0%EB%8F%99%EC%97%90-%EB%8C%80%ED%95%9C-%ED%95%84%EC%9A%94%EC%84%B1/</guid>
            
            <category>Python, Flask, WSGI</category>
            
        
            <category>Python</category>
            
        </item>
        
        <item>
            <title>Golang Testing - 2. HTTP Request Mocking</title>
            <description>&lt;p&gt;본 글은 golang으로 Testcase를 구성할 때 http request를 실제 서버로 보내지 않고, http request와 관련된 mock을 구현하는 방법에 대해서 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;0-시작하기-전에&quot;&gt;0. 시작하기 전에&lt;/h1&gt;

&lt;p&gt;golang으로 api 서버를 만들다보면 3rd api와 연동해야 하는 일이나 MSA 구조라면 간단한 비즈니스 로직을 처리하기 위해서 다른 서비스로 요청해야 하는 경우가 많을 것 입니다. 이런 상황에서 외부 연동에 대한 코드는 무시하고 fucntional한 unit 테스트만 진행하다 보면 &lt;a href=&quot;https://0leaf.github.io/golang/Golang-Testing-Unit-Test-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0/&quot;&gt;이전 글&lt;/a&gt;에서 언급되었던 cover 등으로 확인해봤을때 실제로 많은 영역의 코드를 테스트 할 수 없고 이는 리스크로 남게됩니다.&lt;/p&gt;

&lt;p&gt;물론 실제 서버로 직접 요청하는 것을 포함한 unit 테스트를 구성해도 좋지만 만약 다음의 경우라면 문제가 될 가능성이 있습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;목적지 서버가 k8s 같은 클러스터 내부에 있어 외부에서 직접 호출할 수 없다. (배포 후에나 요청 가능하다)&lt;/li&gt;
  &lt;li&gt;목적지 서버가 먼저 떠있어야 로직상 테스트를 돌릴 수 있기에 배포 순서를 지켜야 한다.&lt;/li&gt;
  &lt;li&gt;단순히 자체 코드에 대한 영향성 만을 보고싶은데 목적지 서버에 종속성이 생긴다.&lt;/li&gt;
  &lt;li&gt;실제 서버로 요청해버리면 응답 속도가 너무 늦어 테스트나 배포 시간이 오래 걸린다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이러한 불편한 상황을 막기 위해 local에서 기대되는 요청에 대한 응답을 mocking 하여 실제 서버에는 요청하지 않지만 마치 요청에 대한 응답을 받은 것 같은 기대효과를 얻을 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;1-예제-시나리오&quot;&gt;1. 예제 시나리오&lt;/h1&gt;

&lt;p&gt;예를 들면 아래 그림처럼 productpage 서버를 구현한다고 가정해봅시다. 그러면 details 서버와 review 서버로 요청을 보낸 뒤 사용자에게 응답을 내려주는 기능을 구현해야 합니다.&lt;/p&gt;

&lt;p&gt;그리고 details 서버와 reviews 서버는 외부에서 호출이 불가능하도록 구현이 되어있고, 배포 후에 해당 망 안에서 호출할 수 있는 경우라고 가정해봅니다.&lt;/p&gt;

&lt;p&gt;이런 경우엔 실제 서버로 요청을 보내는 기능을 포함해서 테스트케이스를 구성할 수 없습니다. 이런 문제 상황을 극복하기 위해 HTTP Request를 mocking 하는 방법에 대해 기술하고자 합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/118353119-eae16680-b59f-11eb-9190-242552bcf7a0.png&quot; alt=&quot;image&quot; /&gt;
&lt;a href=&quot;https://raw.githubusercontent.com/kiali/kiali.io/master/static/images/documentation/features/graph-overview.png&quot;&gt;https://raw.githubusercontent.com/kiali/kiali.io/master/static/images/documentation/features/graph-overview.png&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;2-interface-에-대한-이해&quot;&gt;2. Interface 에 대한 이해&lt;/h1&gt;

&lt;p&gt;먼저 본 과정을 이해하시려면 interface를 이해하셔야 합니다. 다른 java나 c++ 같은 객체 지향 언어를 공부하신 분들이라면 잘 알고계실 다형성과 관련된 이야기 입니다. 쉽게 이야기하실 수 있도록 그림을 하나 두고 이야기해보겠습니다. 혹시라도 제대로 interface에 대해 공부하시고 넘어가고 싶으시다면, 관련해서 깊게 다룬 글들을 쉽게 검색해서 찾아보실 수 있으므로 잠깐 이 글 읽는 것을 멈춘뒤 이해하고 나서 진행하시는 것도 좋습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/118353128-f03eb100-b59f-11eb-9d9a-c19b704f7dcb.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그림 출처 : &lt;a href=&quot;https://docsplayer.org/77693386-Powerpoint-%ED%94%84%EB%A0%88%EC%A0%A0%ED%85%8C%EC%9D%B4%EC%85%98.html&quot;&gt;https://docsplayer.org/77693386-Powerpoint-프레젠테이션.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;사실 이 글에서 다루려고 하는건 복잡한 내용이 아니라 http clinet의 mocking과 관련된 부분만 언급하려고 합니다.&lt;/p&gt;

&lt;p&gt;그림으로 보시면 유명하고 뻔한 짖다 모델을 가져왔습니다. &lt;strong&gt;“짖다” 의 동작을 “누가” 하는지에 따라 다르게 처리한다&lt;/strong&gt;. 이 정도 개념으로만 이해하시면 충분할 것 같습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;“짖다 - httpRequset”&lt;/strong&gt; 라는 동작을&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;본 코드(강아지)&lt;/strong&gt; 가 하면 &lt;strong&gt;“멍멍”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;테스트 코드(고양이)&lt;/strong&gt; 가 하면 &lt;strong&gt;“야옹”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;과 같은 느낌이 되겠네요.&lt;/p&gt;

&lt;p&gt;golang에서도 이러한 구현을 위해 interface 기능을 제공합니다.&lt;/p&gt;

&lt;h1 id=&quot;3-테스트-구성&quot;&gt;3. 테스트 구성&lt;/h1&gt;

&lt;h2 id=&quot;31-예제-시나리오&quot;&gt;3.1. 예제 시나리오&lt;/h2&gt;

&lt;p&gt;이번 예제에서도 자주 쓰는 google, naver, kakao로 http 요청을 하는 정말 간단한 코드를 두고 테스트케이스를 구성해보도록 하고, 구현 먼저 하고 테스트코드를 작성하는 순서로 진행하겠습니다.&lt;/p&gt;

&lt;p&gt;또한 golang 기본 tool 로 제공하는 cover 사용 및 testcase 구성 방법 등은 &lt;a href=&quot;https://0leaf.github.io/golang/Golang-Testing-Unit-Test-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0/&quot;&gt;Golang Testing - Unit Test 구성하기&lt;/a&gt;를 참고하시면 도움됩니다.&lt;/p&gt;

&lt;h2 id=&quot;32-직접-호출-기반-unittest-구성&quot;&gt;3.2. 직접 호출 기반 UnitTest 구성&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;main.go&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;io&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;net/http&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requestPortal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;cli&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cli&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// golang 1.16 부터 io.ReadAll 사용 가능&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ReadAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;urlList&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://google.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://naver.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://daum.net&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://myportal.my&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urlList&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requestPortal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MethodGet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;main_test.go&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;net/http&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;strings&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;testing&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Test_requestPortal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;expectedResult&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;google&quot;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;metod&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;   &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;    &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;wantErr&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}{&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; TC1. 포털 사이트 요청 테스트&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;metod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MethodGet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;s&quot;&gt;&quot;https://gogole.coom&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expectedResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;wantErr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;got&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requestPortal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;got&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
					&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;requestPortal () = %v, want %v&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;테스트 결과&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coverprofile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cover&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;coverage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;52.9&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;statements&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;    &lt;span class=&quot;m&quot;&gt;0.593&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cover&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cover&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/118353144-fa60af80-b59f-11eb-981a-dd68a8de9870.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;3.3 과정에서는 직접 목적지 서버에 요청을 하는 과정을 unit 테스트로 구성하였고, 그 결과 main 함수 외에 대부분의 statement가 커버됨을 확인할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;34-문제-발생-케이스&quot;&gt;3.4. 문제 발생 케이스&lt;/h2&gt;

&lt;p&gt;만약 google.com이 아니라… 예제에서 들었던 것 처럼 현재 테스트 수행 환경에서는 호출 불가능한 목적지 서버로 호출해야 하는 경우가 있다면 어떨까요.&lt;/p&gt;

&lt;p&gt;그러니까 internal 환경으로 배포하고 나면 코드상에 구현되어 있는 url로 정상 동작하지만 배포 전 내 컴퓨터에서 닿지 않는 곳의 목적지 서버로 요청을 보내야 하는 경우에는 테스트를 어떻게 해야할까요.&lt;/p&gt;

&lt;p&gt;확인을 위해 gogole.coom 이라는 존재하지 않는 페이지로 요청을 보내는 테스트케이스를 구성해 보겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;테스트 결과&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coverprofile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cover&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://gogole.coom&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dial&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tcp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lookup&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gogole&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coom&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;no&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;such&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PASS&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;coverage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;35.3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;statements&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;    &lt;span class=&quot;m&quot;&gt;0.014&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cover&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cover&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/118353150-02b8ea80-b5a0-11eb-83fc-111396b89e27.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;coverage 수치로도 확실히 줄었고, cover 툴을 이용해서 확인해봐도 존재하지 않는 host로의 요청에 의해 응답이후를 처리하는 부분들이 커버되지 않았습니다.&lt;/p&gt;

&lt;p&gt;뿐만 아니라 이 테스트코드를 가진 상태로 Makefile 등을 구성하면 testcase가 Fail이 나기 때문에 배포 환경에 따라 문제가 발생할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;35-mock-client-구성&quot;&gt;3.5. Mock Client 구성&lt;/h2&gt;

&lt;p&gt;이제 Mock client를 구성할 차레입니다. 앞 단계에서 쉬운 예로 들었던 내용처럼&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;“짖다(Do)”&lt;/strong&gt; 의 기능을&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;“main.go”&lt;/strong&gt;에서 하면 &lt;strong&gt;“http.client{} 로 구현된 Do 수행”&lt;/strong&gt; - 강아지&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;“main_test.go”&lt;/strong&gt;에서 하면 “&lt;strong&gt;MockClient{} 로 새롭게 구현된 Do 수행”&lt;/strong&gt; - 고양이&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;하도록 구성할 것 입니다.&lt;/p&gt;

&lt;p&gt;이를 위해 Do를 담을 HTTPClient 라는 이름의 interface를 선언하고, 실제 동작할 함수의 구현은 리시버에 그 handler 타입을 받아 구현합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;main.go&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;io&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;net/http&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// HTTPClient interface&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HTTPClient&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Handler&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;cli&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HTTPClient&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Handler&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;cli&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requestPortal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// 이 부분을 interface로 정의된 HTTPClient type, &amp;amp;http.clinet{} 값을 갖는 값으로 지정한다.&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 이렇게 되면 Do(req *http.Request) (*http.Response, error) 의 기능은 원래 존재하는 http client의 Do 함수를 사용한다.&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 실제 코드를 이렇게 구성하면 의도한대로 동작한다.&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;cli&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cli&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cli&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// golang 1.16 부터 io.ReadAll 사용 가능&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ReadAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;urlList&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://google.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://naver.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://daum.net&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://myportal.my&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urlList&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

		&lt;span class=&quot;c&quot;&gt;//이 부분도 handler를 통해 호출하는 방식으로 변경해준다.&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requestPortal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MethodGet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;main_test.go&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;bytes&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;io&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;net/http&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;testing&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// MockClient is the mock client&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MockClient&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Do 를 재구현 함으로써 MockClient 어댑터로 구현된 기능은 본래의 Do와 다르게 동작한다.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MockClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`{ &quot;description&quot;: &quot;okay&quot; }`&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NopCloser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;     &lt;span class=&quot;s&quot;&gt;&quot;200 Ok&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;StatusCode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StatusOK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;       &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestHandler_requestPortal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewRequestHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// MockClient로 cli를 변경해주면서 MockClient 어댑터로 새로 구현된 Do가 호출된다.&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cli&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MockClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;expectedResult&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`{ &quot;description&quot;: &quot;okay&quot; }`&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;cli&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HTTPClient&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;metod&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;   &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;    &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;wantErr&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}{&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; TC1. 포털 사이트 요청 테스트&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;metod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MethodGet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;s&quot;&gt;&quot;https://gogole.coom&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;expectedResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;wantErr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;got&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requestPortal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wantErr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;requestPortal () error = %v, wantErr %v&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wantErr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;got&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;requestPortal () = %v, want %v&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;테스트 결과&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coverprofile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cover&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PASS&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;coverage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;55.6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;statements&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;    &lt;span class=&quot;m&quot;&gt;0.009&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cover&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cover&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/118353157-0b112580-b5a0-11eb-8fa9-51a7efa4d828.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;호출할 수 없는 url로 구성한 unit 테스트 구성으로도 코드의 syntax 나 panic을 확인해 볼 수 있는 converage 를 확보할 수 있는 것을 알 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;4-정리&quot;&gt;4. 정리&lt;/h1&gt;

&lt;p&gt;테스트의 중요성은 실제로 문제를 겪어보면 절실히 깨닫게 되는 것 같습니다. 소잃고 외양간 고치는 느낌처럼 문제가 발생한 뒤에 해결하려고 한다면 이미 입은 피해는 되돌릴 수 없다는 것도 잘 알게됩니다.&lt;/p&gt;

&lt;p&gt;테스트 구성은 안했지만 자주 호출되는 부분들은 몇번 테스트 해봤는데 잘 동작하니까 그대로 배포해버리고 잊어버리고 살고 있다면, 갑자기 발생한 critical 한 이슈를 개선하려고 기억도 잘 나지 않는 코드에서 헤메게 될 가능성이 있습니다.&lt;/p&gt;

&lt;p&gt;갑자기 발생한 코너케이스나 엣지케이스로 panic이 발생하고, 이를 복구할 수 있는 최소한의 recover나 error handling이 안되어 있다면 복구하는데 드는 리소스 뿐만 아니라 비즈니스에도 큰 영향을 주게 됩니다.&lt;/p&gt;

&lt;p&gt;따라서 Test driven 설계를 하거나, 설계 이후에 Test code를 구성하거나 하는 작업은 무시되어선 안된다고 생각합니다. 사실 Testcase를 구성하는 과정에서 coverage를 함께 보다 보면 놓쳤던 부분들이 하나씩 볼 수 있는 경험을 하게되는 것 같습니다.&lt;/p&gt;

&lt;h1 id=&quot;참고자료&quot;&gt;참고자료&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://www.thegreatcodeadventure.com/mocking-http-requests-in-golang/&quot;&gt;https://www.thegreatcodeadventure.com/mocking-http-requests-in-golang/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://quii.gitbook.io/learn-go-with-tests/go-fundamentals/mocking&quot;&gt;https://quii.gitbook.io/learn-go-with-tests/go-fundamentals/mocking&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://levelup.gitconnected.com/mocking-outbound-http-calls-in-golang-9e5a044c2555&quot;&gt;https://levelup.gitconnected.com/mocking-outbound-http-calls-in-golang-9e5a044c2555&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Sat, 15 May 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/golang/Golang-Testing-2-HTTP-Request-Mocking/</link>
            <guid isPermaLink="true">https://0leaf.github.io/golang/Golang-Testing-2-HTTP-Request-Mocking/</guid>
            
            <category>Golang</category>
            
            <category>Testing</category>
            
            <category>Unit Test</category>
            
        
            <category>Golang</category>
            
        </item>
        
        <item>
            <title>Golang Testing - 1. Unit Test 구성하기</title>
            <description>&lt;p&gt;본 글은 Golang으로 개발함에 있어 Testing 패키지를 활용해 Test를 구성/수행 및 Coverage와 Benchmark를 확인할 수 있는 방법에 대해 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;0-시작하기-전에&quot;&gt;0. 시작하기 전에&lt;/h1&gt;

&lt;p&gt;golang으로 개발을 진행하면서 많은 api 서버를 구성했습니다. 개발 기간의 부족, 테스트에 대한 범위의 모호 등 합리적이지 않은 합리화로 unit 테스트 코드를 작성하는데 소흘했던 것 같습니다.&lt;/p&gt;

&lt;p&gt;혹시나 누군가는 테스트 코드를 작성하고는 싶은데, 어떻게? 어디까지? 등에 대해서 궁금증을 갖고 계신분이 있을 수 있어 테스트와 관련해서 조금씩 덧붙여 작성해보려고 합니다.&lt;/p&gt;

&lt;p&gt;이번 글에서는 TDD 같은 개발 방법론에 대한 이야기를 하지 않고 단순하게 테스트 코드를 만드는 과정에 대해서만 언급하려고 합니다.&lt;/p&gt;

&lt;h2 id=&quot;01-개발-환경-갑자기&quot;&gt;0.1. 개발 환경 (갑자기..?)&lt;/h2&gt;

&lt;p&gt;저는 평소 개발할때 다양한 언어를 사용하거나 인프라 코드들을 편집합니다. python, golang, java, javascript, html, shell, json, yaml… 한동안 JetBrains 사의 Professional 도구들을 사용하곤 했는데, 언어마다 다른 도구로 존재해서 그 마다 전문성이 느껴지고 좋은 기능들이 너무 많지만 단축키나 환경 설정들이 각 툴마다 조금씩 다른 것에 대한 아쉬움을 느꼈습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117565350-a65f5200-b0eb-11eb-8540-ca3ea37e59e5.png&quot; alt=&quot;Untitled&quot; class=&quot;aligncenter&quot; width=&quot;330&quot; height=&quot;350&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그래서 저는 각 도구의 전문성을 포기하고 VS Code로 통합해서 개발해보는 방법으로 Golang 개발을 VS Code로 하고 있습니다. 편리한 플러그인들이 많은데 이 설치한 환경 자체도 github와 연동해 어디서든 동기화 시킬 수 있습니다. (VS Code 얘기는 그만….)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;갑자기 뜬금없이 왜 개발환경을 이야기하냐 물어보신다면&lt;/strong&gt; 테스트 코드를 구성하는 것은 결국 생산성에서 문제를 겪게 된다고 생각합니다. 매번 테스트 코드를 컨벤션에 따라 직접 구성하는것도 좋지만,&lt;/p&gt;

&lt;p&gt;만약 &lt;strong&gt;도구에서 효율적으로 자동으로 만들어주는 부분이 있다&lt;/strong&gt;면 적극 활용하는게 좋을 것 같다고 생각했습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VS Code에 그 기능이 존재&lt;/strong&gt;해서 소개드리고자 합니다. (JetBrains 사의 GoLand도 같은 기능을 갖고 있습니다.)&lt;/p&gt;

&lt;h1 id=&quot;1-테스트-코드-만들기&quot;&gt;1. 테스트 코드 만들기&lt;/h1&gt;

&lt;h2 id=&quot;11-직접-만들기&quot;&gt;1.1. 직접 만들기&lt;/h2&gt;

&lt;p&gt;golang.org의 &lt;a href=&quot;https://golang.org/pkg/testing/&quot;&gt;testing&lt;/a&gt; package 내용은 시간이 허락한다면 꼭 한번 읽어보시기 바랍니다.&lt;/p&gt;

&lt;p&gt;본 글에서 자세하게 언급하지 않는 테스트 코드 구성에 대한 Convention 및 방법들에 대해 잘 설명되어 있습니다.&lt;/p&gt;

&lt;p&gt;Convention 부분만 간단히 말씀드리면 아래와 같습니다. 이 부분들은 단순히 Convention 뿐만 아니라 Test 수행할때 참고하는 부분이 되므로 꼭 기준에 맞춰서 만들어야 합니다.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;m&quot;&gt;1.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이름은&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go로&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;끝난다&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;m&quot;&gt;2.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;내&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Test&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이름은&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestXxx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;로&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;구성한다&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X가&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;대문자를&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;의미&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;간단히 &lt;strong&gt;1~n 까지 합을 구하는 함수&lt;/strong&gt;를 만들고 &lt;strong&gt;테스트 코드를 구성&lt;/strong&gt;해 보겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;sumnumbers.go&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SumNumbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;sumnumbers_test.go&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;testing&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestSumNumbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;got&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SumNumbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;55&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;SumNumbers(10) = %d; want 55&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;테스트 실행 : go test -run ‘’ -v&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RUN&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;TestSumNumbers&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PASS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestSumNumbers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.00&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PASS&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;    &lt;span class=&quot;m&quot;&gt;0.005&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;실행 방법에 대해서는 2.1. Test Execution 부분에서 언급하고 있기도 하고 이 단계는 단순한 결과만을 보여드리기 위함이니 그냥 넘어가셔도 좋습니다.&lt;/p&gt;

&lt;h2 id=&quot;12-idevs-code-기능으로-자동-생성하기&quot;&gt;1.2. IDE(VS Code) 기능으로 자동 생성하기&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117565345-9fd0da80-b0eb-11eb-9df0-58d4c21e11c4.gif&quot; alt=&quot;Golang Testing - Unit Test 구성하기 a039d2176bc5450abb504a9745ec93f9&quot; class=&quot;aligncenter&quot; /&gt;&lt;/p&gt;

&lt;p&gt;글의 앞부분에서 이미 말씀드린 대로 VS Code는 Convention에 맞는 Unit Test 템플릿 코드를 자동으로 생성해주는 기능을 갖고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;테스트 코드를 생성하고 싶은 부분의 함수명에서 마우스를 우클릭&lt;/strong&gt;하고&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go: Generate Unit Tests For Function&lt;/strong&gt; 을 선택해주면 자동으로 Convention에 맞는 파일 및 함수가 생성됩니다.&lt;/p&gt;

&lt;p&gt;이때 자동으로 생성된 Unit 테스트 구성은 &lt;a href=&quot;https://blog.golang.org/subtests&quot;&gt;Table-driven 방식&lt;/a&gt;을 기본 골짜로 하여 생성됩니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;sumnumbers_test.go&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;자동 생성된 결과에 Table driven 형태의 TC를 추가했습니다.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;testing&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestSumNumbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}{&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// TODO: Add test cases.&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TC1_TestSumNumbers: okcase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TC2_TestSumNumbers: okcase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TC3_TestSumNumbers: failcase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SumNumbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;SumNumbers() = %v, want %v&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;테스트 실행 : go test -run ‘’ -v&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RUN&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;TestSumNumbers&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RUN&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;TestSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TC1_TestSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_okcase1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RUN&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;TestSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TC2_TestSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_okcase2&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RUN&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;TestSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TC3_TestSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_failcase1&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;main_test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SumNumbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;want&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;55&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FAIL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestSumNumbers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.00&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PASS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TC1_TestSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_okcase1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.00&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PASS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TC2_TestSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_okcase2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.00&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FAIL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TC3_TestSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_failcase1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.00&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;FAIL&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;FAIL&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;    &lt;span class=&quot;m&quot;&gt;0.005&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이런식으로 하나의 함수 안에서 단위테스트를 여러개를 구성할 수 있습니다. TC3_TestSumNumbers:_failcase1 는 의도적으로 테스트의 실패 케이스를 넣어 두었습니다.&lt;/p&gt;

&lt;h1 id=&quot;2-테스트-수행-방법-및-기능-살펴보기&quot;&gt;2. 테스트 수행 방법 및 기능 살펴보기&lt;/h1&gt;

&lt;h2 id=&quot;21-test-execution&quot;&gt;2.1. Test Execution&lt;/h2&gt;

&lt;p&gt;테스트를 수행하는 다양한 방법 역시 &lt;a href=&quot;https://golang.org/pkg/testing/&quot;&gt;testing&lt;/a&gt; package document에 잘 기술되어 있습니다. 이전 단계에서 skip, subtesting 등에 대해서 언급하지 않았으므로 해당 내용이 궁금하신 분은 testing package 링크 글을 참고하시기 바랍니다.&lt;/p&gt;

&lt;p&gt;테스트를 수행할땐 다음과 같은 명령으로 수행합니다. -run 뒤의 값으로 테스트를 수행할 조건 대상을 선정할 수 있고 -v를 붙여주면 자세한 결과를 확인할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;실행방법&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&apos;&apos;&lt;/span&gt;  &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;      &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matching&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Foo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;such&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;TestFooB -var&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;   &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;For&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matching&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Foo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subtests&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matching&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;A=&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;     &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;For&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subtests&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matching&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;A=1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;기본적으로 특정 패키지의 파일들을 test하고 싶을 경우 해당 위치에서 go test -v 만 해도 쉽게 확인할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;22-code-coverage-testing&quot;&gt;2.2. Code Coverage Testing&lt;/h2&gt;

&lt;p&gt;testing package를 통해 testcase를 구성하고 나면 code coverage또한 체크할 수 있는 이점이 있습니다. &lt;a href=&quot;https://blog.golang.org/cover&quot;&gt;go blog Cover&lt;/a&gt;와 관련된 글을 참고하여 해당 내용을 정리해보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;커버리지 측정 관련된 내용이므로 쉽게 확인하기 위해 예제 코드를 Cover 글에서도 이야기하고 있는 switch 문을 포함하는 예제로 살펴보겠습니다.&lt;/p&gt;

&lt;h3 id=&quot;221-test-coverage-for-go&quot;&gt;2.2.1. Test coverage for Go&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;예제 코드&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;negative&quot;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;zero&quot;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;small&quot;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;big&quot;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;huge&quot;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;enormous&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;예제 테스트 코드&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;일부러 모든 경우를 충족시키지 않기 위해 negative, small 부분만 확인하도록 구성합니다.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;testing&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}{&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;negative check&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;negative&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;small check&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;small&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Errorf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Size() = %v, want %v&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;got&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;want&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;실행 방법&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cover&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;테스트&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;코드&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;경로&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;실행 결과&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RUN&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;TestSize&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RUN&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;TestSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;negative_check&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RUN&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;TestSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;small_check&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PASS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestSize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.00&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PASS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;negative_check&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.00&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PASS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;small_check&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.00&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PASS&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;coverage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;33.3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;statements&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;    &lt;span class=&quot;m&quot;&gt;0.005&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 결과는 statement coaverage 측정 기준으로 33.3%를 충족하는 결과를 보여줍니다. 예상했던 대로 테스트 케이스를 충분하게 작성하지 않았기 대문에 모든 case를 돌지 못한 결과입니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%BD%94%EB%93%9C_%EC%BB%A4%EB%B2%84%EB%A6%AC%EC%A7%80&quot;&gt;coverage&lt;/a&gt;의 경우도 statment coverage 외에 다양한 기준과 방법이 존재하지만 여기서는 statement coverage만 다루도록 하겠습니다.&lt;/p&gt;

&lt;h3 id=&quot;222-viewing-the-results&quot;&gt;2.2.2. Viewing the results&lt;/h3&gt;

&lt;p&gt;golang에서 기본으로 제공하는 강력한 툴중에 cover라는 도구를 사용하면 정확히 어떤 영역들의 코드가 cover 되었는지를 아래와 같은 방법으로 확인할 수 있습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;-coverprofile 옵션으로 커버리지 정보를 추출한 파일을 생성합니다.&lt;/li&gt;
  &lt;li&gt;-func / -html 둘 중 하나의 옵션으로 상세 coverage 정보를 확인합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;coverprofile 생성&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;여기서 statement가 여러번 호출될 경우 진하게 표시하기 위해 -covermode=count를 추가했습니다.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;covermode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coverprofile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coverage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;cover tool의 -func 옵션을 이용한 coverage 측정 결과&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cover&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coverage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;            &lt;span class=&quot;m&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Size&lt;/span&gt;            &lt;span class=&quot;m&quot;&gt;42.9&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;m&quot;&gt;33.3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;cover tool의 -html 옵션을 이용한 coverage 측정 결과&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cover&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coverage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117565349-a4958e80-b0eb-11eb-8169-3a898da86e0b.png&quot; alt=&quot;Untitled 1&quot; class=&quot;aligncenter&quot; width=&quot;430&quot; height=&quot;330&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 결과를 보면 어느 부분의 코드가 테스트되지 않았고, 어떤 식으로 테스트 케이스를 추가해야되는지 직관적으로 알 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;23-benchmark-testing&quot;&gt;2.3. Benchmark Testing&lt;/h2&gt;

&lt;p&gt;기존의 테스트 코드에 아래의 Convention에 따라 필요한 내용을 추가하면 Benchmark Testing을 수행할 수 있습니다. Benchmark는 성능을 평가할때 사용하는데 활용될 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;m&quot;&gt;1.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이름은&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go로&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;끝난다&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;m&quot;&gt;2.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;내&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Benchmark&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이름은&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BenchmarkXxx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;로&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;구성한다&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X가&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;대문자를&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;의미&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;sumnumbers_test.go&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;SumNumbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 코드를 기존의 테스트 케이스에 혹은 새로 구성하여 반영해줍니다.&lt;/p&gt;

&lt;p&gt;b.N 만큼 SumNumbers를 호출하여 성능을 평가한 뒤 결과로 알려주는데, b.N의 값은 본 코드를 쫒아가면 다음 주석이 있습니다. &lt;strong&gt;Run the benchmark for at least the specified amount of time.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;테스트를 수행하는 환경에서 benchmark를 수행하기 위한 적당한 시간 및 횟수를 계산하고 그를 기준으로 benchmark 테스트를 합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;실행 방법&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;테스트&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;코드&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;경로&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;실행 결과&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;          &lt;span class=&quot;m&quot;&gt;361147497&lt;/span&gt;                &lt;span class=&quot;m&quot;&gt;3.295&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;PASS&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;    &lt;span class=&quot;m&quot;&gt;1.534&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;수행 결과로 361147497번의 호출을 했을때 평균 3.295 ns의 시간이 걸리는 것을 확인할 수 있습니다.&lt;/p&gt;

&lt;p&gt;위 내용중에 b.N에 대해 아직 모호하게 생각되는 분들을 위해 아래 두 옵션을 추가로 소개해드립니다.&lt;/p&gt;

&lt;p&gt;benchtime 옵션을 통해 시간 혹은 횟수를 지정하여 테스트할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;명시적 횟수 지정 예 (10회)&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;명시적 시간 지정 예 (10초)&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 옵션으로 몇가지를 테스트 해보겠습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;명시적 횟수에 따른 벤치마크 테스트 (수행 시간을 주목해주세요)&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;                 &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;               &lt;span class=&quot;m&quot;&gt;246.0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;                &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;                &lt;span class=&quot;m&quot;&gt;25.40&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;               &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;                 &lt;span class=&quot;m&quot;&gt;9.610&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;              &lt;span class=&quot;m&quot;&gt;1000&lt;/span&gt;                 &lt;span class=&quot;m&quot;&gt;4.072&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;100000&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;            &lt;span class=&quot;m&quot;&gt;100000&lt;/span&gt;                 &lt;span class=&quot;m&quot;&gt;4.096&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;100000000&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;          &lt;span class=&quot;m&quot;&gt;100000000&lt;/span&gt;                &lt;span class=&quot;m&quot;&gt;3.403&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1000000000&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;          &lt;span class=&quot;m&quot;&gt;1000000000&lt;/span&gt;               &lt;span class=&quot;m&quot;&gt;3.309&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;benchmark 수행 횟수가 적을 수록 평균 시간이 엄청 느린 것을 알 수 있습니다. 1~1000회까지는 속도의 차이가 꽤 심하며, 그 이후로는 큰 차이를 보이지 않는것도 확인할 수 있네요.&lt;/p&gt;

&lt;p&gt;수행 횟수에 따라 시간이 달라지는걸 예상해보면, 컴파일 이후 loader로 부터 메모리에 fetch 되고 실행 되는 과정이 한번 수행할때는 크게 영향을 주고, 많이 수행할땐 그 수로 나눠지면서 미미해지는게 아닌가 싶습니다.&lt;/p&gt;

&lt;p&gt;예를들면 아래와 같습니다.&lt;/p&gt;

&lt;p&gt;1회일 경우: (메모리 올라가는 시간 + 1번 수행 시간) / 1&lt;/p&gt;

&lt;p&gt;100회일 경우: (메모리 올라가는 시간 + 100번 수행 시간) / 100&lt;/p&gt;

&lt;p&gt;위 계산 방식으로 다항식을 실제 결과와 비교해보니 딱 들어맞지는 않습니다. 메모리에 올라가는 시간 말고 다른 영향을 미치는 부분이 있나봅니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;명시적 시간 지정에 따른 벤치마크 테스트 (수행 횟수를 주목해주세요)&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.001&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;            &lt;span class=&quot;m&quot;&gt;290641&lt;/span&gt;                 &lt;span class=&quot;m&quot;&gt;3.964&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;           &lt;span class=&quot;m&quot;&gt;3124398&lt;/span&gt;                 &lt;span class=&quot;m&quot;&gt;3.924&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;          &lt;span class=&quot;m&quot;&gt;30180873&lt;/span&gt;                 &lt;span class=&quot;m&quot;&gt;3.577&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;          &lt;span class=&quot;m&quot;&gt;350010990&lt;/span&gt;                &lt;span class=&quot;m&quot;&gt;3.399&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;          &lt;span class=&quot;m&quot;&gt;706296723&lt;/span&gt;                &lt;span class=&quot;m&quot;&gt;3.319&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;          &lt;span class=&quot;m&quot;&gt;1000000000&lt;/span&gt;               &lt;span class=&quot;m&quot;&gt;3.313&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;BenchmarkSumNumbers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;12&lt;/span&gt;          &lt;span class=&quot;m&quot;&gt;1000000000&lt;/span&gt;               &lt;span class=&quot;m&quot;&gt;3.310&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;n초에 시행할 수 있는 횟수를 계산해서 benchmark를 수행해주는데, 재밌는건 2초까지는 횟수가 늘다가 3초부턴 상한 값이 정해져있는지 혹은 그이상 의미가 없는지 더 늘어나지 않는 모습을 알 수 있습니다.&lt;/p&gt;

&lt;p&gt;정리해보면 benchmark에 별도로 benchtime 옵션을 주지 않으면 컴퓨터 환경에 따라 golang에서 알아서 계산 후 수행합니다. 혹시 benchmark 수행을 매번 돌리실 경우나 정확한 성능평가보단 추세를 보고싶으시다면 적당한 크기 (위 예제에선 1000 회 정도)로 지정해도 괜찮을 것 같네요.&lt;/p&gt;

&lt;h1 id=&quot;3-정리&quot;&gt;3. 정리&lt;/h1&gt;

&lt;p&gt;비교적 간단한 내용이고 이미 공식 블로그나 다른 곳에서도 정리된 글들이 많이 보여서 글로 정리할 필요가 있을까 고민을 조금 했습니다. 하지만 중간 중간 궁금한 내용들을 찾아보고 그 부분만을 기록으로 남기면 누군가가 보았을때 그 흐름을 알지 못할수도 있겠다고 생각했습니다. 그리고 이 글을 계속 덧붙여 업데이트 해나갈 기준을 만들어 두고 싶었던 이유도 있습니다. 테스트와 관련해서는 앞으로도 꾸준히 글과 생각을 정리해서 올려보려고 합니다.&lt;/p&gt;

&lt;h1 id=&quot;참고자료&quot;&gt;참고자료&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://golang.org/pkg/testing/&quot;&gt;https://golang.org/pkg/testing/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://blog.golang.org/cover&quot;&gt;https://blog.golang.org/cover&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Sun, 09 May 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/golang/Golang-Testing-1-Unit-Test-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0/</link>
            <guid isPermaLink="true">https://0leaf.github.io/golang/Golang-Testing-1-Unit-Test-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0/</guid>
            
            <category>Golang</category>
            
            <category>Testing</category>
            
            <category>Unit Test</category>
            
        
            <category>Golang</category>
            
        </item>
        
        <item>
            <title>Postman을 활용한 자동 REST API 테스트</title>
            <description>&lt;p&gt;postman과 newman cli를 활용하여 REST API를 테스트 하는 방법을 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;0-들어가기-전에&quot;&gt;0. 들어가기 전에&lt;/h1&gt;

&lt;p&gt;이번에는 REST API를 테스트하는 방법으로 Postma 툴을 활용하는 방법에 대해서 기술해보도록 하겠습니다. Postman 평소에 자주 사용하던 툴이기도 했는데, API를 시나리오 기반으로 자동으로 테스트하는 셋을 구성하고 싶은 생각에 몇몇 방법을 찾아봤으나, 해당 방법이 제일 간단한 것 같아서 정리합니다.&lt;/p&gt;

&lt;p&gt;Postman에 대한 자세한 내용은 &lt;a href=&quot;https://www.postman.com/&quot;&gt;여기&lt;/a&gt;서 확인하실 수 있고 운영체제에 맞는 툴을 다운로드 받거나 웹 기반으로도 서비스를 제공하고 있습니다.&lt;/p&gt;

&lt;p&gt;Postman 툴은 글 작성 시점 기준으로 무료이며, 원하는 추가 기능을 사용하려면 비용을 지불해야 합니다. 자세한 내용은 공식 홈페이지에서 참고하시기 바랍니다. 본 글은 무료 계정을 사용하였습니다.&lt;/p&gt;

&lt;h1 id=&quot;1-workspace-생성&quot;&gt;1. Workspace 생성&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117138404-f4bbda80-ade5-11eb-8b59-b6e44fa1986b.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 화면 내용처럼 Workspace를 생성합니다. Visibility는 Personal, Team, Private, Public 에서 선택을 합니다.&lt;/p&gt;

&lt;h1 id=&quot;2-api-요청-구성&quot;&gt;2. API 요청 구성&lt;/h1&gt;

&lt;p&gt;요청할 API를 찾으신다면 &lt;a href=&quot;https://developers.naver.com/docs/common/openapiguide/apilist.md#%EB%B9%84%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%B0%A9%EC%8B%9D-%EC%98%A4%ED%94%88-api&quot;&gt;네이버 개발자 센터&lt;/a&gt; 같은 곳에 친절하게 설명되어 있는 api들이 많습니다. 다만 저는 조금 간단히 하기 위해 웹 검색의 url을 그냥 가져와보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;위 링크에 접속해보면 API 요청에 대한 정보를 얻을 수 있고 이 내용을 Postman에서 구성해보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117138423-fa192500-ade5-11eb-942b-578acd16c629.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;강남역 맛집을 네이버에서 검색하면 위와 같이 GET 요청에 대한 URL이 생성됩니다. 이것을 Postman으로 요청해보겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117138446-ff766f80-ade5-11eb-8c14-5231bca79976.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위와 같이 사용하는 법은 너무 간단합니다. URL을 붙여넣으니 쿼리 파라미터에도 자동으로 들어가는군요. 응답으로는 사용자들에게 보여줄 HTML 페이지 전문이 내려옵니다.&lt;/p&gt;

&lt;h1 id=&quot;3-테스트-셋-구성&quot;&gt;3. 테스트 셋 구성&lt;/h1&gt;

&lt;p&gt;그러면 이제 원래 하고싶었던 내용에 대해서 기술해보도록 하겠습니다. 서버를 배포할때 API에 대해서 테스트를 자동으로 해보고 싶을 경우 Postman에서 일부분 관련 기능을 제공해줍니다. 그 기능들에 대해 적어봅니다.&lt;/p&gt;

&lt;h2 id=&quot;31-변수의-활용&quot;&gt;3.1 변수의 활용&lt;/h2&gt;

&lt;p&gt;먼저 테스트에도 활용될 수 있지만 변수에 대해서 이야기 해보려고 합니다. postman에서 변수 기능을 제공하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117138462-056c5080-ade6-11eb-8b97-f27826955254.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 화면처럼 우측 상단에 눈 모양의 버튼을 누르면 변수를 설정할 수 있는데, 이 기능은 나중에 자동화 테스트를 위해 collection을 export 해야하는데, &lt;strong&gt;Environment와 Globals 변수는 export에 포함되지 않습니다. 따라서 아래 화면의 박스쳐진 부분을 선택해서 반드시 Collection 변수로 설정&lt;/strong&gt;해줍니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117138480-0a310480-ade6-11eb-9d30-05f1bc60ab8a.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이런식으로 저장하면 아래와 같이 &lt;strong&gt;** 을 통해 여러 곳에서 재사용 할 수 있습니다. 이 변수는 테스트케이스 구성에서도 사용될 예정입니다. 다만 Environment 변수나 Global 변수가 아닌 **Collection 변수로 지정했는지 다시 한번 확인&lt;/strong&gt;해주시기 바랍니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117138498-0f8e4f00-ade6-11eb-9d74-3e1c4509b007.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;잘 설정된 예 - C : Colllection 변수로 지정되어야 export에 포함됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117138510-14530300-ade6-11eb-92d3-0f896af4a165.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;잘못 설정된 예 - E : Environment나 Gloval 변수로 지정해서 사용하면 해당 작업환경에선 동작하지만 collection을 json으로 export 할때 포함되지 않아 문제가 발생합니다.&lt;/p&gt;

&lt;h2 id=&quot;32-테스트-작성&quot;&gt;3.2 테스트 작성&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117138521-1917b700-ade6-11eb-896f-42f1047bee3f.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;오늘 주로 이야기하고 싶은 기능들은 모두 붉은색 네모 부분들입니다.&lt;/p&gt;

&lt;p&gt;테스트 절차을 수행하기 위한 코드는 javascript로 구성됩니다. Tests를 누르면 나오는 화면에서 오른쪽 네모 박스 부분은 자주 쓰이는 테스트 구성에 대한 예제 인데 클릭하면 자동으로 관련된 javascript가 왼쪽 입력 칸에 들어오게 됩니다.&lt;/p&gt;

&lt;p&gt;Tests 기능을 통해 http response code, body 등의 정보를 바탕으로 해당 요청이 성공적이었는지를 테스트 할 수 있습니다.&lt;/p&gt;

&lt;p&gt;Pre-request Script 기능을 이용해 테스트의 Precondition을 수행할 수 있습니다. 변수를 지정한다던지 어떤 요청을 수행하기 전에 미리 설정을 진행할 수 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;321-pre-request-script-구성&quot;&gt;3.2.1. Pre-request Script 구성&lt;/h3&gt;

&lt;p&gt;오른쪽 SNIPPET 구성에서 &lt;strong&gt;get an environment variable&lt;/strong&gt;, &lt;strong&gt;set an environment variable&lt;/strong&gt; 두 개를 이용해서 간단히 테스트해봅니다.&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestInput1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;TestInput1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;TestInput1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestInput1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;네이버 맛집 검색결과&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위와 같은 코드를 구성하고 request를 반복해서 요청하면 실제 변수에 해당 값이 저장됨을 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117138546-203ec500-ade6-11eb-8759-6e422a7924f2.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;322-tests-구성&quot;&gt;3.2.2. Tests 구성&lt;/h3&gt;

&lt;p&gt;테스트 해볼 내용은 다음과 같습니다. 물론 기능의 동작을 확인하기 위한 내용이라 실제 테스트 설계 방법과 연관해서 생각하시지 않으셨으면 좋겠습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;TestInput1 변수의 내용에 &lt;strong&gt;네이버 맛집 검색결과&lt;/strong&gt; 가 존재하는가&lt;/li&gt;
  &lt;li&gt;response code가 200으로 내려오는가&lt;/li&gt;
  &lt;li&gt;response body내 맛집 내용이 포함되어 있는가&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestInput1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;TestInput1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;TestInput1 contains 네이버 맛집 검색결과&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TestInput1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;네이버 맛집 검색결과&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Status code is 200&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;have&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Body matches string&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;맛집&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117138556-25037900-ade6-11eb-8b61-0e1df58f52c8.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 화면 결과처럼 각 테스트에 대한 결과를 확인할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;33-여러-테스트-동시-수행&quot;&gt;3.3. 여러 테스트 동시 수행&lt;/h2&gt;

&lt;p&gt;왼쪽 화면 → 실행 Collection 마우스 우클릭 → Run collection&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/117138572-2af95a00-ade6-11eb-95d2-605e1b9c9968.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여러 테스트 진행을 확인하기 위해 지금까지 한 과정을 복사했습니다. 총 6개를 Run collection 하면 테스트 수행을 순차적으로 하고 이때 순서와 횟수 등을 변경할 수 있습니다. 그 결과로 레포트까지 얻을 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;4-자동화-api-테스트와-cicd-연동&quot;&gt;4. 자동화 API 테스트와 CI/CD 연동&lt;/h1&gt;

&lt;p&gt;postman에서 collection을 cli로 실행할 수 있는 newman(&lt;a href=&quot;https://www.npmjs.com/package/newman&quot;&gt;npm&lt;/a&gt;/&lt;a href=&quot;https://hub.docker.com/r/postman/newman/&quot;&gt;docker&lt;/a&gt;) 이라는 도구를 제공합니다. 이 도구를 활용한다면 기 작성한 postman collection을 활용하여 배포 과정에 API 테스트를 포함시킬 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;5-정리&quot;&gt;5. 정리&lt;/h1&gt;

&lt;p&gt;API 설계와 명세 그리고 테스트까지… postman 뿐만 아니라 swagger나 다른 툴 및 방법들을 사용해보았는데 각 도구가 저에게 딱 맞지 않고 조금씩 부족한 부분들이 있었던 것 같습니다. 그래서 저는 필요한 경우에 맞게 선택해서 사용하거나 섞어서 활용하고 있습니다.&lt;/p&gt;

&lt;p&gt;하지만 이 글의 목적은 API 테스트 설계 도구로 Postman을 사용해보면 어떨까 에서 출발했고 그 간단한 사용법을 남기는 것이었습니다. SW 테스트와 관련해서 공부하다보면 늘 앞부분에 나오는 말중에 하나는 “&lt;strong&gt;완벽한 테스트는 없다”&lt;/strong&gt; 인 것 같습니다. 그만큼 테스트를 많이 해도 완벽할 수 없다는 말인데, 그를 위해서 최소한 테스트를 쉽게 설계할 수 있는 도구나 방법이 중요하다고 생각합니다. 그런 이유로 Postman은 이런 요구를 충족할 수 있는 대안이 될 수 있을 것 같습니다.&lt;/p&gt;

&lt;h1 id=&quot;참고자료&quot;&gt;참고자료&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=z0MimkXIvE8&quot;&gt;https://www.youtube.com/watch?v=z0MimkXIvE8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://blog.postman.com/newman-run-and-test-your-collections-from-the-command-line/&quot;&gt;https://blog.postman.com/newman-run-and-test-your-collections-from-the-command-line/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://dev.to/leading-edje/hello-newman-how-to-build-a-ci-cd-pipeline-that-executes-api-tests-2h5l&quot;&gt;https://dev.to/leading-edje/hello-newman-how-to-build-a-ci-cd-pipeline-that-executes-api-tests-2h5l&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://community.postman.com/t/how-do-i-set-a-collection-variable/5466&quot;&gt;https://community.postman.com/t/how-do-i-set-a-collection-variable/5466&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Wed, 05 May 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/testing/Postman%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9E%90%EB%8F%99%ED%99%94-REST-API-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0/</link>
            <guid isPermaLink="true">https://0leaf.github.io/testing/Postman%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9E%90%EB%8F%99%ED%99%94-REST-API-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0/</guid>
            
            <category>Testing, Postman, REST</category>
            
        
            <category>Testing</category>
            
        </item>
        
        <item>
            <title>S3 파일 업로더 구성하기 (Cognito → S3)</title>
            <description>&lt;p&gt;Cognito를 활용해 client에서 file server를 거치지 않고 바로 S3로 저장하는 방법에 대해서 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;s3-파일-업로더-구성하기-cognito--s3&quot;&gt;S3 파일 업로더 구성하기 (Cognito → S3)&lt;/h1&gt;

&lt;h1 id=&quot;0-시작하기-전에&quot;&gt;0. 시작하기 전에&lt;/h1&gt;

&lt;p&gt;본 글은 공식 가이드 문서를 참고하여 S3 파일 업로드 브라우저를 구성하는 과정을 기록합니다. 물론 공식 가이드 문서에 내용이 자세히 나와있으나, 잘 이해 안되거나 설명되지 않은 부분들 대해 이 글을 읽는 분들이 해소하실 수 있길 바라며 기록합니다.&lt;/p&gt;

&lt;p&gt;먼저 해당 구성은 파일을 S3에 업로드 해야 하는 업무 요구사항이 있었습니다. 이를 위한 해결책으로 다음과 같은 방법들이 있었습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;FTP 서버 구성 후 cronjob 으로 S3로 전달
    &lt;ul&gt;
      &lt;li&gt;로그인/권한 문제 해결될 수 있으나, 파일 전달 목적의 비효울성이 발생합니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;파일 서버 구성 후 S3로 전달
    &lt;ul&gt;
      &lt;li&gt;S3의 버킷 정책이나 ACL 등을 고려하지 않고 S3에 접근 가능한 IAM 역할을 가진 ec2로 쉽게 전달할 수 있으나, 파일 전달 목적의 비효율이 발생합니다. (서버를 한번 거쳐서 S3로 전달하기 때문)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;front page에서 client 차원으로 직접 S3로 파일 전달
    &lt;ul&gt;
      &lt;li&gt;cognito, 권한 등을 고려해야 하는 문제가 있으나, client에서 직접 S3로 파일을 전달하므로 효율적입니다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;가장 빠르고 쉬운 방법으로 요구사항을 충족시킬 수 있는 구성을 택하려고 했고, 3번의 과정을 진행하면서 겪었던 내용을 기술합니다.&lt;/p&gt;

&lt;h1 id=&quot;1-building-block&quot;&gt;1. Building Block&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116883396-8699db00-ac60-11eb-9c15-79afdcc9e047.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Building Block이 이해가 안가는 부분이 있을 수 있을 것 같아 약간의 설명을 덧붙입니다.&lt;/p&gt;

&lt;p&gt;EC2는 사실 프론트 서버를 띄우기 위해 구성했는데 어떤 방식으로 띄워도 상관 없습니다. (S3 static render, lambda 등)&lt;/p&gt;

&lt;p&gt;User는 응답받은 front페이지에서 Javascript sdk로 Cognito에 S3 버킷에 접근 가능한 권한의 키를 이 프론트 페이지가 들고있는지 확인받습니다. (여기서 Cognito를 활용하는데 &lt;strong&gt;로그인 방식&lt;/strong&gt;과 &lt;strong&gt;비로그인 방식&lt;/strong&gt;이 존재합니다)&lt;/p&gt;

&lt;p&gt;S3는 Public한 공간에서 요청이 들어올텐데 이를 제한하기 위해 액세스 차단과 관련된 설정이 필요합니다. (다운로드를 불가능하게 한다는 등의 조건)&lt;/p&gt;

&lt;h1 id=&quot;2-구성&quot;&gt;2. 구성&lt;/h1&gt;

&lt;h2 id=&quot;21-s3-버킷-생성&quot;&gt;2.1. S3 버킷 생성&lt;/h2&gt;

&lt;p&gt;Amazon S3 → Buckets → Create bucket&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116883419-8d285280-ac60-11eb-88c0-e060034cec56.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116883452-94e7f700-ac60-11eb-9c28-5ff5ac84a161.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;버킷 이름은 임의로 지정하고, 위와 같은 설정을 구성합니다.&lt;/p&gt;

&lt;p&gt;여기서, 위 설정 내용을 조금 짚어봐야 할 것 같습니다. 필요한 내용은 붉은 글씨를 읽어주시기 바랍니다. 이 과정을 모두 거치고 나서 &lt;strong&gt;cognito를 이용한 파일 업로드는 성공했는데 외부에서 public url로 파일을 다운로드 못하도록&lt;/strong&gt; 막고 싶었는데, ACL, bucket 정책 등에서 많이 헤매였던 경험이 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;22-s3-cors-설정&quot;&gt;2.2. S3 CORS 설정&lt;/h2&gt;

&lt;p&gt;Amazon S3 → Buckets → 생성한 Bucket → 권한 탭 → CORS 편집&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116883477-9b766e80-ac60-11eb-8fe8-b0f40fbbe86d.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;AllowedHeaders&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;AllowedMethods&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;HEAD&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;GET&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;PUT&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;DELETE&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;AllowedOrigins&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ExposeHeaders&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ETag&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;x-amz-meta-custom-header&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 내용이 들어갈 수 있도록 CORS 를 설정해줍니다. CORS 관련된 자세한 내용은 &lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/ManageCorsUsing.html#cors-example-1&quot;&gt;여기&lt;/a&gt;를 참고하시면 됩니다.&lt;/p&gt;

&lt;h2 id=&quot;23-cognitio-설정&quot;&gt;2.3. Cognitio 설정&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116883498-a3361300-ac60-11eb-8fe2-cb7c36a7cc92.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Cognito 페이지에 가보면 위 화면처럼 &lt;strong&gt;사용자 풀 관리&lt;/strong&gt;와 &lt;strong&gt;자격 증명 풀 관리&lt;/strong&gt;를 생성할 수 있습니다. 본 글에서는 &lt;strong&gt;자격 증명 풀 관리&lt;/strong&gt;만을 사용하지만, 사용자 풀 관리를 활용해 Cognito 인증 기반 요청을 수행할 수 있습니다. 이 글은 &lt;strong&gt;비인증 기반 요청을 다루기 때문에 자격 증명 풀 관리를 선택&lt;/strong&gt;합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116883522-a92bf400-ac60-11eb-9189-224f289422b5.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;인증되지 않은 자격 증명에 대한 엑세스 활성화를 체크&lt;/strong&gt;합니다.&lt;/p&gt;

&lt;p&gt;이 내용은 Cognito를 통해 로그인 절차를 거친 뒤 얻은 key로 요청하는 방식과 로그인 하지 않고 자격증명 풀 관리 key만 가지고 요청하는 방식에 대해 어떻게 허용할 것인지에 대한 이야기 입니다. 저희는 별도로 로그인 과정을 거치지 않고 front 페이지에서 바로 요청할 것이기 때문에 비인증 자격 증명에 대한 엑세스 요청도 가능하도록 체크해줍니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116883533-ae893e80-ac60-11eb-97a9-f5b1fa6e3375.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116883565-b517b600-ac60-11eb-9670-88b4830e586a.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2012-10-17&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Statement&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;mobileanalytics:PutEvents&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cognito-sync:*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;s3:DeleteObject&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;s3:GetObject&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;s3:ListBucket&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;s3:PutObject&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;s3:PutObjectAcl&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;arn:aws:s3:::BUCKETNAME&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;arn:aws:s3:::BUCKETNAME/*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 화면에서 세부 정보 숨기기(Hide Details)가 감춰져 있는데, 여기서 무시하고 허용 버튼을 누르면 나중에 IAM 에서 해당 역할을 추가해야 합니다. 번거로운 작업을 줄이기 위해 해당 화면의 &lt;strong&gt;Unauth_Role&lt;/strong&gt; 부분의 Policy 부분에 위 내용으로 바꿔준 뒤 허용 버튼을 누릅니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116883594-bea11e00-ac60-11eb-800f-4e9d85fe630b.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;생성하고 나면 위 화면과 같이 샘플 코드에 &lt;strong&gt;IdentityPoolId&lt;/strong&gt;가 보입니다. 이 Id는 나중에 front page의 javascript 에서 사용할 예정이므로 메모해둡니다.&lt;/p&gt;

&lt;h2 id=&quot;24-front-server-구성&quot;&gt;2.4. Front Server 구성&lt;/h2&gt;

&lt;p&gt;front page는 &lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/sdk-for-javascript/v2/developer-guide/s3-example-photo-album-full.html&quot;&gt;공식 가이드 문서에서 제공하는 코드&lt;/a&gt;를 사용합니다. 사진을 업로드 하는 html, js 코드로 구성되어 있습니다.&lt;/p&gt;

&lt;p&gt;저는 위 코드와 더불어 python flask 기반으로 간단하게 서버를 띄우도록 하겠습니다. 아래 코드 중 경로와
&lt;strong&gt;s3_photoExample.js&lt;/strong&gt; 코드의 BUCKET_NAME, REGION, IDENTITY_POOL_ID 정보를 각각 채워줍니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.html&lt;/strong&gt; 코드의 SDK_VERSION_NUMBER 부분도 변경해줘야 하는데 아래 코드는 이미 반영해두었으니 확인만 해주시기 바랍니다.&lt;/p&gt;

&lt;p&gt;./app.py&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;flask&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Flask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render_template&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Flask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render_template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;index.html&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0.0.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;5000&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;./templates/index.html&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- **DO THIS**: --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!--   Replace SDK_VERSION_NUMBER with the current SDK version number --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://sdk.amazonaws.com/js/aws-sdk-sdk-2.283.1.min.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;static/js/s3_photoExample.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getHtml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;listAlbums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;My Photo Albums App&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;app&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;./static/js/s3_photoExample.js&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumBucketName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;BUCKET_NAME&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bucketRegion&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;REGION&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;IdentityPoolId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;IDENTITY_POOL_ID&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bucketRegion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;credentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;CognitoIdentityCredentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;IdentityPoolId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;IdentityPoolId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;S3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;2006-03-01&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumBucketName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;listAlbums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listObjects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Delimiter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;There was an error listing your albums: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albums&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;CommonPrefixes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;commonPrefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;commonPrefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;decodeURIComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getHtml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;span onclick=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;deleteAlbum(&apos;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&apos;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;gt;X&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;span onclick=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;viewAlbum(&apos;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&apos;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getHtml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
            &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;p&amp;gt;Click on an album name to view it.&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;p&amp;gt;Click on the X to delete the album.&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;p&amp;gt;You do not have any albums. Please Create album.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;htmlTemplate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;h2&amp;gt;Albums&amp;lt;/h2&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;getHtml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;button onclick=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;createAlbum(prompt(&apos;Enter Album Name:&apos;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Create New Album&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getHtml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;htmlTemplate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createAlbum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Album names must contain at least one non-space character.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Album names cannot contain slashes.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;headObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Album already exists.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;NotFound&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;There was an error creating your album: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;putObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;There was an error creating your album: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Successfully created album.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;viewAlbum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;viewAlbum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumPhotosKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listObjects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumPhotosKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;There was an error viewing your album: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// &apos;this&apos; references the AWS.Response instance that represents the response&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;httpRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;endpoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bucketUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumBucketName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;photos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;photo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;photoKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;photo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;photoUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bucketUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;photoKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getHtml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;span&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;lt;img style=&quot;width:128px;height:128px;&quot; src=&quot;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;photoUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&quot;/&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;span onclick=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;deletePhoto(&apos;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&apos;,&apos;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;photoKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&apos;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;span&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;photoKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumPhotosKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;photos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;p&amp;gt;Click on the X to delete the photo&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;p&amp;gt;You do not have any photos in this album. Please add photos.&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;htmlTemplate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Album: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;getHtml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;photos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;lt;input id=&quot;photoupload&quot; type=&quot;file&quot; accept=&quot;image/*&quot;&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;lt;button id=&quot;addphoto&quot; onclick=&quot;addPhoto(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&apos;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&apos;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Add Photo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;lt;button onclick=&quot;listAlbums()&quot;&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Back To Albums&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getHtml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;htmlTemplate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;addPhoto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;photoupload&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Please choose a file to upload first.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fileName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumPhotosKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;photoKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumPhotosKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fileName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Use S3 ManagedUpload class as it supports multipart uploads&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;upload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;S3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ManagedUpload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;Bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumBucketName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;photoKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;upload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Successfully uploaded photo.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;viewAlbum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;There was an error uploading your photo: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;deletePhoto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;photoKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;deleteObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;photoKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;There was an error deleting your photo: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Successfully deleted photo.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;viewAlbum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;deleteAlbum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;albumName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listObjects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;albumKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;There was an error deleting your album: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;objects&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;deleteObjects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;Delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Quiet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;There was an error deleting your album: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Successfully deleted album.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;listAlbums&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;3-결과-확인&quot;&gt;3. 결과 확인&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116883615-c52f9580-ac60-11eb-8856-346d0d1f205d.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;구성한 프론트페이지는 위 화면과 같이 뜨는 것을 확인해 볼 수 있습니다. 간단하게 폴더와 파일들을 조회하고 생성하고 삭제하고 업로드 하는 기능을 제공합니다.&lt;/p&gt;

&lt;p&gt;그렇다면 업로드 된 파일을 public url로 다운로드 받아보는건 어떤지 확인해보도록 합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116883636-ca8ce000-ac60-11eb-9260-2f04a30ef1de.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;1.jpeg라는 파일을 test 폴더를 생성하고 업로드 하면 S3 화면에서 Copy URL로 public url을 얻을 수 있습니다.&lt;/p&gt;

&lt;p&gt;이제 이 항목을 다운로드 받아보도록 합니다.
&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116883666-d24c8480-ac60-11eb-8947-7d73477ed6c5.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;브라우저에서 접속한 경우&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;wget&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;//file-uploader.s3.ap-northeast-2.amazonaws.com/test/1.jpeg&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;04&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;37&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;  &lt;span class=&quot;nx&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;//file-uploader.s3.ap-northeast-2.amazonaws.com/test/1.jpeg&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Resolving&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uploader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;northeast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amazonaws&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;com&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uploader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;northeast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amazonaws&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)...&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;52.219&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;56.99&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Connecting&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uploader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;northeast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amazonaws&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;com&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uploader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;northeast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amazonaws&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;52.219&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;56.99&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;connected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;HTTP&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;awaiting&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;403&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Forbidden&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;2021&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;04&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;37&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ERROR&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;403&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Forbidden&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;wget 명령으로 터미널에서 다운로드 시도한 경우&lt;/p&gt;

&lt;p&gt;두 경우 모두 의도한 대로 동작하는 것을 알 수 있습니다.&lt;/p&gt;

&lt;p&gt;이 권한 설정은 &lt;strong&gt;2.1 버킷 생성&lt;/strong&gt; 과정에서 설명된 ACL 권한과 관련이 있으므로 혹시 의도하시는 권한 설정이 있다면 다시 한번 보시기 바랍니다.&lt;/p&gt;

&lt;h1 id=&quot;4-개선-사항&quot;&gt;4. 개선 사항&lt;/h1&gt;

&lt;p&gt;혹시 위 코드를 조금 수정해서 급한대로 파일 업로더로 사용하고 싶으시다면 아래와 같은 부분들을 어렵지 않게 수정할 수 있습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;image 파일 외 다른 파일형식 업로드 가능하도록 변경 (input의 type 변경)&lt;/p&gt;

    &lt;p&gt;&lt;a href=&quot;https://www.w3schools.com/tags/att_input_type_image.asp&quot;&gt;https://www.w3schools.com/tags/att_input_type_image.asp&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;여러 파일을 선택 가능하도록 변경 (input에 multiple 적용)&lt;/p&gt;

    &lt;p&gt;&lt;a href=&quot;https://www.w3schools.com/tags/att_input_multiple.asp&quot;&gt;https://www.w3schools.com/tags/att_input_multiple.asp&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;업로드중인 파일의 업로드 진행 상황 표시하도록 변경 (putObject 및 httpUploadProgress 사용)&lt;/p&gt;

    &lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;putObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fileKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ACL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;public-read&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;uploadStatusDone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;viewFolder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;folderName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;addFiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;folderName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;httpUploadProgress&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;uploadinfo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;fileName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loaded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;% &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;5-생각해볼-점&quot;&gt;5. 생각해볼 점&lt;/h1&gt;

&lt;h2 id=&quot;51-보안-취약점-비인증-액세스-방식-도입&quot;&gt;5.1. 보안 취약점 (비인증 액세스 방식 도입)&lt;/h2&gt;

&lt;p&gt;먼저 위 방법은 굉장히 취약한 방법입니다. 따라서 급하게 사용하는 경우에 최소한 &lt;strong&gt;보안 그룹 등을 이용한 화이트리스트 접근 제어&lt;/strong&gt;나, 간단한 형식의 &lt;strong&gt;페이지 접근 password&lt;/strong&gt;를 걸어두시길 바랍니다. 그 이유는 만약 해당 페이지에 접근 가능하다면 &lt;strong&gt;마우스 우클릭으로 쉽게 javascript의 소스코드를 확인할 수 있고 그 결과 cognito ID 확인&lt;/strong&gt;할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;52-개선-방법-인증-액세스-방식-도입&quot;&gt;5.2. 개선 방법 (인증 액세스 방식 도입)&lt;/h2&gt;

&lt;p&gt;글 초입부에 짧게 언급하였는데 이러한 방법을 &lt;strong&gt;사용자 풀 관리&lt;/strong&gt; 와 함께 &lt;strong&gt;인증 액세스 방식&lt;/strong&gt;을 도입하면 개선할 수 있을 것 같습니다. 본 글에서 다루지는 않지만 나중에 다루더라도 함께 찾아봤던 글들을 여기에 남깁니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.slideshare.net/awskorea/intro-to-amazon-cognito-2016&quot;&gt;https://www.slideshare.net/awskorea/intro-to-amazon-cognito-2016&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://mygumi.tistory.com/362&quot;&gt;https://mygumi.tistory.com/362&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;53-다른-방법&quot;&gt;5.3. 다른 방법&lt;/h2&gt;

&lt;p&gt;간단하게 누군가가 쉬운 방법으로 S3에 파일을 업로드 하는 것이 목적이라면 아래와 같은 방법들이 있습니다.&lt;/p&gt;

&lt;p&gt;1.awslabs 에서 만든 repo (조회만 가능한 버전)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/awslabs/aws-js-s3-explorer&quot;&gt;https://github.com/awslabs/aws-js-s3-explorer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2.awslabs 에서 만든 repo의 alpha branch (업로드 다운로드 가능한 버전)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/awslabs/aws-js-s3-explorer/tree/v2-alpha&quot;&gt;https://github.com/awslabs/aws-js-s3-explorer/tree/v2-alpha&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3.electron 기반 s3 upload app&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.electronjs.org/apps/s3uploader&quot;&gt;https://www.electronjs.org/apps/s3uploader&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;위 내용들은 리서치 과정에서 찾은 대안들 이며 실제로 시도해보지는 않았음을 밝힙니다.&lt;/p&gt;

&lt;h1 id=&quot;6-정리&quot;&gt;6. 정리&lt;/h1&gt;

&lt;p&gt;개발을 하다보면 자연스레 저장소에 업로드해야하는 요청이나 필요한 경우가 자주 발생하곤 합니다. 파일 업로드 기능을 수행하기 위해 세부 요구사항에 맞게 그때 마다 조금씩 설계를 다르게 하곤 하는데 가장 흔하게 사용될 수 있는 cloud저장소의 업로드 방법 중 AWS S3 업로드와 관련된 내용을 한번 정리해보았습니다.&lt;/p&gt;

&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/sdk-for-javascript/v2/developer-guide/s3-browser-examples.html&quot;&gt;https://docs.aws.amazon.com/ko_kr/sdk-for-javascript/v2/developer-guide/s3-browser-examples.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://mygumi.tistory.com/362&quot;&gt;https://mygumi.tistory.com/362&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://slideshare.net/awskorea/intro-to-amazon-cognito-2016&quot;&gt;slideshare.net/awskorea/intro-to-amazon-cognito-2016&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Mon, 03 May 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/aws/S3-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%8D%94-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0/</link>
            <guid isPermaLink="true">https://0leaf.github.io/aws/S3-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%8D%94-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0/</guid>
            
            <category>Cognito</category>
            
            <category>S3</category>
            
        
            <category>AWS</category>
            
        </item>
        
        <item>
            <title>click log system 구성하기 (API Gateway → Kinesis → S3)</title>
            <description>&lt;p&gt;lambda 구성 없이 API Gateway, Kinesis Data Stream, Kinesis Data Firehose, S3로 click log 시스템을 구성하는 과정을 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;0-시작하기-전에&quot;&gt;0. 시작하기 전에&lt;/h1&gt;

&lt;p&gt;사용자가 application에서 특정 action을 했을 때 서버에 남을 api 로그와 별개로 &lt;strong&gt;사용자 행동과 관련된 로그를 별도로 저장하고 싶은 경우, 임의의 body 데이터를 의도한 공간에 저장하기 위한 경우&lt;/strong&gt;의 시스템 구성에 대해 기록합니다.&lt;/p&gt;

&lt;h1 id=&quot;1-building-block&quot;&gt;1. Building block&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773272-826a9380-aa8f-11eb-9201-8c24e6214a1d.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;다른 글들을 보면 kinesis 중간에 lambda가 handing 해주는 부분이 있는데 lambda 과정을 생략하는 방법을 다루고자 합니다.&lt;/p&gt;

&lt;p&gt;본 글에서는 API Gateway를 통해 직접 kinesis data streams로 데이터를 전달하여 kinesis data firehose를 통해 S3로 stream data를 이관하는 방법을 기술하고자 합니다.&lt;/p&gt;

&lt;h1 id=&quot;2-aws-console로-구성하기&quot;&gt;2. aws console로 구성하기&lt;/h1&gt;

&lt;p&gt;aws console은 aws 업데이트 마다 화면 구성이 및 기능들이 달라지겠지만, 직관적으로 작업할 수 있는 장점이 있기에 진행했던 내용을 정리하여 기술합니다.&lt;/p&gt;

&lt;h2 id=&quot;21-iam-role-생성&quot;&gt;2.1. IAM role 생성&lt;/h2&gt;

&lt;h3 id=&quot;211-정책policy-생성&quot;&gt;2.1.1. 정책(Policy) 생성&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Identity and Access Management(IAM) → 정책 → 정책 생성&lt;/strong&gt;
&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773273-88607480-aa8f-11eb-90f3-1680822db4b1.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 화면에서 필요한 액세스 권한만을 부여하는 것이 맞지만 지금 과정은 테스트 과정이므로 모든 권한을 허용하는 것으로 진행해보도록 합니다.&lt;/p&gt;

&lt;p&gt;위와 같이 정책 오류에 대한 메세지는 &lt;strong&gt;리소스에서 특정 혹은 모든 리소스&lt;/strong&gt;에서 문제되는 부분을 해결할 수 있습니다.&lt;/p&gt;

&lt;p&gt;[태그 추가는 건너 뛰도록 합니다.]&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773276-8e565580-aa8f-11eb-9c7b-6c5131c095fb.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;마지막으로 정책에 대한 이름을 지정하고 생성합니다.&lt;/p&gt;

&lt;h3 id=&quot;212-역할role-생성&quot;&gt;2.1.2. 역할(Role) 생성&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Identity and Access Management(IAM) → 역할 → 역할 생성&lt;/strong&gt;
&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773278-93b3a000-aa8f-11eb-8225-8c2ff8fef26c.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;신뢰할 수 있는 유형의 개체를 선택합니다. 사용할 서비스에서 이 역할을 접근할 때 신뢰성을 보장하기 위해 선택합니다. 여기서는 API Gateway에서 역할을 사용할 것이므로 API Gateway를 선택합니다.&lt;/p&gt;

&lt;p&gt;이후에 신뢰할 수 있는 서비스들을 json으로 더 추가할 수 있습니다. &lt;strong&gt;만약 신뢰할 수 있는 서비스에 등록되지 않은 서비스에서 해당 권한으로 요청하게 되면 permission error가 발생&lt;/strong&gt;하게 됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773285-99a98100-aa8f-11eb-94f0-c00ea5ae8cd0.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 화면에서 보이는 정책이 CloudWatchLog 밖에 없을 수 있는데 일단 무시하고 생성한 뒤 이후에 정책을 연결 할 수 있습니다.&lt;/p&gt;

&lt;p&gt;저는 위 화면처럼 &lt;strong&gt;권한 경계를 사용하여 최대 role개의 권한 제어&lt;/strong&gt;를 선택하고 만들어둔 정책을 선택했는데 필수는 아닙니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773292-9f06cb80-aa8f-11eb-8ecf-e1b7dbdd452b.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;마지막으로 역할에 대한 이름을 지정하고 생성합니다. 역할 설명은 원하는 내용으로 수정 변경합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773294-a3cb7f80-aa8f-11eb-8c74-09c4626e49ec.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;역할 생성이 완료되면 &lt;strong&gt;역할 ARN&lt;/strong&gt;을 이후 Gateway API 진행 과정에서 사용하므로 별도로 메모해둡니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773299-a7f79d00-aa8f-11eb-85ea-52882f54a8d5.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;또한 &lt;strong&gt;정책 연결&lt;/strong&gt;을 통해 생성한 정책을 역할과 연결해 줍니다.&lt;/p&gt;

&lt;h2 id=&quot;22-kinesis-data-streams-생성&quot;&gt;2.2. Kinesis data streams 생성&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Amazon Kinesis → 데이터 스트림 → 데이터 스트림 생성&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773303-ac23ba80-aa8f-11eb-8e90-ace03695d932.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;테스트로 생성하는 목적이므로 샤드는 1개로 설정합니다. 샤드의 수가 많을 수록 허용하는 요청수가 늘어나게 됩니다. 이후 필요한 서비스의 목표에 따라 설정하도록 합니다.&lt;/p&gt;

&lt;h2 id=&quot;23-api-gateway&quot;&gt;2.3. API Gateway&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;API Gateway → API → API 생성&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;231-api-gateway-생성&quot;&gt;2.3.1. API Gateway 생성&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773307-b2b23200-aa8f-11eb-9183-77d66574436b.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;REST API&lt;/strong&gt;를 선택하여 구축합니다.&lt;/p&gt;

&lt;p&gt;이 &lt;a href=&quot;https://aws.amazon.com/ko/blogs/compute/announcing-http-apis-for-amazon-api-gateway/&quot;&gt;링크 글&lt;/a&gt;에 따르면, 아래와 같이 HTTP API가 기존의 REST API 보다 더 많은 기능, 더 낮은 지연 시간, 더 낮은 비용 을 위해서 추가된 기능이라고 하는데, 여기서는 kinesis를 구성하기 위해 &lt;strong&gt;REST API&lt;/strong&gt;를 선택합니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;With HTTP APIs, we have reduced request pricing to $1.00/million requests for the first 300 million requests, and $0.90/million for all requests after that. Most customers will see an average cost saving up to 70%, when compared to API Gateway REST APIs. In addition, you will see significant performance improvements in the API Gateway service overhead.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773316-b8a81300-aa8f-11eb-941e-6fce42d11af8.png&quot; alt=&quot;image&quot; /&gt;
위와 같이 이름을 지정하고 생성합니다.&lt;/p&gt;

&lt;p&gt;다음의 공식 가이드 문서에서 말하고 있는 기능들 중에 3번의 &lt;strong&gt;PutRecord&lt;/strong&gt;를 api gateway와 연동하려고 합니다. 다른 기능들이 필요한 경우 본 글을 참고하여 &lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/integrating-api-with-aws-services-kinesis.html&quot;&gt;가이드 문서&lt;/a&gt;를 따라 진행하시길 권장드립니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Kinesis의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListStreams&lt;/code&gt; 작업&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CreateStream&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DescribeStream&lt;/code&gt; 또는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DeleteStream&lt;/code&gt; 작업&lt;/li&gt;
  &lt;li&gt;Kinesis의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetRecords&lt;/code&gt; 또는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PutRecords&lt;/code&gt;(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PutRecord&lt;/code&gt; 포함) 작업&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;위 기능에 대한 가이드문서의 리소스 구성은 다음과 같습니다&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;API의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/streams&lt;/code&gt; 리소스에 HTTP GET 메서드를 노출하고 메서드를 Kinesis의 &lt;a href=&quot;https://docs.aws.amazon.com/kinesis/latest/APIReference/API_ListStreams.html&quot;&gt;ListStreams&lt;/a&gt; 작업과 통합하여 호출자 계정의 스트림을 나열합니다.&lt;/li&gt;
  &lt;li&gt;API의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/streams/{stream-name}&lt;/code&gt; 리소스에 HTTP POST 메서드를 노출하고 메서드를 Kinesis의 &lt;a href=&quot;https://docs.aws.amazon.com/kinesis/latest/APIReference/API_CreateStream.html&quot;&gt;CreateStream&lt;/a&gt; 작업과 통합하여 호출자 계정에서 명명된 스트림을 생성합니다.&lt;/li&gt;
  &lt;li&gt;API의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/streams/{stream-name}&lt;/code&gt; 리소스에 HTTP GET 메서드를 노출하고 메서드를 Kinesis의 &lt;a href=&quot;https://docs.aws.amazon.com/kinesis/latest/APIReference/API_DescribeStream.html&quot;&gt;DescribeStream&lt;/a&gt; 작업과 통합하여 호출자 계정에서 명명된 스트림을 설명합니다.&lt;/li&gt;
  &lt;li&gt;API의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/streams/{stream-name}&lt;/code&gt; 리소스에 HTTP DELETE 메서드를 노출하고 메서드를 Kinesis의 &lt;a href=&quot;https://docs.aws.amazon.com/kinesis/latest/APIReference/API_DeleteStream.html&quot;&gt;DeleteStream&lt;/a&gt; 작업과 통합하여 호출자 계정에서 스트림을 삭제합니다.&lt;/li&gt;
  &lt;li&gt;API의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/streams/{stream-name}/record&lt;/code&gt; 리소스에 HTTP PUT 메서드를 노출하고 메서드를 Kinesis의 &lt;a href=&quot;https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecord.html&quot;&gt;PutRecord&lt;/a&gt; 작업과 통합합니다. 그러면 클라이언트가 단일 데이터 레코드를 명명된 스트림에 추가할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;API의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/streams/{stream-name}/records&lt;/code&gt; 리소스에 HTTP PUT 메서드를 노출하고 메서드를 Kinesis의 &lt;a href=&quot;https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecords.html&quot;&gt;PutRecords&lt;/a&gt; 작업과 통합합니다. 그러면 클라이언트가 데이터 레코드 목록을 명명된 스트림에 추가할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;API의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/streams/{stream-name}/records&lt;/code&gt; 리소스에 HTTP GET 메서드를 노출하고 메서드를 Kinesis의 &lt;a href=&quot;https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetRecords.html&quot;&gt;GetRecords&lt;/a&gt; 작업과 통합합니다. 그러면 클라이언트가 지정된 샤드 반복기를 사용하여 명명된 스트림에 데이터 레코드를 나열할 수 있습니다. 샤드 반복기는 순차적으로 데이터 레코드 읽기를 시작할 샤드 위치를 지정합니다.&lt;/li&gt;
  &lt;li&gt;API의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/streams/{stream-name}/sharditerator&lt;/code&gt; 리소스에 HTTP GET 메서드를 노출하고 메서드를 Kinesis의 &lt;a href=&quot;https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html&quot;&gt;GetShardIterator&lt;/a&gt; 작업과 통합합니다. 이 헬퍼 메서드는 Kinesis의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListStreams&lt;/code&gt; 작업에 제공되어야 합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;위 가이드 문서는 RESTful 한 구성으로 stream을 지정하여 CRUD 할 수 있도록 되어있는데, 여기서는 stream 이름을 지정하여 PutRecords 할 수 있는 기능을 연동 해보겠습니다.&lt;/p&gt;

&lt;h3 id=&quot;232-resource-구성&quot;&gt;2.3.2. Resource 구성&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773324-bd6cc700-aa8f-11eb-91f8-891653e40ba3.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 화면과 같이 리소스를 구성해 줍니다. 스트림을 직접 만든 kinesis로 지정할 것이기 때문에 가이드 문서에 나와 있는 {stream-name} 부분의 리소스 구성은 생략하도록 합니다.&lt;/p&gt;

&lt;h3 id=&quot;233-method-구성&quot;&gt;2.3.3. Method 구성&lt;/h3&gt;

&lt;p&gt;Method를 생성하고 선택하면 아래 화면이 나오는데, 메서드 요청과 통합 요청을 각각 선택하여 다음의 설정들을 진행한다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773325-c2317b00-aa8f-11eb-8e48-8f3c17a7d9dc.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.3.3.1. PUT - 메서드 요청&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773331-c9f11f80-aa8f-11eb-8270-0e41114e0610.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;HTTP 메서드는 POST 입니다. 가이드 문서에 따르면 아래와 같이 언급하고 있습니다.&lt;/p&gt;

&lt;p&gt;리소스에 HTTP PUT 메서드를 노출하고 메서드를 Kinesis의 PutRecord작업과 통합합니다. 그러면 클라이언트가 단일 데이터 레코드를 명명된 스트림에 추가할 수 있습니다.&lt;/p&gt;

&lt;p&gt;API Gateway로 바깥으로 제공하는 method는 RESTful의 의미상 PUT으로, 내부적인 kinesis 동작을 위한 요청 method는 &lt;a href=&quot;https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecord.html&quot;&gt;PutRecord 문서&lt;/a&gt;를 보면 POST로 전달하는 것을 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.3.3.2. PUT - 통합 요청&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773333-ceb5d380-aa8f-11eb-8232-17f25efeb0d4.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;매핑 템플릿 항목을 선택하고, &lt;strong&gt;Content-Type에 application/json을 추가한 뒤 템플릿 내용에 아래 정보를 저장&lt;/strong&gt; 합니다.&lt;/p&gt;

&lt;p&gt;어떤 stream에 요청할지에 대한 정보를 담고 있으며 &lt;strong&gt;KinesisDataStreamName&lt;/strong&gt; 에는 생성한 stream의 이름을 지정해줍니다.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;StreamName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;KinesisDataStreamName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$util.base64Encode($input.body)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;PartitionKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$context.requestId&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;해당 정보에 대한 자세한 내용은 &lt;a href=&quot;https://docs.aws.amazon.com/kinesis/latest/APIReference/API_PutRecord.html&quot;&gt;링크 글&lt;/a&gt;을 참고하시기 바랍니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.3.3. PUT - 테스트&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773337-d83f3b80-aa8f-11eb-9074-83f8c0429b83.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;요청 본문에 아래와 같이 입력했는데, 오른쪽 로그를 살펴보면 통합 요청에서 추가했던 매핑 템플릿이 포함되어 전달된 것을 볼 수 있고, 응답 기대 결과로 ShardId가 내려온 것으로 보아 성공적으로 POS 요청이 동작하였음을 알 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;요청 본문&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Test&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;실제 요청 본문 로그&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;StreamName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;api-gateway-kinesis-test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ewogICAgIkRhdGEiOiAiVGVzdCIKfQ==&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;PartitionKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;e000e702-1ed8-433b-8c8f-8e294684460c&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;24-kinesis-data-streams-데이터-확인&quot;&gt;2.4. Kinesis data streams 데이터 확인&lt;/h2&gt;

&lt;p&gt;kinesis의 데이터를 가져오기 위해서 &lt;a href=&quot;https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetRecords.html&quot;&gt;GetRecords 문서&lt;/a&gt; 를 보면 &lt;strong&gt;POST 요청에 다음과 같은 요청을 body에 포함&lt;/strong&gt;해야 합니다.&lt;/p&gt;

&lt;p&gt;ShardIterator가 required field 이며 원하는 kinesis stream의 ShardIterator를 알아야 해당 스트림에서 데이터를 꺼내올 수 있다는 의미입니다.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Limit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ShardIterator&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이를 위해 가이드 문서에서는 api gateway에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/streams/{stream-name}/sharditerator&lt;/code&gt; 이 리소스의 구현을 통해 연동하는 것을 가이드 하고 있습니다.&lt;/p&gt;

&lt;p&gt;본 글에서는 해당 내용을 연동하지 않고, aws cli를 통해 간단히 stream의 데이터를 확인할 수 있는 방법을 진행하고자 합니다.&lt;/p&gt;

&lt;h3 id=&quot;241-sharditerator-요청&quot;&gt;2.4.1. ShardIterator 요청&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;kinesis&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;get-shard-iterator&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--stream-name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;api-gateway-kinesis-test&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--shard-id&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;shardId&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-000000000000&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--shard-iterator-type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;AT_TIMESTAMP&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--timestamp&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1609489201&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;stream-name : kinesis stream 이름&lt;/p&gt;

&lt;p&gt;shard-id : PutRecord 결과로 받은 응답 shardId&lt;/p&gt;

&lt;p&gt;teimstamp : unix epoch time으로 해당 시간 이후로 요청된 내용을 가져오기 위함&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ShardIterator&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;AAAAAAAAAAETNsov/ad8I319/hcr67iF+GXRfWPGKddiRLLryOUdajcITPhRItI09YJd9ENy4PLyjP0WRxr0ljrFDdRqO6b3FY1tDtt86VMjQEEDSma+LAqSBgz7buORcglJRn8MgDXLLnWJsTlG0uDauZnDi4tfCCnrLDr3FrYO1vOA4j+eAi4fiPDYzuWNH/3BtbocoFn3PrrG/2Nwf3S+oSeu6wpbGrGyrpqWHtD42l2MRGDCyH3d6vq5eQCk2forH0oEh0Rk2B/Uw5P3cIJ4K1UDzEYO&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;242-getrecords&quot;&gt;2.4.2. GetRecords&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;kinesis&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;get-records&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;--shard-iterator&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;AAAAAAAAAAETNsov/ad&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;319&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/hcr&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;67&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;iF+GXRfWPGKddiRLLryOUdajcITPhRItI&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;09&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;YJd&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ENy&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;PLyjP&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;WRxr&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ljrFDdRqO&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;FY&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;tDtt&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;86&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;VMjQEEDSma+LAqSBgz&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;buORcglJRn&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;MgDXLLnWJsTlG&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;uDauZnDi&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;tfCCnrLDr&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;FrYO&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;vOA&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;j+eAi&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;fiPDYzuWNH/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;BtbocoFn&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;PrrG/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Nwf&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;S+oSeu&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;wpbGrGyrpqWHtD&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;MRGDCyH&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;vq&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;eQCk&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;forH&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;oEh&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Rk&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;B/Uw&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;cIJ&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;UDzEYO&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Records&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;SequenceNumber&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;49617687179155666429430101670197006370059396208769630210&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ApproximateArrivalTimestamp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1619426371.64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;e30=&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;PartitionKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;04294d1f-491d-4ea9-8e28-8923e48d9d2b&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;SequenceNumber&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;49617687179155666429430101670198215295879010975383289858&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ApproximateArrivalTimestamp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1619426373.735&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;e30=&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;PartitionKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;8130f87d-fc2b-410f-8a22-9a288b8fc11d&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;SequenceNumber&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;49617687179155666429430101670199424221698625673277472770&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ApproximateArrivalTimestamp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1619426374.598&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;e30=&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;PartitionKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;70d2ec6e-e74f-43f3-94ea-b5b97b779277&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;SequenceNumber&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;49617687179155666429430101670200633147518240302452178946&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ApproximateArrivalTimestamp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1619426374.803&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;e30=&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;PartitionKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;888809c6-98a7-4c2a-9170-c4988bd13339&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;SequenceNumber&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;49617687179155666429430101670201842073337854931626885122&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ApproximateArrivalTimestamp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1619426374.97&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;e30=&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;PartitionKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;22601971-e0a1-4749-8b34-18178ae33427&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;NextShardIterator&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;AAAAAAAAAAH7+NNTZsDi9Sh5qwpc1/mO0f86w56xSq8vkSjHWSxgBzSqZdiTtg89qFTaHfA89m2dwGmGutxeO+2kA7naO0XDlHYE80UywWV6TPmlQBJ54jo6D5ke1hKeZoYQq78jWdf6BdXS8CF4UM3BgmoNyxwKIMZg/aMxNO5H5a9gpaFEZHnIlDwz3ygbdTXFyCjhXcAL+mlmyoF8VmUMZp/Tk85jymj/htqwzrxOYlk2zc27bN5EE48CL0TP45FfUg0nX9Q=&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;MillisBehindLatest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 결과는 해당 스트림에 저장된 데이터의 정보를 출력한 것을 나타냅니다.&lt;/p&gt;

&lt;h2 id=&quot;25-s3-버킷-생성&quot;&gt;2.5. S3 버킷 생성&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Amazon S3 → 버킷 만들기&lt;/strong&gt;
&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773338-decdb300-aa8f-11eb-8918-c6197e389dd2.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;화면과 같이 원하는 이름의 bucket을 생성합니다. 다른 bucket 설정은 변경하지 않아도 됩니다.&lt;/p&gt;

&lt;h2 id=&quot;26-kinesis-data-filehose-생성&quot;&gt;2.6. Kinesis data filehose 생성&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Amazon kinesis → Data Firehose → Create delivery stream&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;261-source-stream-지정&quot;&gt;2.6.1. Source stream 지정&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773344-e4c39400-aa8f-11eb-88d2-a816d91256b8.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Kinesis Data Stream을 선택하고, 기존에 생성한 stream을 지정하면 lambda 없이 firehose에서 S3로 stream data를 옮길 수 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;262-process-records-옵션&quot;&gt;2.6.2. Process records 옵션&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773350-ee4cfc00-aa8f-11eb-894c-8f1c723eaffd.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;lambda function을 통해 transform이나 convert 동작을 수행할 수 있는 옵션을 제공하는데, 지금은 사용하지 않고 넘기기로 합니다.&lt;/p&gt;

&lt;h3 id=&quot;263-destination-지정&quot;&gt;2.6.3. Destination 지정&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773356-f60ca080-aa8f-11eb-857f-451681f8c084.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;s3로 저장하는 것이 목표이므로 이전 단계에서 만들었던 S3 bucket을 지정하여 설정합니다.&lt;/p&gt;

&lt;h3 id=&quot;264-configure-설정&quot;&gt;2.6.4. configure 설정&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773365-fc028180-aa8f-11eb-9570-c0192318e6d0.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;buffer size와 buffer interval 둘 중 하나의 옵션으로 s3로 저장하는 동작이 trigger 됩니다.&lt;/p&gt;

&lt;p&gt;위 내용대로라면 5MB 혹은 300sec 넘어갈 경우 s3로 stream 데이터가 이동하게 됩니다.&lt;/p&gt;

&lt;h2 id=&quot;27-s3-저장-결과-확인&quot;&gt;2.7. S3 저장 결과 확인&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116773372-002e9f00-aa90-11eb-9a76-1e80ce3e022b.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 화면과 같이 최종 결과로 stream data가 s3에 저장된 것을 볼 수 있습니다. 1MB, 60sec 값으로 kinesis firehose의 설정을 반영한 결과 입니다.&lt;/p&gt;

&lt;h2 id=&quot;3-정리&quot;&gt;3. 정리&lt;/h2&gt;

&lt;p&gt;처음엔 AWS 공식 가이드 문서를 쫒아서 진행하는데 의도한대로 잘 동작하지 않았습니다.&lt;/p&gt;

&lt;p&gt;같은 문제를 겪는 분들이 있을 것 같아 리서치를 했고 부분마다 안되는 곳들을 찾아서 순서대로 진행해 보았습니다.&lt;/p&gt;

&lt;p&gt;처음엔 시간이 지나면 이 글대로도 동작하지 않을 것 같아서 console, cli, serverless 혹은 cdk로 구성하는 방법을 모두 기록으로 남길까 고민했습니다.&lt;/p&gt;

&lt;p&gt;하지만 이후 시스템 기능의 변화가 있더라도 큰 흐름은 바뀌지 않을 것 같고 console로 구성하면서 그 과정을 이해한다면 cli나 cdk 등의 구성에서도 큰 어려움을 느끼지 않을 것이라고 생각하여 이쯤에서 마무리 지으려고 합니다.&lt;/p&gt;

&lt;h1 id=&quot;참고자료&quot;&gt;참고자료&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/integrating-api-with-aws-services-kinesis.html&quot;&gt;https://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/integrating-api-with-aws-services-kinesis.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://haandol.github.io/2020/07/28/apigateway-kinesis-logging.html&quot;&gt;https://haandol.github.io/2020/07/28/apigateway-kinesis-logging.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chang12.github.io/api-gateway-kinesis-proxy/&quot;&gt;https://chang12.github.io/api-gateway-kinesis-proxy/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://joobly.tistory.com/22&quot;&gt;https://joobly.tistory.com/22&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Sat, 01 May 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/aws/click-log-system/</link>
            <guid isPermaLink="true">https://0leaf.github.io/aws/click-log-system/</guid>
            
            <category>API Gateway</category>
            
            <category>Kinesis</category>
            
            <category>S3</category>
            
        
            <category>AWS</category>
            
        </item>
        
        <item>
            <title>AWS API Gateway 고정 IP 만들기 (NLB → VPC endpoint → API Gateway)</title>
            <description>&lt;p&gt;NLB, VPC endpoint, API Gateway를 활용하여 AWS API Gateway의 IP를 고정 IP로 만드는 과정을 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;0-시작하기-전에&quot;&gt;0. 시작하기 전에&lt;/h1&gt;

&lt;p&gt;API Gateway의 IP가 고정이든 유동이든 큰 신경쓸 필요가 없는 경우가 대부분이긴 합니다.
하지만 회사 보안 정책이나 특정 시스템의 방화벽 허용을 위한 예외 처리를 화이트 리스트로 관리해야 한다면, IP는 아무래도 고정으로 지정되어 있어야 관리하기 편합니다.&lt;/p&gt;

&lt;p&gt;현재 글 작성 시점 기준으로 AWS에서 해당 기능을 편리한 방법으로 제공하지 않고 있으며 여러가지 쉽고 어려운 방법들이 존재하는데, 그 중 구조상 제일 괜찮은 것으로 생각되는 아래 구성에 대한 기록을 남깁니다.&lt;/p&gt;

&lt;p&gt;Route 53/Domain → NLB → VPC Endpoint → API Gateway(Private)&lt;/p&gt;

&lt;h1 id=&quot;1-문제의-인식&quot;&gt;1. 문제의 인식&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772474-526cc180-aa8a-11eb-8956-9402d5665828.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://google.com으로&quot;&gt;https://google.com&lt;/a&gt; 으로 GET 요청을 날리는 간단한 API 를 하나 정의하고 배포해보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;그 결과 &lt;a href=&quot;https://344i1vresf.execute-api.ap-northeast-2.amazonaws.com/test&quot;&gt;https://344i1vresf.execute-api.ap-northeast-2.amazonaws.com/test&lt;/a&gt; API주소를 얻었습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;위 주소는 글 작성 이후 삭제될 예정이므로 호출하셔도 올바른 응답을 얻을 수 없습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;문제의 현상을 보기 위함이니 참고용으로 보시면 될 것 같습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;요청&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;curl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;-X&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;344&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;vresf.execute-api.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.amazonaws.com/test&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;응답&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;meta&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;http-equiv=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;content-type&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text/html;charset=utf-8&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;TITLE&amp;gt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;301&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Moved&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;H&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;301&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Moved&amp;lt;/H&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;The&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;moved&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;A&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;HREF=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://www.google.com/&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;here&amp;lt;/A&amp;gt;.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;응답 결과가 301로 떨어지는걸로 봐서 API Gateway는 잘 연동되었다는 것을 알 수 있습니다.&lt;/p&gt;

&lt;p&gt;이제 테스트 환경은 끝났고,&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://344i1vresf.execute-api.ap-northeast-2.amazonaws.com&quot;&gt;https://344i1vresf.execute-api.ap-northeast-2.amazonaws.com&lt;/a&gt; 주소의 실제 IP를 확인해보겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;nslookup&lt;/strong&gt; 혹은 &lt;strong&gt;dig&lt;/strong&gt;을 이용하여 확인합니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$dig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;344i1vresf.execute-api.ap-northeast-2.amazonaws.com]&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;http://344i1vresf.execute-api.ap-northeast-2.amazonaws.com/&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$nslookup&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;344i1vresf.execute-api.ap-northeast-2.amazonaws.com]&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;http://344i1vresf.execute-api.ap-northeast-2.amazonaws.com/&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;회차&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;요청&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;nslookup&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;344&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;vresf.execute-api.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.amazonaws.com&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Server:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;		&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;192.168&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;10.1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;192.168&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;10.1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;53&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Non-authoritative&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;answer:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Name:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;344&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;vresf.execute-api.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.amazonaws.com&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;3.35&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;86.48&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Name:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;344&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;vresf.execute-api.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.amazonaws.com&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;52.78&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;233.230&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;---------------&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;회차&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;요청&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;nslookup&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;344&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;vresf.execute-api.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.amazonaws.com&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Server:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;		&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;192.168&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;10.1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;192.168&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;10.1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;53&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Non-authoritative&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;answer:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Name:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;344&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;vresf.execute-api.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.amazonaws.com&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;3.34&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;120.247&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Name:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;344&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;vresf.execute-api.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.amazonaws.com&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;52.78&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;33.158&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;---------------&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;회차&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;요청&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;nslookup&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;344&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;vresf.execute-api.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.amazonaws.com&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Server:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;		&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;192.168&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;10.1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;192.168&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;10.1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;53&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Non-authoritative&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;answer:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Name:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;344&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;vresf.execute-api.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.amazonaws.com&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;3.36&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;158.122&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Name:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;344&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;vresf.execute-api.ap-northeast&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;-2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.amazonaws.com&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Address:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;3.36&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;30.67&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 결과의 &lt;strong&gt;Non-authoritative answer 부분&lt;/strong&gt;을 보시면 응답 서버의 IP가 계속 바뀌어 내려오는 것을 확인할 수 있습니다. 따라서 AWS API Gateway는 고정 IP로 사용자들에게 API 서비스를 제공하지 않는다는 것을 확인할 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;2-building-block&quot;&gt;2. Building Block&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772480-5993cf80-aa8a-11eb-9041-5b3cd98b4926.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;NLB와 API Gateway의 위치가 위 그림과 정확히 일치하지 않지만 전체적인 동작의 이해를 돕기 위해 Subnet 구성을 통합하고 그 안에 블록을 포함시켰습니다.&lt;/p&gt;

&lt;p&gt;실제 시스템을 구성하게 될 순서는 &lt;strong&gt;API Gateway → VPC Endpoint → NLB → DNS 연결&lt;/strong&gt; 순으로 위 그림 기준 &lt;strong&gt;오른쪽에서 왼쪽&lt;/strong&gt;으로 구성합니다.&lt;/p&gt;

&lt;h1 id=&quot;3-구성&quot;&gt;3. 구성&lt;/h1&gt;

&lt;p&gt;VPC 구성은 아래와 같이 이미 완료되어있는 것을 가정하며 본 글에서 VPC 구성 방법은 다루지 않으나, 이후 다른 글에서 다루어 보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772484-5ef11a00-aa8a-11eb-8838-71a5705ab29d.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;31-api-gateway-생성&quot;&gt;3.1. API Gateway 생성&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;API Gateway → API → API 생성&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772486-644e6480-aa8a-11eb-8977-1951b7749ae2.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 화면에서 네번째 항목인 &lt;strong&gt;REST API 프라이빗&lt;/strong&gt; 을 선택해 API 를 생성합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772488-69131880-aa8a-11eb-91aa-bc41029b3a55.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;엔드포인트 유형의 설명을 보면 REST API 프라이빗 으로 만든 API 는 &lt;strong&gt;API Gateway용 VPC 엔드포인트를 통해서만 엑세스 할 수 있다&lt;/strong&gt;는 것을 주의깊게 보셔야 합니다. 외부에서 직접 호출이 불가능하며 VPC 엔드포인트와 연동이 필요합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772492-6fa19000-aa8a-11eb-992a-2c56ee985d5d.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;문제의 인식 부분에서 사용했던 테스트용 Get Method를 위 내용과 같이 정의한 뒤에 배포합니다.&lt;/p&gt;

&lt;p&gt;api gateway 생성 시 지정했던 vpceID를 에 넣어 해당 정책을 ResourcePolicy에서 반드시 추가시켜줘야 합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python3&quot;&gt;{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: [
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Principal&quot;: &quot;*&quot;,
            &quot;Action&quot;: &quot;execute-api:Invoke&quot;,
            &quot;Resource&quot;: [
                &quot;execute-api:/*&quot;
            ]
        },
        {
            &quot;Effect&quot;: &quot;Deny&quot;,
            &quot;Principal&quot;: &quot;*&quot;,
            &quot;Action&quot;: &quot;execute-api:Invoke&quot;,
            &quot;Resource&quot;: [
                &quot;execute-api:/*&quot;
            ],
            &quot;Condition&quot; : {
                &quot;StringNotEquals&quot;: {
                    &quot;aws:SourceVpce&quot;: &quot;&quot;
                }
            }
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;32-vpc-endpoint-생성&quot;&gt;3.2. VPC Endpoint 생성&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772498-77f9cb00-aa8a-11eb-8bf4-1cee49a96cfb.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;서비스 이름은 execute-api가 포함된 것을 선택합니다.&lt;/p&gt;

&lt;p&gt;원하는 VPC를 선택한 뒤 서브넷을 선택할때 API Gateway를 통해 private 영역에 있는 API를 호출하려고 하면 private 영역을 선택해야 합니다. 여기서는 private 영역을 선택해줍니다.&lt;/p&gt;

&lt;p&gt;보안 그룹은 필요한 경우 원하는 보안 그룹을 지정합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772501-7d571580-aa8a-11eb-9ffc-ab82e12454ba.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;VPC Endpoint를 생성하고 나면 위 화면과 같이 private zone에 해당하는 ip가 임의로 할당된 것을 볼 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;33-network-load-balancer-생성-및-elastic-ip-연결&quot;&gt;3.3. Network Load Balancer 생성 및 Elastic IP 연결&lt;/h2&gt;

&lt;h3 id=&quot;331-elastic-ip-생성&quot;&gt;3.3.1. Elastic IP 생성&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;네트워크 및 보안 → 탄력적 IP → 탄력적 IP 주소 할당&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;NLB 생성 과정에서 탄력적 IP 주소를 사용할 수 있도록 지정하는 화면이 있기 때문에, 미리 만들어둡니다. 해당 과정에서는 a zone, c zone에서 사용할 두개의 static ip를 생성합니다.&lt;/p&gt;

&lt;h3 id=&quot;332-network-load-balancer-생성&quot;&gt;3.3.2. Network Load Balancer 생성&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;EC2 → 로드 밸런싱 → 로드밸런서 → Load Balancer 생성&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772504-821bc980-aa8a-11eb-99fa-c056a675dbd9.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Network Load Balancer를 선택하여 생성합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.3.2.1. 기본 설정&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772510-8647e700-aa8a-11eb-8a27-2319e53942be.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.3.2.2. Network mapping&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772516-8e078b80-aa8a-11eb-9c03-a192c9778eb5.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.3.2.3. Listeners and routing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772518-92cc3f80-aa8a-11eb-8f7e-d19ba5fe76b2.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 화면에서 &lt;strong&gt;Create target group&lt;/strong&gt; 을 선택하여 대상 그룹을 생성하고 VPC Endpoint로 routing 할 IP 들을 지정해주어야 합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.3.2.4. Traget group&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772526-a5df0f80-aa8a-11eb-9ebf-dfb0a16a5998.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 화면은 대상 그룹의 생성 화면인데 특별한 내용 없이 저정하고 다음으로 넘어갑니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772529-ac6d8700-aa8a-11eb-8f1a-2e98b0da82c0.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 화면과 같이 IP 부분에 &lt;strong&gt;VPC Endpoint 때 자동으로 생성되었던 IP&lt;/strong&gt;들 (a zone, c zone 모두)을 등록해줍니다.&lt;/p&gt;

&lt;p&gt;이후 NLB 생성을 완료해줍니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772531-b1cad180-aa8a-11eb-8b57-972c73061bae.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이후 대상 그룹에서 health check가 healthy(green)으로 불이 들어오면
NLB → StaticIP → 대상그룹 → VPC End Point 까지 연결이 잘 되었다고 생각할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;34-동작-확인&quot;&gt;3.4. 동작 확인&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Host : {api gateway 주소}&quot;&lt;/span&gt; https://&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;nlb 주소&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;api gateway stage&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;사용자 지정 도메인 이름을 연동하기 전에 NLB 주소로 API Gateway를 호출해보고자 한다면 위의 방식으로 테스트 해볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;여기서 드는 의문점은 VPC Endpoint와 API Gateway를 연결한 적이 없이 없는데 어떻게 호출할 수 있지 라는 생각이 들 수 있습니다.&lt;/p&gt;

&lt;p&gt;직접 연결하지 않아도 API Gateway를 호출할 수 있는데 NLB를 통해 호출해야 하는 과정을 위해 Header의 Host 필드에 요청할 API Gateway 주소를 지정해야 합니다.&lt;/p&gt;

&lt;p&gt;이 다음 단계에서 도메인과 API Gateway를 연결하게 되면 도메인을 통해 헤더 없이 직접 호출할 수 있게 됩니다.&lt;/p&gt;

&lt;h2 id=&quot;35-사용자-지정-도메인-이름&quot;&gt;3.5. 사용자 지정 도메인 이름&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/116772538-b7281c00-aa8a-11eb-8b25-d6fde419ac0e.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 화면은 API Gateway 화면에서 왼쪽에 &lt;strong&gt;위치한 사용자 지정 도메인 이름&lt;/strong&gt; 을 선택했을때 나오는 화면이며,&lt;/p&gt;

&lt;p&gt;도메인과 관련된 내용을 추가하여 생성하고 생성된 항목을 선택하면 API Gateway의 배포된 Phase와 연동할 수 있습니다.&lt;/p&gt;

&lt;p&gt;해당 도메인 주소에 NLB 주소의 CNAME을 Route53에도 추가해줍니다.&lt;/p&gt;

&lt;p&gt;이 과정을 끝내면 생성한 도메인으로 일반적인 방식으로 API 요청을 할 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;4-정리&quot;&gt;4. 정리&lt;/h1&gt;

&lt;p&gt;위 과정을 진행하고 나면 NLB에 지정한 도메인을 dig 혹은 nslookup을 통해 요청해보면 nlb 생성 시 지정한 Elastic IP로 일관된 IP로부터의 응답을 내려주는 것을 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;이후 AWS에서 API Gateway의 IP를 고정으로 내려주는 기능이 추가될 지 모르겠으나 현재로서는 해당 구조가 제일 문제가 발생하지 않을 구조라 판단하여 조사한 자료들을 바탕으로 구성한 기록을 남깁니다.&lt;/p&gt;

&lt;h1 id=&quot;참고자료&quot;&gt;참고자료&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://zenliu.medium.com/how-to-assign-elastic-ip-to-amazon-api-gateway-ddbee9146bec&quot;&gt;https://zenliu.medium.com/how-to-assign-elastic-ip-to-amazon-api-gateway-ddbee9146bec&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://medium.com/opseco-technologies/assign-fixed-ip-to-aws-api-gateway-fb72507a2883&quot;&gt;https://medium.com/opseco-technologies/assign-fixed-ip-to-aws-api-gateway-fb72507a2883&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Sat, 01 May 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/aws/AWS-API-Gateway-static-ip/</link>
            <guid isPermaLink="true">https://0leaf.github.io/aws/AWS-API-Gateway-static-ip/</guid>
            
            <category>API Gateway</category>
            
            <category>NLB</category>
            
            <category>VPC endpoint</category>
            
            <category>static IP</category>
            
        
            <category>AWS</category>
            
        </item>
        
        <item>
            <title>Go 동시성 패턴 - Pipelines and cancellation (fan in/fan out)</title>
            <description>&lt;p&gt;Golang 동시성 패턴 중 channel을 활용한 fan in/ fan out에 대한 내용을 설명합니다.&lt;/p&gt;

&lt;h1 id=&quot;go-동시성-특성&quot;&gt;Go 동시성 특성&lt;/h1&gt;

&lt;p&gt;I / O 및 다중 CPU를 효율적으로 사용하는 스트리밍 데이터 파이프 라인을 쉽게 구성 할 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;파이프라인&quot;&gt;파이프라인&lt;/h1&gt;

&lt;p&gt;golang에서 공식적인 개념의 파이프라인은 정해진 것이 없고, 일반적으로 채널로 연결된 일련의 단계를 파이프라인 이라고 일컫습니다.&lt;/p&gt;

&lt;p&gt;또한 각 단계는 &lt;strong&gt;동일한 기능을 수행&lt;/strong&gt;하는 고루틴 그룹입니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;인바운드&lt;/em&gt; 채널을 통해 &lt;em&gt;업스트림&lt;/em&gt;에서 값 수신 (소스 또는 생산자) - 1단계&lt;/li&gt;
  &lt;li&gt;해당 데이터에 대해 일부 기능을 수행하여 일반적으로 새로운 값을 생성합니다. - 2단계&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;아웃 바운드&lt;/em&gt; 채널을 통해 값을 &lt;em&gt;다운 스트림으로&lt;/em&gt; 전송 (싱크 또는 소비자) - 3단계&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;위 내용을 이해한 바를 그림으로 표현하면 아래와 같습니다.&lt;/p&gt;

&lt;p&gt;upstream 과 downstream을 이해하기 쉽게 step을 이어서 그리지 않고 나누어 표현했습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/79149004/115551535-33ca3600-a2e6-11eb-8f56-3a7b68816a9f.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;실제 사례에 활용하는 방법을 위해, kakao, naver, google로 특정 검색을 요청하고 결과를 취합하는 예제를 구성하며 살펴보도록 하겠습니다.&lt;/p&gt;

&lt;h1 id=&quot;step-1--producer&quot;&gt;step 1 : producer&lt;/h1&gt;

&lt;p&gt;producer는 입력 데이터에 대한 channel 들을 생성합니다.&lt;/p&gt;

&lt;p&gt;생성한 채널을 이용해 이후 fan out 단계에서 함수들이 해당 채널로부터 값을 가져갑니다.&lt;/p&gt;

&lt;p&gt;이 예제에서는 카카오, 구글, 다음 웹사이트의 주소를 파라미터로 받아 각각에 대한 채널을 생성합니다.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;produceChan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// 값을 보낼 목적의 channel을 생성한다.&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;outChan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// 생성한 channel로 요청이 필요한 url 들을 보낸다.&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// &amp;lt;-done에 의해 갑자기 종료되는 경우에 chan을 close 한다.&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outChan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outChan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outChan&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;step2-1--fan-out&quot;&gt;step2-1 : fan out&lt;/h1&gt;

&lt;p&gt;fan out은 채널이 닫히기 전까지 채널 안에 있는 값들을 여러 함수들이 꺼내올 수 있는 것을 말합니다.&lt;/p&gt;

&lt;p&gt;하나의 채널 안에 있는 값들을 꺼내서 여러 함수에서 동시적 처리가 가능합니다.&lt;/p&gt;

&lt;p&gt;이 예제에서는 카카오, 구글, 다음 웹사이트로 동시에 http get 요청을 합니다.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fanOut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outChan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// 값을 받을 목적의 channel을 생성한다.&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;inChan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// 동시에 수행해야 하는 operation을 처리한다. 여기서는 http request get 요청을 수행한다.&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// &amp;lt;-done에 의해 갑자기 종료되는 경우에 chan을 close 한다.&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inChan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outChan&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

			&lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

			&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ioutil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ReadAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

			&lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inChan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inChan&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;step2-2--fan-in&quot;&gt;step2-2 : fan in&lt;/h1&gt;

&lt;p&gt;fan in은 단일 채널에 fan out때 요청했던 결과들을 입력으로 받아 하나로 모을 수 있습니다.&lt;/p&gt;

&lt;p&gt;여기서 fan out의 결과인 입력 채널들이 모두 닫힐때까지 (작업이 완료 될 때 까지) 기다려주는데, sync.WaitGroup을 이용해서 모든 입력 채널들의 작업이 완료되는 것을 기다립니다.&lt;/p&gt;

&lt;p&gt;그 결과로 fan in의 outbound chan은 카카오, 구글, 다음의 response body 결과를 들고있게 됩니다.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fanIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outChan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// 동기화를 위해 waitgroup를 사용한다.&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wg&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WaitGroup&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// 결과를 합칠 채널을 생성한다.&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;merged&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;wg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outChan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;outChanMerge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;oc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// &amp;lt;-done에 의해 갑자기 종료되는 경우에 wait group을 종료한다.&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

		&lt;span class=&quot;c&quot;&gt;// outChan으로부터의 결과를 merge 하는 채널로 전달한다.&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;merged&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
				&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outChan&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outChanMerge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// 모든 요청에 대한 응답을 동기화하여 합치기 위해 기다린다.&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;wg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Wait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;merged&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;step-3--consume&quot;&gt;step 3 : consume&lt;/h1&gt;

&lt;p&gt;consume 단계는 fan out/ fan in 과정을 통해 취합된 결과들이 outbound channel에 담겨있는데, 이를 꺼내 활용하는 과정입니다.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumeChan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outChan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outChan&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;step-4-main-호출&quot;&gt;step 4: main 호출&lt;/h1&gt;

&lt;p&gt;실제로 앞의 과정들을 호출하는 코드는 아래와 같습니다.&lt;/p&gt;

&lt;p&gt;done 의 언급에 대해서 본글에 설명이 안되어있는데, 간략히 말씀드리자면, chan 을 통해 데이터를 주고받는 경우 많은 주의를 기울여야 합니다.&lt;/p&gt;

&lt;p&gt;의도하지 않게 inbound channel에서 데이터를 무한정 기다리게 될 수도 있고, 닫힌 channel에 값을 넣어버리면 panic이 나는 경우 등이 있기 때문입니다.&lt;/p&gt;

&lt;p&gt;이중에 무한정 기다리게되는 hang을 피하기 위해 done 이라는 채널을 두어 명시적 취소 절차를 진행할 수 있습니다.&lt;/p&gt;

&lt;p&gt;자세한 내용은 원글 블로그에 자세히 나와있으므로 참고해보시면 좋을 것 같습니다.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;inChan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;produceChan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://naver.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://google.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://www.daum.net&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;f1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fanOut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inChan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;f2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fanOut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inChan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;f3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fanOut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inChan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;outChan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fanIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumeChan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outChan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;참고자료&quot;&gt;참고자료&lt;/h1&gt;

&lt;p&gt;https://blog.golang.org/pipelines&lt;/p&gt;
</description>
            <pubDate>Thu, 15 Apr 2021 00:00:00 +0000</pubDate>
            <link>https://0leaf.github.io/golang/Go-Concurrency-Patterns-Pipelines-and-cancellation/</link>
            <guid isPermaLink="true">https://0leaf.github.io/golang/Go-Concurrency-Patterns-Pipelines-and-cancellation/</guid>
            
            <category>동시성 패턴</category>
            
        
            <category>Golang</category>
            
        </item>
        
    </channel>
</rss>
