C# MongoDB Driver 2.0+를 사용하다 발생한 "Element 'key' does not match any field or property of class" 오류를 처리하는 방법에 대해 알아봅니다.

 

 

 

1. 현상.

 

FindOneAndUpdate 작업에 IsUpsert 옵션을 true로 설정해 둔 채 작업을 수행하다 에러가 발생했습니다.

 

신규 Insert시에는 문제가 없었으나 Update시에 발생한 문제였으며 예외 메시지는 다음과 같았습니다.

 

Element '{FIELD}' does not match any field or property of class {PROJECT}.MongoDB.Documents.{CLASS}.

 

 

 

2. 수정.

 

클래스 선언 위에 "[BsonIgnoreExtraElements]"를 추가해 줍니다.

 

이후 FindOneAndUpdate 작업을 다시 수행하면 정상적으로 수행 됩니다.

 

 

 

References: Element 'Id' does not match any field or property of class

 

Element 'Id' does not match any field or property of class

I got the result from the collection in MongoDB, the structure is the same as below [DataContract] public class Father { [BsonId] [DataMember] public MongoDB.Bson.ObjectId _id { get; s...

stackoverflow.com

 

반응형

 

Notion API Developer - Beta 한글 번역

 

 

 

0. 앞선 글

 

페이지는 사용자가 빠른 메모부터 공유문서, 랜딩페이지에 이르기까지 모든 것을 작성하는 곳입니다. 통합을 사용해 사용자는 콘텐츠를 조직하여 Notion을 단일 소스로 변경하거나 Notion내에서 콘텐츠를 수집, 연결, 시각화할 수 있습니다.

 

이 가이드에서는 페이지 콘텐츠의 구성요소가 API에 표시되는 방식과 이를 사용하여 수행할 수 있는 작업에 대해 알아보도록 하겠습니다. 이 가이드를 통해 사용자는 콘텐츠가 포함된 새 페이지를 만들고 다른 페이지의 콘텐츠를 읽어와 기존 페이지 블록에 추가할 수 있습니다.

 

 

 

1. 페이지 콘텐츠와 속성.

 

일반적으로 페이지 속성은 기한, 범주, 다른 페이지와의 관계 같은 구조화된 정보를 저장하는데 적합합니다. 페이지 콘텐츠는 좀 더 느슨한 구조나 자유 형식 콘텐츠를 저장하는데 적합합니다. 페이지 콘텐츠는 사용자의 생각을 작성하거나 이야기하는 곳입니다. 페이지 속성은 사용자가 데이터를 저장하고 시스템을 구축하는 곳입니다. 여러분의 통합은 여러분이 기대하는 대로 속성과 콘텐츠를 사용하는 것을 목표로 해야 합니다.

 

https://developers.notion.com/docs/working-with-page-content

 

 

2. 콘텐츠를 블록으로 모델링하기.

 

페이지 콘텐츠는 블록 객체 목록으로 표시됩니다. 이러한 블록을 페이지의 자식이라고도 합니다. 각 블록에는 단락, 제목, 이미지와 같은 타입이 있습니다. 토글 목록과 같은 일부 타입의 블록에는 자체 자식이 존재할 수 있습니다.

 

간단한 예제로 단락 블록을 확인해 보겠습니다.

 

{
  "object": "block",
  "id": "380c78c0-e0f5-4565-bdbd-c4ccb079050d",
  "type": "paragraph",
  "created_time": "",
  "last_edited_time": "",
  "has_children": false,

  "paragraph": {
    "text": [/* details omitted */]
  }
}

 

모든 단락 블록에는 object, type, created_time, last_edited_time, has_children의 공통된 속성을 포함합니다. 또한 단락 속성 내에 type-specific 정보가 포함되어 있습니다. 단락 블록에는 "text" 속성이 존재하며 블록 타입에 따라 type-specific 속성이 달라질 수 있습니다.

 

이제 블록에 자식 블록이 있는 예시를 살펴보도록 하겠습니다. "paragraph"에 들여 쓰기 된 "to_do" 블록을 확인해 보세요.

 

{
  "object": "block",
  "id": "380c78c0-e0f5-4565-bdbd-c4ccb079050d",
  "type": "paragraph",
  "created_time": "",
  "last_edited_time": "",
  "has_children": true,

  "paragraph": {
    "text": [/* details omitted */],
    "children": [
      {
        "object": "block",
        "id": "6d5b2463-a1c1-4e22-9b3b-49b3fe7ad384",
        "type": "to_do",
        "created_time": "",
        "last_edited_time": "",
        "has_children": false,
  
        "to_do": {
          "text": [/* details omitted */],
          "checked": false
        }
      }
    ]
  }
}

 

자식 블록은 type-specific 속성 내에 블록 목록으로 표시됩니다. 만약 블록에 자식이 있다면 "has_children" 속성은 true가 됩니다. 단락 블록과 같은 일부 블록 타입만 자식을 지원합니다.

 

* 지원하지 않는 블록 타입(Notion Version 2021-05-13 기준)

Notion API는 현자 텍스트와 유사한 블록만을 지원하며 곧 더 많은 블록을 지원할 예정입니다. 지원되지 않는 블록 타입은 페이지에 "unsupported" 타입으로 표시됩니다.

 

 

 

3. 서식이 있는 텍스트(Rich Text)

 

앞선 블록 예시에서 "text" 속성의 생략된 값은 서식이 있는 텍스트(Rich Text) 객체의 목록이었습니다. 서식이 있는 텍스트 객체는 단순한 문자열 이상을 표현할 수 있습니다. 이 객체에는 스타일 정보, 링크, 멘션 등이 포함될 수 있습니다.

 

"Grocery List"라는 단어만 포함된 간단한 예시를 살펴보도록 하겠습니다.

 

{
  "type": "text",
  "text": {
    "content": "Grocery List",
    "link": null
  },
  "annotations": {
    "bold": false,
    "italic": false,
    "strikethrough": false,
    "underline": false,
    "code": false,
    "color": "default"
  },
  "plain_text": "Grocery List",
  "href": null
}

 

서식이 있는 텍스트 객체는 type-specific 한 구성과 유사한 패턴을 따릅니다. 위의 서식이 있는 텍스트 객체에는 "text" 타입이 있으며 "text" 속성에 해당 타입과 관련된 추가 구성이 존재합니다. annotations, plain_text, href와 같은 타입에 의존하지 않는 기타 정보들은 서식이 있는 텍스트 객체의 최상위 수준에 위치하게 됩니다.

 

서식이 있는 텍스트는 페이지 콘텐츠와 내부 페이지 속성 값 모두에 사용될 수 있습니다.

 

 

 

4. 콘텐츠가 있는 페이지 만들기.

 

페이지 생성 엔드포인트를 사용하면 자식 블록을 통해 페이지를 만들 수 있습니다. 이 엔드포인트는 다름 페이지 내에서 페이지를 만들거나 데이터베이스 내에서 페이지 만들기를 지원합니다.

 

샘플 콘텐츠가 있는 다른 페이지 내에 페이지를 새로 만들어 보도록 하겠습니다. 이 엔트포인트에 대해 세 가지 파라미터를 사용하게 됩니다. "parnet" 파라미터는 부포 페이지가 됩니다. 기존의 페이지 ID를 사용할 수 있습니다.

 

{
  "type": "page_id",
  "page_id": "494c87d0-72c4-4cf6-960f-55f8427f7692"
}

 

"properites" 파라미터는 페이지 속성을 표현하는 객체입니다. 우선 이 예시에서는 "title" 속성만이 있는 간단한 페이지 속성을 구성하도록 하겠습니다.

 

{
  "Name": {
    "type": "title",
    "title": [{ "type": "text", "text": { "content": "A note from your pals at Notion" } }]
  }
}

 

"children" 파라미터는 페이지 콘텐츠를 표현하는 블록 객체 목록입니다. 몇 가지 샘플 콘텐츠를 사용하도록 하겠습니다.

 

[
  {
    "object": "block",
    "type": "paragraph",
    "paragraph": {
      "rich_text": [{ "type": "text", "text": { "content": "You made this page using the Notion API. Pretty cool, huh? We hope you enjoy building with us." } }]
    }
  }
]

 

이 세 가지 파라미터를 모두 사용해 엔드포인트에 요청을 전송하여 페이지를 생성해 보도록 하겠습니다.

 

curl -X POST https://api.notion.com/v1/pages \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2021-05-13" \
  --data '{
    "parent": { "database_id": "494c87d0-72c4-4cf6-960f-55f8427f7692" },
    "properties": {
        "title": {
      "title": [{ "type": "text", "text": { "content": "A note from your pals at Notion" } }]
        }
    },
    "children": [
    {
      "object": "block",
      "type": "paragraph",
      "paragraph": {
        "text": [{ "type": "text", "text": { "content": "You made this page using the Notion API. Pretty cool, huh? We hope you enjoy building with us." } }]
      }
    }
  ]
}'

* 토큰과 ID 정보는 적절히 수정되어야 합니다.

* API 요청에는 크기 제한이 존재합니다. 자세한 내용은 Size Limit를 확인해 주세요.

 

페이지가 추가되면 새 페이지 객체가 포함된 응답을 받게 됩니다. Notion을 살펴보고 새 페이지를 확인해 보세요.

 

 

 

5. 페이지에서 블록 읽어오기.

 

페이지 콘텐츠는 자식 블록 검색 엔드포인트를 이용해 읽어올 수 있습니다. 이 엔드포인트는 모든 자식 목록을 반환합니다. 페이지는 블록 자식을 읽어오기 위한 일반적인 시작 방법이지만 다른 종류의 블록에 대한 자식들도 검색할 수 있습니다.

 

"block_id" 파라미터는 블록의 ID를 의미합니다. 예시에 따른다면 응답에 페이지 ID가 포함되어 있을 것입니다. 해당 페이지의 ID를 "block_id"로 사용해 페이지에서 샘플 콘텐츠를 읽어오도록 하겠습니다.

 

이제 "block_id"를 사용해 엔드포인트에 요청을 보내고 하위의 블록을 검색합니다.

 

curl https://api.notion.com/v1/blocks/16d8004e-5f6a-42a6-9811-51c22ddada12/children?page_size=100 \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Notion-Version: 2021-05-13"

* block_id 및 토큰 정보는 적절히 수정되어야 합니다.

 

블록 객체 목록이 포함된 응답을 받게 됩니다.

 

{
  "object": "list",
  "results": [
    {
      "object": "block",
      /* details omitted */
    }
  ],
  "has_more": false,
  "next_cursor": null
}

 

페이징 된 응답을 받을 수 있습니다. 페이징 된 응답은 Notion API 전반에서 사용됩니다. 페이징 된 응답의 최대 결과 개수는 100개입니다. "start_cursor"과 "page_size" 파라미터를 통해 100개가 넘는 결과를 얻어올 수도 있습니다.

 

이 응답에서 요청한 자식 블록은 "results" 배열 내부에 존재하게 됩니다.

 

 

 

6. 중첩된 블록 읽어오기.

 

결과 자체에 자식이 포함된 블록이 있는 경우 어떤 일이 일어날까요? 이 경우 응답에 중첩된 블록이 포함되지는 않지만 "has_children"의 값은 true가 됩니다. 통합에 페이지 콘텐츠 혹은 모든 블록의 완전한 표현이 필요하다면 "has_children"이 true인 블록에 대해 결과를 검색하고 엔드포인트를 재귀적으로 호출해야 합니다.

 

큰 페이지를 읽는데 다소 시간이 걸릴 수 있습니다. 아키텍처에서 작업 대기열과 같은 비동기 작업을 사용하는 것이 좋습니다. 또한 요청 제한에 도달할 수 있으므로 새 요청을 전송하는 속도를 적절히 늦춰야 할 수도 있습니다.

 

 

 

7. 페이지에 블록 추가하기.

 

통합은 블록 자식 추가 엔드포인트를 사용해 더 많은 콘텐츠를 추가할 수도 있습니다. 예시에서 만든 페이지에 다른 블록을 추가해 보도록 하겠습니다. 이 엔드포인트에는 "block_id"와 "children"의 두 개의 파라미터가 필요합니다

 

"block_id"는 기존 블록의 ID입니다. 블록 ID에 앞선 예시에서 사용한 페이지 ID를 동일하게 사용하도록 합니다.

 

"children" 파라미터는 추가할 내용을 설명할 블록 객체 목록입니다. 더 만든 샘플 콘텐츠를 사용해 보도록 하겠습니다.

 

[
  {
    "object": "block",
    "type": "paragraph",
    "paragraph": {
      "text": [{ "type": "text", "text": { "content": "– Notion API Team", "link": { "type": "url", "url": "https://twitter.com/NotionAPI" } } }]
    }
  }
]

 

두 파라미터를 이용해 엔드포인트에 요청을 전송하여 블록을 추가합니다.

 

curl -X PATCH https://api.notion.com/v1/blocks/16d8004e-5f6a-42a6-9811-51c22ddada12/children \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2021-05-13" \
  --data '{
    "children": [
    {
      "object": "block",
      "type": "paragraph",
      "paragraph": {
        "text": [{ "type": "text", "text": { "content": "– Notion API Team", "link": { "type": "url", "url": "https://twitter.com/NotionAPI" } } }]
      }
    }
  ]
}'

* 블록 ID와 토큰을 적절히 수정하는 것을 잊지 마세요.

 

업데이트된 블록이 포함된 응답을 받게 됩니다. 응답에 하위 블록이 포함되어 있지는 않지만 "has_children"의 값이 true로 설정된 것을 확인할 수 있습니다.

 

 

 

8. 맺는 글.

 

사용자가 Notion에서 보는 것의 거의 모든 것이 블록으로 표시됩니다. 이제 통합으로 블록이 있는 페이즈를 만들었고 블록을 읽어올 수 있으며 페이지에 블록을 추가하는 방법을 이해했습니다. 이제 Notion에서 노출된 대부분의 영역을 다를 수 있게 되었습니다. 

 

 

 

* 현재 블록을 삭제하거나 업데이트하는 것은 불가능합니다.

(NotionVersion 2021-05-13) 이러한 작업은 파괴적이므로 API를 통해 이 작업을 노출하는 가장 좋은 방법을 신중히 조사하고 있습니다. 향후 기능에 대한 업데이트를 위해 계속 지켜봐 주시기 바랍니다.

 

 

* 이 글은 Notion API Develpers - Beta: Working with page content를 번역한 글입니다.

 

Working with page content

Overview Pages are where users write everything from quick notes, to shared documents, to curated landing pages in Notion. Integrations can help users turn Notion into the single source of truth by syndicating content or help users gather, connect, and vis

developers.notion.com

 

 

 

반응형

 

Notion API Developer - Beta 한글 번역 

 

 

 

0. 앞선 글.

 

Notion에서 드디어 API 서비스를 시작했습니다. 오래 기다린 기능인만큼 바로 사용해보고 싶은데 아직 한글 가이드가 없어 공식 가이드를 읽으며 참고할만한 내용을 포스팅합니다.

 

 

 

1. 시작하기.

 

Notion API를 사용해 처음으로 API 요청을 만드는 방법에 대해 알아보겠습니다.

 

Notion API를 처음 사용한다면 잘 찾아오셨습니다. 이 가이드에서는 다음과 같은 방법을 알아봅니다.

* Notion 워크스페이스에서 통합(Integration)을 생성합니다.

* Notion에서 새 데이터베이스를 만들고 통합 권한을 부여해 액세스 합니다.

* 코드를 사용해 데이터베이스에 페이지를 추가합니다.

 

 

 

2. 시작하기 전에.

 

시작하기 전에 필요한 몇 가지 사항이 있습니다.

* 관리자 유저로 Notion 워크스페이스에 로그인합니다.

* CURL 커맨드가 설치된 터미널 프로그램.

 

 

 

3. 신규 통합 만들기.

 

브라우저를 새로 열어 Notion 통합 페이지를 엽니다. "새 통합" 버튼을 사용해 신규 통합을 생성합니다. 통합 이름을 지정하세요. 이 예시에서는 "Vacation Planner"로 정했습니다. 제출을 완료해 통합을 생성합니다.

 

https://developers.notion.com/docs/getting-started

 

시크릿 아래에서 내부용 통합 토큰을 찾을 수 있습니다. 이 토큰을 표시하도록 하고 복사해두세요. 텍스트 에디터와 같은 나중에 쉽게 찾을 수 있는 곳에 붙여 넣어 둡시다.

 

 

 

4. 통합을 사용해 데이터베이스 공유.

 

API로 구축된 통합은 사용자에 공유 권한과 유사한 권한 시스템을 따릅니다. 여기에는 중요한 차이점이 있습니다. 통합은 처음엔 워크스페이스의 페이지나 데이터베이스에 액세스 할 수 없습니다. API를 통해 해당 페이지에 액세스 하려면 사용자가 특정 페이지를 통합에 공유해야 합니다. 이런 방식으로 Notion에서 사용자와 팀의 정보를 안전하게 보호할 수 있습니다.

 

워크스페이스의 새 페이지 또는 기존 페이지에서 시작해봅시다. /표 혹은 /table을 입력하여 새 데이터베이스를 추가합니다. 제목을 정해줍니다. 이 예시에서는 "Weekend getaway destinations"라고 정했습니다. 이제 공유 버튼을 클릭해 실렉터에서 통합을 찾아 선택한 뒤 초대를 클릭합니다.

 

https://developers.notion.com/docs/getting-started

 

이제 통합에 새 데이터베이스를 읽고 쓰고 편집할 수 있는 권한이 부여되었습니다. 통합이 워크스페이스에 추가되면 모든 구성원과 통합이 같이 페이지 및 데이터베이스를 공유할 수 있습니다. 이 단계에서는 관리자 권한이 요구되지 않습니다.

 

계속하기 전에 방금 만든 데이터베이스의 ID를 알아보도록 합시다.

Notion 데스크톱 앱을 사용하는 경우 공유 버튼을 다시 한번 클릭해 링크 복사를 선택합니다. 브라우저에 이 URL을 붙여 넣고 확인하세요. 이 URL에서 데이터베이스 ID는 워크스페이스 이름 슬래시(/) 뒤부터 물음표(?) 앞까지입니다. 데이터베이스 ID는 문자와 숫자를 포함하는 32자입니다. 이 ID를 복사해 나중에 쉽게 찾을 수 있는 곳에 저장해 두세요.

 

https://www.notion.so/myworkspace/a8aec43384f447ed84390e8e42c2e089?v=...
                                                                    |-------------------- Database ID ------------------|

 

 

 

5. 데이터베이스에 아이템 추가하기.

 

Notion 데이터베이스에서 각각의 아이템은 자식 페이지입니다. 부모를 데이터베이스로 설정함으로써 새 페이지를 생성해 데이터베이스에 아이템을 추가할 수 있습니다. 새 아이템을 추가하기 위해 페이지 생성 엔드포인트에 HTTP 요청을 보내봅시다.

 

터미널 프로그램을 열고 다음 커맨드를 입력하세요. Authorization와 database_id의 값은 앞서 생성한 적절한 값으로 변경되어야 합니다. 줄 끝에 보이는 문자(\) 뒤에 공백이 없어야 함을 주의하세요.

 

curl -X POST https://api.notion.com/v1/pages \
  -H "Authorization: Bearer MY_NOTION_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2021-05-13" \
  --data '{
    "parent": { "database_id": "DATABASE_ID" },
    "properties": {
      "Name": {
        "title": [
          {
            "text": {
              "content": "Yurts in Big Sur, California"
            }
          }
        ]
      }
    }
  }'

 

커맨드를 실행하고 Notion으로 이동해 새 항목이 데이터베이스에 추가되었는지 확인하세요.

 

이제 Notion API를 사용해 데이터베이스에 새 항목을 추가했습니다. 커맨드와 함께 보낸 HTTP 요청에 대해 좀 더 자세히 살펴보겠습니다.

* Notion API는 REST API 규칙을 따릅니다.

* 토큰은 Authorization 헤더에 포함되며 요청의 출처를 식별합니다.

* Notion API의 각 엔드포인트는 파라미터를 사용해 호출할 수 있습니다. 엔드포인트의 참고 페이지에는 이러한 파라미터에 대해 설명되어 있습니다. 이 예시에서 parent와 properties는 모두 본문에 명시되어 있습니다. 데이터베이스 작업 가이드에는 다른 엔드포인트를 사용하는 방법에 대해 설명되어 있습니다,

 

 

 

6. 마무리

 

방금 배운 내용을 사용하면 다른 서비스와 시스템을 연결해 새로운 정보를 Notion에 보내거나 업데이트 해 여러분의 팀이 정보를 확인하고 조치를 취할 수 있도록 합니다.

 

이 가이드에서는 CURL 명령어를 통해 Notion API에 HTTP 요청을 보내는 방법을 사용하였습니다. 일반적으로 통합은 프로그래밍 언어를 사용하여 코드로 작성될 것입니다. 거의 모든 프로그래밍 언어를 사용할 수 있지만 통합을 사용한 코드를 실행하는데 가장 쉽고 빠른 방법을 찾고 있다면 이 예제를 사용해 보세요. 숙련된 프로그래머들에게도 이 예제는 훌륭한 시작점이 될 것입니다.

 

* 이 글은 Notion API Develpers - Beta: Getting started를 번역한 글입니다.

 

Getting started

Learn how to make your first API requests using the Notion API

developers.notion.com

 

 

반응형

 

Notion API Developer - Beta 한글 번역

 

 

 

0. 앞선 글.

 

데이터베이스 스키마, 쿼리 등에 대해 알아봅시다.

 

데이터베이스를 통해 사용자는 Notion에서 구조화된 데이터를 만들고 다룰 수 있습니다. 통합을 사용해 사용자는 데이터베이스를 외부 시스템과 동기화하거나 Notion 데이터베이스를 중심으로 워크플로우를 구축할 수 있습니다.

 

이 가이드에서는 데이터베이스가 API에서 어떻게 표현되는지부터 데이터베이스에 아이템을 추가하는 방법, 아이템을 찾는 방법뿐 아니라 페이지의 속성(properties)을 업데이트하는 방법도 배울 것입니다.

 

 

 

1. 데이터베이스의 구조.

 

데이터베이스 객체는 사용자가 데이터베이스를 열 때 Notion에서 보는 것을 표현합니다. 가장 중요한 부분은 속성(properties) 컬렉션에 정의된 데이터베이스의 스키마입니다.

 

{
  "object": "database",
  "id": "2f26ee68-df30-4251-aad4-8ddc420cba3d",
  "created_time": "2020-03-17T19:10:04.968Z",
  "last_edited_time": "2020-03-17T21:49:37.913Z",
  "title": [/* details omitted */],
  "properties": {/* a collection of property objects */},
}

 

 

 

2. 데이터베이스의 속성(Properties)

 

여러분이 보고 있는 데이터베이스가 표라고 가정해 보도록 합시다. 속성 객체는 열에 있는 모든 값들의 타입을 포함하며 열에 대한 설명을 저장합니다. 텍스트, 숫자, 날짜, 사람 등의 일반적인 타입을 사용할 수 있으며 각 타입에 대한 추가 구성 또한 사용할 수 있습니다. 다음 데이터베이스 객체 예시를 통해 속성 섹션에 대해 알아보도록 하겠습니다.

 

{
  "object": "database",
  "properties": {
    "Grocery item": {
      "id": "fy:{",
      "type": "title",
      "title": {}
    },
    "Price": {
      "id": "dia[",
      "type": "number",
      "number": {
        "format": "dollar"
      }
    },
    "Last ordered": {
      "id": "]\\R[",
      "type": "date",
      "date": {}
    },
  }
  // remaining details omitted
}

 

이 데이터베이스 객체에는 세 가지 속성이 정의되어 있습니다. 각각의 키는 속성의 이름이며 그 값은 속성 객체입니다. 몇 가지 핵심 사항에 대해 알아보겠습니다.

* "title"은 특별한 타입입니다. 모든 데이터베이스에는 "title" 타입을 가진 딱 하나의 속성이 존재합니다. 이 타입의 속성은 데이터베이스에서 각각의 아이템에 대한 페이지 제목을 참조하게 됩니다. 이 예시에서는 "Grocery item" 속성에 이 "title" 타입이 있습니다.

* "type"의 값은 속성 객체의 또 다른 키에 해당됩니다. 각 속성 객체에는 "type"의 값과 동일한 이름의 속성이 존재합니다. 예를 들어 "Last ordered"에는 "type"에 "date"라는 값이 존재하고 "date" 속성도 존재합니다. 이 패턴은 Notion API 전체에서 사용되며 type-specific 데이터라고 합니다.

* 특정 속성 객체에는 추가 구성이 있습니다. "number" 속성 내부에는 추가 구성이 있는 것을 확인할 수 있습니다. 이 예시에서 포맷 설정은 이 열이 보이는 방식을 제어하며 "dollar"로 설정되었습니다.

 

 

 

3. 데이터베이스에 페이지 추가하기.

 

페이지는 데이터베이스 내부의 아이템으로 사용되며 각 페이지의 속성은 부모 데이터베이스의 스키마를 따라야 합니다. 데이터베이스를 표라고 가정하면 페이지의 속성들은 한 행의 모든 값을 정의합니다.

 

페이지는 페이지 생성 API의 엔드포인트를 사용해 데이터베이스에 추가됩니다. 이 예시에서 데이터베이스에 새 페이지를 추가해 보도록 하겠습니다. 엔드포인트는 "parent"와 "properies"라는 두 가지 파라미터가 요구됩니다.

 

데이터베이스에 페이지를 추가할 때 "parent" 파라미터는 데이터베이스가 되어야 합니다. 

 

{
  "type": "database_id",
  "database_id": "2f26ee68-df30-4251-aad4-8ddc420cba3d"
}

* 데이터베이스에 접근하기 위해 통합에 미리 권한을 부여해야 합니다.

 

"properties" 파라미터는 속성 이름이나 ID를 키로 사용하고 속성 값 객체를 값으로 사용하는 객체입니다. 이 파라미터를 올바르게 작성하기 위해 데이터베이스 스키마의 특성 객체를 참고하세요. 예시 데이터베이스에 대해서 다음 객체를 생성할 수 있습니다.

 

{
  "Grocery item": {
    "type": "title",
    "title": [{ "type": "text", "text": { "content": "Tomatoes" } }]
  },
  "Price": {
    "type": "number",
    "number": 1.49
  },
  "Last ordered": {
    "type": "date",
    "date": { "start": "2021-05-11" }
  }
}

 

이제 위의 "parent"와 "properties" 두 파라미터를 사용해 페이지를 생성하기 위해 엔드포인트에 HTTP 요청을 전송해 보겠습니다.

 

curl -X POST https://api.notion.com/v1/pages \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2021-05-13" \
  --data '{
      "parent": { "type": "database_id", "database_id": "2f26ee68-df30-4251-aad4-8ddc420cba3d" },
      "properties": {
      "Grocery item": {
        "type": "title",
        "title": [{ "type": "text", "text": { "content": "Tomatoes" } }]
      },
      "Price": {
        "type": "number",
        "number": 1.49
      },
      "Last ordered": {
        "type": "date",
        "date": { "start": "2021-05-11" }
      }
    }
  }'

* Authorization와 database_id를 적절히 바꾸는 것을 잊지 마세요

* 정상적으로 페이지가 추가되기 위해선 데이터베이스의 스키마가 알맞게 구성되어야 함을 잊지 마세요.

 

페이지가 추가된다면 새 페이지 객체가 포함된 응답을 받게 됩니다. 이 응답에서 중요한 속성은 페이지 ID입니다. Notion을 외부 시스템에 연결하여 사용하는 경우 이 페이지 ID를 알아두는 것이 좋습니다. 나중에 이 페이지의 속성을 업데이트할 때 업데이트 페이지 엔드포인트에서 이 ID를 사용합니다.

 

 

 

4. 데이터베이스에서 페이지 찾기.

 

데이터베이스 쿼리 엔드포인트를 사용해 데이터베이스에서 페이지를 읽어올 수 있습니다. 이 엔드포인트를 사용하려면 "Last ordered가 지난주부터"와 같은 기준에 따라 페이지를 찾을 수 있습니다. 일부 큰 데이터베이스에서는 이 엔드 포인트를 사용하면 특정 순서의 더 작은 결과를 얻어 낼 수 있습니다.

 

이렇게 페이지를 찾는 데 사용되는 조건을 필터라고 합니다. 필터는 "Tag에 긴급이 포함됨"과 같은 단순한 조건부터 "Tag에 긴급이 포함되어야 하고 Due date는 몇 주 이내여야 하며 Assignee는 Cassandra Vasquez여야 함"과 같은 복잡한 조건으로 설정할 수 있습니다. 이러한 복잡한 조건은 "and"나 "or"을 사용해 여러 개의 단순한 조건을 결합하여 사용하므로 복합필터라고 합니다.

 

이 가이드에서는 예시 데이터베이스에 단일 속성 조건을 사용하는 것을 중점으로 둡니다. 데이터베이스 스키마를 살펴보면 "Last ordered" 속성이 "date" 타입을 사용한다는 것을 알고 있습니다. 즉 "date" 타입에 대한 조건을 사용해 "Last ordered"에 대한 필터를 만들 수 있습니다. 

 

{
  "property": "Last ordered",
  "date": {
    "past_week": {}
  }
}

 

이 필터를 사용해 예시 데이터베이스에서 조건에 맞는 페이지를 찾아와 보도록 합시다.

 

curl -X POST https://api.notion.com/v1/databases/2f26ee68df304251aad48ddc420cba3d/query \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"''
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2021-05-13" \
    --data '{
      "filter": {
      "property": "Last ordered",
      "date": {
        "past_week": {}
      }
        }
    }'

* Authorization과 URL의 databases 뒤에 데이터베이스 ID를 적절하게 바꿔야 함을 잊지 마세요.

 

필터에 일치하는 페이지 객체 목록이 포함된 응답을 받을 수 있습니다.

 

{
  "object": "list",
  "results": [
    {
      "object": "page",
      /* details omitted */
    }
  ],
  "has_more": false,
  "next_cursor": null
}

 

사실 이 응답은 페이징 된(paginated) 응답입니다. 페이징 된 응답은 큰 객체 목록을 반환하는 모든 Notion API의 응답에 사용됩니다. 페이징 된 응답의 최대 결과 개수는 100개입니다. 페이징 된 결과는 "start_cursor"과 "page_size" 파라 미터를 사용해 100개 이상의 결과를 얼어올 수도 있습니다.

 

이 예시에서 요청한 개별 페이지에 대한 정보는 "results"에 있습니다. 통합이나 사용자가 최근에 만들어진 페이지에 관심이 있다면 어떨까요? 가장 최근에 생성된 페이지가 첫 번째로 오도록 결과를 정렬할 수 있습니다. 특히 결과 페이지가 하나가 아닌 경우에 유용합니다.

 

"sort" 파라미터는 개별 속성 혹은 타임스탬프에 의해 결과를 정렬하는 데 사용됩니다. 이 파라미터는 정렬 객체의 배열에 할당될 수 있습니다.

 

페이지가 생성된 시간은 데이터베이스 스키마를 따르는 페이지 속성이 아닙니다. 이 속성은 모든 페이지에 존재는 두 종류의 타임스탬프 중 하나입니다. 이를 "created_time" 타임스탬프라고 합니다. 

 

이제 가장 최근에 생성된 페이지가 먼저 표시되도록 결과를 정렬하는 정렬 객체를 만들어보도록 하겠습니다.

 

{
  "timestamp": "created_time",
  "direction": "descending"
}

 

마지막으로 이 정렬 객체를 사용해 페이지를 요청해 보도록 하겠습니다.

 

curl -X POST https://api.notion.com/v1/databases/2f26ee68df304251aad48ddc420cba3d/query \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"''
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2021-05-13" \
    --data '{
      "filter": {
      "property": "Last ordered",
      "date": {
        "past_week": {}
      }
        },
    "sorts": [{ "timestamp": "created_time", "direction": "descending" }]
    }'

* 데이터베이스 ID과 토큰 정보를 적절히 수정해야 함을 잊지 마세요.

 

 

 

5. 맺는 글.

 

데이터베이스 속성들에 의해 만들어진 데이터베이스 스키마를 이해하는 것은 Notion 데이터베이스 작업의 핵심입니다. 이를 통해 데이터베이스에 페이지를 추가하고 데이터베이스에서 아이템을 찾을 수 있습니다.

 

* 이 글은 Notion API Develpers - Beta: Working with database를 번역한 글입니다.

 

Working with databases

Learn about database schemas, querying databases, and more.

developers.notion.com

 

 

 

반응형

https://dev.to/sowmenappd/build-a-highly-available-node-js-application-using-docker-nginx-and-aws-elb-3cjp

 

Docker, Express, NGINX, AWS ELB를 복합적으로 사용해 고가용성을 위한 애플리케이션 환경을 구축해 봅니다.

 

 

 

로드 밸런싱이 무엇인가요?

 

 

로드 밸런싱은 들어오는 네트워크 트래픽을 서버 그룹에 분산하는 데 사용되는 기술 혹은 알고리즘입니다. 모든 공용 사용자에게 서버에서 호스팅 하는 서비스에 대한 단일 진입점을 제공합니다.

 

프로덕션 서버는 일반적으로 로드 밸런서 뒤에서 실행됩니다. 서버 전체에서 들어오는 부하를 "균등"하게 나워 서버 과부하를 방지할 수 있기 때문입니다.

 

또한 로드 밸런서는 트래픽을 라우팅 하는 서버에 보조 기능을 제공합니다. 로드 밸런서는 역방향 프락시 역할을 합니다. 역방향 프락시는 서버 그룹과 사용자 간의 중개자와 같습니다. 역방향 프락시가 처리하는 모든 요청은 요청 조건에 따라 적절한 서버로 전달됩니다. 이런 방식으로 역방향 프락시는 구성파일, 토큰, 암호와 같은 민감한 데이터가 저장되는 주 서버에 대한 액세스를 방지하면서 서버의 ID를 익명으로 유지합니다.

 

 

 

로드 밸런서로서의 NGINX와 AWS ELB

 

NGINX는 역방향 프락시의 역할도 할 수 있는 빠른 무료 오픈소스 로드 밸런서입니다.

 

반면에 ELB는 아마존 AWS에서 제공하는 로드 밸런싱 서비스입니다. ELB는 ALB, CLB, NLB의 세 가지 유형이 있습니다. 게이트웨이 로드 밸런서라고 하는 새로운 로드 밸런서도 AWS가 제공하는 클라우드 서비스 제품군에 추가되었습니다.

 

이 튜토리얼의 아이디어는 다중 포트에서 실행되는 고 가용성 Node.js 서버를 제공할 수 있는 계단식의 다중 로드 밸런서 구조를 만드는 것입니다.

 

* 참고사항

Docker 애플리케이션을 위해 AWS의 자체 ECS, ECR 환경을 활용하는 방법을 포함해 AWS에서 Node.js 애플리케이션을 위한 인프라를 구축하는 방법에는 여러 가지 방법이 있습니다. 하지만 이 자습서에서는 이에 초점을 맞추지 않고 EC2 인스턴스, 로드 밸런서의 메커니즘, 로드밸런싱, 프락시 포트를 통해 Docker와 상호작용 하는 방법을 더 잘 이해하는 것을 목표로 합니다.

 

 

 

아키텍처 개요

 

 

이것이 우리가 목표로 하는 아키텍처입니다. AWS와 NGINX에서 관리하는 다중 로드 밸런서는 node 앱을 위한 EC2 인스턴스에서 여러 포트를 관리하는데 도움이 됩니다. 이 아키텍처의 장점은 두 인스턴스가 AZ1과 AZ2의 서로 다른 가용 영역을 가진다는 것입니다. 이로 인해 한 영역이 다운되더라도 다른 영역은 계속 동작할 것이며 두 애플리케이션은 충돌하지 않게 됩니다.

 

 

 

Node.js 앱

 

단순하게 하기 위해 다음과 같은 표준 스타터 express node 앱을 사용합니다:

 

const express = require("express");
const app = express();
const PORT = process.env.PORT;
const SERVER_ID = process.env.SERVER_ID;

app.get("/", (req, res)=>{
  res.send({server: SERVER_ID, port: PORT});
});

app.listen(PORT, ()=>{
  console.log(`Server ${SERVER_ID} is running at ${PORT}.`);
});

 

 포트는 환경변수의 PORT를 사용해 express 앱에 제공됩니다. Docker를 통해 이 포트 값을 제공할 것입니다. docker-compose를 이용하면 간단한 작업입니다. 또 다른 환경 변수인 SERVER_ID가 있지만 데모용일 뿐이므로 걱정하지 마세요.

 

전체 설정이 준비되면 SERVER_ID는 로드 밸런서가 응답을 가져오는 서버를 알려주는 데 사용됩니다. 이를 통해 다중 로드 밸런서 / 역방향 프락시를 사용하는 인프라 구성이 올바른 방식으로 실행되고 있는지 확인하는데 도움이 됩니다.

 

이러한 유형의 구성은 프로덕션 파이프라인에서 일반적인 구성입니다. 일반적으로 이 경우 기본 앱 서버는 VPC에 배치됩니다. 

 

한 가지 알아둘 점은 레벨 1 로드 밸런서가 실제 클라이언트의 요청을 처리하기 때문에 공용으로 분류되는 반면 레벨 2 로드 밸런서는 소스 간의 요청을 라우팅 하는 역할을 하는 내부의 로드 밸런서라는 것입니다.

 

 

 

EC2 서버 실행하기.

 

AWS 계정에 로그인하고 EC2 대시보드로 이동합니다. 다음 단계에 따라 새 서버를 설정하고 Docker를 사용할 준비를 합니다.

 

1. 대시보드에서 인스턴스 시작을 클릭합니다.

 

 

2. 빠른 시작 섹션에서 Amazon Linux 2 AMI를 선택합니다.

 

 

3. 인스턴스 유형에서 t2.micro를 선택합니다. 이 대신 원하는 다른 유형을 선택할 수도 있습니다.

 

 

4. 이 데모에서 두 인스턴스를 서로 다른 가용 영역에서 동작하길 원하므로 두 인스턴스를 별도로 시작해야 합니다. 이 글에서 리전은 ap-northeast-2 이므로 서브넷은 ap-northeast-2a를 선택했습니다.

 

 

5. 사용자 데이터 섹션 아래에 이 스크립트 코드를 붙여 넣어 node.js Docker 앱을 실행하기 위한 필수 소프트웨어를 설치하게 합니다.

 

 

#!/bin/bash
sudo amazon-linux-extras install -y docker
sudo service docker start
sudo usermod -a -G docker ec2-user
sudo chkconfig docker on
sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo yum install -y gcc-c++ make
curl -sL https://rpm.nodesource.com/setup_14.x | sudo -E bash -
sudo yum install -y nodejs git

 

6. 스토리지 추가와 태그 추가 섹션은 기본값을 유지한 채 건너뜁니다.

 

7. 보안 그룹 우성의 경우 포트 22(SSH)와 80(HTTP)이 열려있는 새 보안 그룹을 생성합니다.

 

 

IP 범위의 경우 Anywhere  또는 MyIP*8을 선택할 수 있습니다. 테스트 용이므로 아무거나 선택해도 됩니다. 전 Anywhere인 0.0.0.0을 선택하였습니다.

 

8. 검토 및 시작 버튼을 클릭해 실행시킵니다.

 

9. 인스턴스에 SSH를 위한 새 키 페어를 생성합니다. 나중에 앱이나 내부 로드 밸런서에 대한 Docker 이미지를 빌드하는데 필요합니다.

 

 

이제 두 개의 인스턴스 중 첫 번째 인스턴스가 시작되었습니다. 동일한 단계를 거쳐 다음 인스턴스를 시작하고 서브넷 값을 앞서 생성한 값이 아닌 다른 값으로 변경하고 방금 생성한 SSH 키 페어를 사용해 두 번째 인스턴스를 생성합시다.

 

 

 

 

앱 컨테이너화와 NGINX 구성.

 

여기서는 앱을 위해 다음 저장소를 사용합니다: load_balanced_nodejs_app

 

sowmenappd/load_balanced_nodejs_app

Source code for docker configuration of highly available Node JS app configured with NGINX running on multiple ports - sowmenappd/load_balanced_nodejs_app

github.com

 

이를 통해 프로세스 속도를 높일 수 있습니다. 저장소의 계층을 보자면 다음과 같습니다.

 

 

앱 폴더에는 Dockerfile과 함께 노드 서버 소스 코드가 포함되어 있습니다. nginx 폴더에는 업스트림 서버 포트 구성을 정의하는 구성 파일인 nginx.conf가 있으며 다음과 같습니다:

 

http{    
    upstream lb {        
        server 172.17.0.1:1000 weight=1;        
        server 172.17.0.1:2000 weight=1;        
        server 172.17.0.1:3000 weight=1;    
    }     
    server {        
        listen 80;        
        location / {            
            proxy_pass http://lb;        
        }    
    }
}

 

이 구성 파일은 메인 NGINX 서버가 포트 80번에서 동작한다고 지정하고 루트 위치 "/"은 lb라는 이 구성 파일에 정의된 업스트림으로 요청(프락시 패스)을 릴레이 합니다. lb는 서버 수를 지정하는 업스트림 객체이며 이 객체는 포함될 서버의 수와 이러한 서버가 내부적으로 실행될 포트를 지정합니다. 여기서 포함될 서버란 docker-compose를 통해 마운트 되는 서버이며 이는 이후 섹션에서 좀 더 자세히 다룹니다. 프락시는 80번 포트의 트래픽 부하를 분산시키게 됩니다. 

 

우리의 경우 업스트림 프락시는 트래픽을 1000번, 2000번, 3000번 포트로 보냅니다. 이 포트 번호는 docmer-compose YAML 파일에서 작성되는 env 변수로 익스프레스 서버 인스턴스에 전송되는 내부 PORT 값과 일치해야 합니다. 

 

각각의 시작되는 인스턴스에 대해 다음 작업을 수행해 줍니다.

 

1. 생성했던 키 페어를 이용해 인스턴스에 SSG로 연결합니다.

 

2. 다음 터미널 명령을 수행해 dockerfile로 앱 이미지를 빌드합니다.

 

git clone https://github.com/sowmenappd/load_balanced_nodejs_app.git
cd load_balanced_nodejs_app/app
docker build -t app .

 

 

3. 다음으로 NGINX 서버 이미지를 빌드합니다.

 

cd ../nginx
docker build -t nginx-s .

 

 

4. docker images 명령어를 실행 해 다음과 같은 내용이 표시되는지 확인합니다.

 

 

5. 두 번째 서버는 docker-compose.yml 파일을 수정해야 합니다. env 변수중 SERVER_ID는 모든 앱인 app1, app2, app3에 대해 2로 변경해야 합니다.

 

 

걱정하지 마세요 프로덕션 서버에서는 이런 일을 할 필요가 없습니다. 이는 데모 목적만을 위한 것입니다.

 

6. 마지막으로 다음 명령어를 실행합니다.

 

cd ..
docker-compose up -d

 

격리된 서버는 이제 백그라운드에서 세 개의 express 앱을 실행하게 됩니다. 이제 필요한 것은 AWS가 제공하는 로드 밸런서인 AWS ALB를 사용하여 이 시스템을 마운트 하는 것입니다.

 

 

 

AWS ALB에 시스템 마운트 하기.

 

이제 두 인스턴스 모두 마운트 할 준비가 되었습니다. 다음 단계를 따라 AWS에 애플리케이션 로드 밸런서를 설정하도록 합시다.

 

1. EC2 대시보드의 대상 그룹으로 이동해 대상 그룹을 만듭니다.

 

 

2. 대상 유형은 인스턴스를 선택 한 뒤 대상 그룹 이름을 작성하고 다음을 클릭하세요.

 

 

3. 실행 중인 두 인스턴스를 선택하고 선택한 인스턴스를 위한 포트를 80으로 설정한 뒤 아래에 보류 중인 것으로 포함 버튼을 클릭합니다.

 

 

4. 보류 중인 항목에 추가된 인스턴스를 확인한 뒤 대상 그룹을 생성합니다.

 

 

5. 이제 로드 밸런서로 이동해 로드 밸런서 생성 버튼을 클릭한 뒤 Application Load Balancer 생성을 클릭합니다.

 

 

6. 앞서 인스턴스를 생성할 때 선택한 가용 영역을 고른 뒤 계속합니다.

 

 

7. 보안 그룹 구성으로 이동해 모든 IP에 대해 80번 포트가 열려있는 새 보안 그룹을 만들고 다음을 클릭합니다.

 

 

8. 라우팅 구성에서 앞서 기존 대상 그룹을 고른 뒤 앞서 생성한 대상 그룹을 선택합니다.

 

 

9. 설정을 검토 한 뒤 로드 밸런서를 생성합니다. 로드 밸런서는 생성 후 상태 확인을 실행 한 뒤 몇 분 내로 실행되어야 합니다.

 

 

이제 EC2 대시보드의 로드 밸런서에서 방금 생성한 로드 밸런서의 DNS이름을 복사합니다. 

 

 

이 DNS 주소를 브라우저에 붙여 넣고 엔터를 누르세요. 브라우저를 새로 고칠 때마다 SERVER_ID와 PORT가 다른 값을 전송하는 것을 볼 수 있습니다.

 

 

이는 기본적으로 NGINX와 AWS 로드 밸런서가 로드 밸런싱을 위해 기본적으로 라운드 로빈 알고리즘을 사용하기 때문입니다.

 

 

 

맺는 글.

 

이렇게 배포된 시스템은 다중 로드 밸런서의 구성을 통해 높은 가용성을 보장하고 오랜 기간 동작하는 동안 많은 양의 트래픽을 견딜 수 있게 되었습니다. 이 자습서를 뒤이어 소스 제어와 통합 배포 파이프라인을 관리하고 GitHub 저장소에 커밋할 때 변경사항을 서버에 배포하는 방법을 보여주는 또 다른 기사를 게시할 예정입니다.

 

해당 글은 다음 글을 참고해 번역한 글입니다: Build a highly available Node.js application using Docker, NGINX and AWS ELB

 

Build a highly available Node.js application using Docker, NGINX and AWS ELB

What is load balancing? Load balancing is a technique(algorithm) used to distribute incomi...

dev.to

 

 

 

 

 

 

반응형

https://dev.to/vishnuchilamakuru/nginx-cheatsheet-24ph

 

NGINX는 웹 서비스, 역방향 프록시, 캐싱, 로드밸런싱, 미디어 스트리밍등을 위한 오픈소스 소프트웨어 입니다. 이 글에서는 자주 사용하는 NGINX 구성을 몇가지 다루도록 하겠습니다.

 

 

 

1. Listen To Port

 

server {
  # Standard HTTP Protocol
  listen 80;

  # Standard HTTPS Protocol
  listen 443 ssl;

  # Listen on 80 using IPv6
  listen [::]:80;

  # Listen only on using IPv6
  listen [::]:80 ipv6only=on;
}

 

 

 

2. Access Logging

 

server {
  # Relative or full path to log file
  access_log /path/to/file.log;

  # Turn 'on' or 'off'
  access_log on;
}

 

 

 

3. Domain Name

 

server {
  # Listen to yourdomain.com
  server_name yourdomain.com;

  # Listen to multiple domains
  server_name yourdomain.com www.yourdomain.com;

  # Listen to all domains
  server_name *.yourdomain.com;

  # Listen to all top-level domains
  server_name yourdomain.*;

  # Listen to unspecified Hostnames (Listens to IP address itself)
  server_name "";

}

 

 

 

4. Static Assets

 

server {
  listen 80;
  server_name yourdomain.com;

  location / {
          root /path/to/website;
  } 
}

 

 

 

5. Redirect

 

server {
  listen 80;
  server_name www.yourdomain.com;
  return 301 http://yourdomain.com$request_uri;
}

 

server {
  listen 80;
  server_name www.yourdomain.com;

  location /redirect-url {
     return 301 http://otherdomain.com;
  }
}

 

 

 

6. Reverse Proxy

 

server {
  listen 80;
  server_name yourdomain.com;

  location / {
     proxy_pass http://0.0.0.0:3000;
     # where 0.0.0.0:3000 is your application server (Ex: node.js) bound on 0.0.0.0 listening on port 3000
  }

}

 

 

 

7. Load Balancing

 

upstream node_js {
  server 0.0.0.0:3000;
  server 0.0.0.0:4000;
  server 123.131.121.122;
}

server {
  listen 80;
  server_name yourdomain.com;

  location / {
     proxy_pass http://node_js;
  }
}

 

 

 

8. SSL

 

server {
  listen 443 ssl;
  server_name yourdomain.com;

  ssl on;

  ssl_certificate /path/to/cert.pem;
  ssl_certificate_key /path/to/privatekey.pem;

  ssl_stapling on;
  ssl_stapling_verify on;
  ssl_trusted_certificate /path/to/fullchain.pem;

  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_connection_timeout 1d;
  ssl_session_cache shared:SSL:50m;
  add_header Strict-Transport-Security max-age=15768000;
}

# Permanent Redirect for HTTP to HTTPS
server {
  listen 80;
  server_name yourdomain.com;
  return 301 https://$host$request_uri;
}

 

 

 

개인적으로 사용하는 서버에서 NGINX를 사용하고 있습니다. dev.to를 보던 중 저장해 두고 필요할 때마다 참고하기 위해 포스팅 하였습니다. 해당 글의 출처는 다음과 같습니다: Nginx Cheatsheet

 

Nginx Cheatsheet

Nginx is open-source software for web serving, reverse proxying, caching, load balancing, media strea...

dev.to

 

 

 

 

 

 

반응형

https://dev.to/appfleet/building-docker-images-to-docker-hub-using-jenkins-pipelines-71m

 

Jenkins를 이용해 docker 이미지를 빌드하는 방법에 대해 알아봅니다.

 

 

 

0. Jenkins 및 docker 설치.

 

들어가기 앞서 jenkins와 docker를 미리 준비합니다.

 

 

 

1. Github 저장소 생성

 

가장 먼저 jenkins에서 빌드할 Github 저장소를 생성해 줍니다. 저장소에는 도커 이미지로 빌드할 때 사용될 dockerfile이 포함되어야 합니다.

 

Github 저장소는 다음을 참고해 주시기 바랍니다: JenkinsDockerPipeline

 

TheFatDuck/JenkinsDockerPipeline

Contribute to TheFatDuck/JenkinsDockerPipeline development by creating an account on GitHub.

github.com

 

dockerfile은 설명할 내용이 없으며 Jenkinsfile은 뒤에서 설명하도록 하겠습니다.

 

 

 

2. 빌드 환경 구성.

 

Jenkins에서 Docker 이미지를 빌드하기 위해선 별도의 플러그인이 필요합니다. Jenkins 플러그인 설치 페이지로 이동 후 "Docker Pipeline" 플러그인을 설치합니다.

 

 

다음으론 Docker Registry의 인증 정보를 등록해 줄 차례입니다. Global Credential 페이지로 이동 후 Add Credentials를 클릭해 인증 정보를 등록합니다.

 

 

전 이전에 생성한 Harbor의 인증정보를 입력했습니다.

 

 

다음은 git을 이용하기 위한 설정입니다. 먼저 Jenkins가 설치된 서버에 git이 없다면 설치합니다.

 

$ sudo apt-get install git

 

그 후 git exe 경로를 확인합니다.

 

$ gut --exec-path

 

Jenkins의 Global tool configuration 페이지로 이동해 Git 항목을 확인한 경로로 수정해 줍니다.

 

 

다음은 도커 사용 권한입니다. 기본적으로 Jenkins에서 바로 docker.sock를 사용할 순 없습니다. 다음 명령어로 권한을 부여해 주세요.

 

$ sudo chmod 666 /var/run/docker.sock

 

 

 

3. Jenkins 아이템 생성

 

이제 Jenkins Pipeline을 사용해 실제 빌드를 진행해 보도록 하겠습니다. "새로운 Item"을 클릭해 "Pipeline"을 선택하고 새로운 아이템을 만듭니다.

 

 

저장소를 확인해 보셨다면 내부에 ${env.BUILD_NUMBER}를 확인할 수 있습니다. 이 값을 태그로 이용할 것이며 해당 값은 빌드할 때 함께 넘겨줍니다. 이를 위해 매개변수를 정의합니다.

 

 

다음은 파이프 라인 관련 설정입니다. 파이프라인 설정은 다음과 같이 설정하시면 됩니다.

 

 

"Pipeline script from SCM"을 선택한 뒤 SCM은 git을 고르고 리포지토리 주소를 입력하면 됩니다. 해당 리포지토리 내의 "Jenkinsfile"을 파이프라인 스크립트로 사용하겠다는 의미를 가집니다.

 

"Build with parameter"를 클릭해 BUILD_NUMBER를 입력한 뒤 빌드하면 파이프라인을 통해 빌드되는 것을 확인할 수 있습니다.

 

 

이제 Jenkinsfile을 확인해 봅시다.

 

node {
  stage('========== Clone repository ==========') {
    checkout scm
  }
  stage('========== Build image ==========') {
    app = docker.build("jenkins-docker-pipeline/my-image")
  }
  stage('========== Push image ==========') {
    docker.withRegistry('YOUR_REGISTRY', 'YOUR_CREDENTIAL') {
      app.push("${env.BUILD_NUMBER}")
      app.push("latest")
    }
  }
}

 

업로드된 Jenkinsfile은 Scripted pipeline을 위한 스크립트입니다. 다른 방식으로 Declarative pipeline을 위한 방식도 있으나 이 글에선 설명하지 않도록 하겠습니다.

 

파이프라인은 세 스테이지로 동작합니다.

1. SCM에서 소스코드를 체크아웃받습니다.

2. dockerfile을 이용해 "jenkins-docker-pipeline/my-image"라는 이름으로 이미지를 빌드합니다. 

   Jenkinsfile에서 push 할 때 이미지 태그를 설정하므로 여기선 이미지 이름만 설정합니다.

3. DockerRegistry에 Credential을 이용해 이미지를 push 합니다. 

   여기서 앞서 정의한 BUILD_NUMBER가 사용되며 자동으로 latest 태그의 이미지도 함께 push 됩니다.

 

예를 들어 BUILD_NUMBER에 0.0.1을 입력하고 빌드하면 jenkins-docker-pipeline/my-image:0.0.1과 jenkins-docker-pipeline/my-image:latest가 push 됩니다.

 

 

 

 

 

 

반응형

http://blog.logicwind.com/efk-setup/

 

중앙 로그 수집을 위해 Eleastcsearch, Fluentd, Kibana를 이용해 EFK 스택을 구축해보도록 합니다.

 

 

 

1. 앞선 글

 

중앙 로그 수집을 위해 로그 수집기를 알아봤습니다: 2020.10.28 - [Programming] - LogStash vs Fluentd - 어떤 것을 선택해야 할까

 

LogStash vs Fluentd - 어떤 것을 선택해야 할까

이 글은 다음 글을 번역한 글입니다: Logstash vs Fluentd — Which one is better! Logstash vs Fluentd — Which one is better ! When it comes to collecting and shipping logs to Elastic stack, we usu..

smoh.tistory.com

 

Fluentd를 사용해보고자 했지만 미뤄졌던 일이 이제야 사용해 볼만한 기회가 찾아와 좀 더 자세히 포스팅하기로 했습니다.

 

EFK 스택은 기존 ELK 스택의 변형입니다. 기존 로그 수집 미들웨어인 Logstash 대신 Fluentd를 사용한 스택입니다. Elasticsearch, Logstash, Fluentd, Kibana에 대한 설명은 이 글에서 다루지 않도록 하겠습니다.

 

이 글의 예시는 Visual Studio의 dotNet5.0을 이용해 예시 프로젝트를 만들고 그 프로젝트의 로그를 fluentd를 통해 elasticsearch로 보낸 뒤 kibana에서 확인하는 과정으로 진행하도록 하겠습니다.

 

해당 내용은 다음 git 저장소에서 확인할 수 있습니다: FluentdTester

 

GitHub - smoh-dev/FluentdTester: https://smoh.tistory.com/415

https://smoh.tistory.com/415. Contribute to smoh-dev/FluentdTester development by creating an account on GitHub.

github.com

 

 

 

2. 테스트용 프로젝트 생성.

 

VisualStuio를 열고 dotNet 5.0을 사용해 WebAPI 프로젝트를 생성합니다. 프로젝트는 HTTPS를 지원하지 않도록 설정하였으며 Docker 지원은 체크해 생성합니다.

 

 

로그를 남기기 위해 Serilog를 사용하도록 합니다. NuGet 패키지 관리자를 열어 Serilog, Serilog.Sinks.File, Serilog.Formatting.Elasticsearch 패키지를 설치합니다.

 

 

Serilog는 로그를 남기기 위함이며 Serilog.Sink.File은 로그를 파일에 쓰기 위함이고 Serilog.Formatting.Elasticsearch는 로그 형식을 Elasticseach에 맞게 남겨주는 데 사용합니다.

 

새 컨트롤러를 생성해 Get요청이 오면 로그를 남기도록 코드를 작성합니다.

 

using Microsoft.AspNetCore.Mvc;
using Serilog;
using Serilog.Core;
using Serilog.Formatting.Elasticsearch;

namespace FluentdTester
{
    [Route("api/[controller]")]
    [ApiController]
    public class LogController : ControllerBase
    {
        private readonly Logger logger;
        public LogController()
        {
            logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .Enrich.FromLogContext()
                .Enrich.WithProperty("Service", "LogTester")
                .WriteTo.File(new ElasticsearchJsonFormatter(), "logs/fluentd-test.log", rollingInterval: RollingInterval.Day)
                .CreateLogger();
        }
        // GET: api/log/test
        [HttpGet("test")]
        public IActionResult Get()
        {
            logger.Debug(string.Format("This is sample log."));
            return Ok();
        }
    }
}

 

다음은 편의를 위한 코드 수정입니다. Production 환경에서도 swagger에 접속할 수 있도록  Startup.cs 파일을 수정합니다.

 

// Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseDeveloperExceptionPage();
    app.UseSwagger();
    app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "FluentdLogTester v1"));
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}

 

이제 도커 이미지로 빌드해 봅시다. 자동으로 생성된 Dockerfile을 우클릭 해 Docker 이미지 빌드를 클릭합니다.

 

 

정상적으로 빌드되는지 확인합니다. 해당 방식으로 이미지를 빌드하면 자동으로 latest 태그가 설정되어 빌드가 됩니다.

 

 

 

3. fluentd 추가하기.

 

앞서 작성한 프로그램이 로그를 남기면 fluentd는 그 로그파일을 읽어 Elasticsearch로 로그를 전송하는 역할을 담당하게 될 겁니다. 이렇게 로그 파일을 추적해 로그를 전송하는 방식은 fluentd의 "tail" Input Plugin을 사용합니다. 자세한 내용은 공식 홈페이지를 참고해 주시기 바랍니다: Fluentd - tail

 

로그를 읽어 들이는 Input Plugin이 있으면 반대로 읽은 로그를 Elasticsearch로 전송하는 기능도 있습니다. 다행히도 별도의 구현을 할 필요 없이 바로 Elasticsearch로 로그를 보낼 수 있도록 Elasticsearch Output Plugin을 제공해주고 있습니다. 자세한 내용은 공식 홈페이지를 참고해 주시기 바랍니다: Fluentd - elasticsearch

 

이제 tail과 elasticsearch를 사용할 수 있도록 fluentd의 설정 파일을 작성하도록 하겠습니다.

 

#/fluentd/conf/fluent.conf
<source>
  @type tail
  path /app/logs/fluentd-tester/*.log
  pos_file /app/logs/td-agent/logtest.log.pos
  tag logtest
  <parse>
    @type json
  </parse>
</source>
<match *.**>
  @type copy
  <store>
    @type elasticsearch
    host elasticsearch
    port 9200
    logstash_format true
    logstash_prefix fluentd
    logstash_dateformat %Y%m%d
    include_tag_key true
    type_name access_log
    tag_key @log_name
    flush_interval 1s
  </store>
  <store>
    @type stdout
  </store>
</match>

 

앞서 작성한 프로그램의 로그를 읽어 elasticsearch로 전송하는 설정 파일입니다. 다음으로는 이 설정 파일과 elasticsearch 플러그인을 사용할 수 있도록 fluentd 이미지를 빌드하는 dockerfile을 작성합니다.

 

# /fluentd/dockerfile
FROM fluentd:v1.9.1-debian-1.0
COPY /conf/* /fluentd/etc/
USER root
RUN ["gem", "install", "fluent-plugin-elasticsearch", "--no-document", "--version", "4.3.3"]
USER fluent

 

이제 이 dockerfile을 사용해 fluentd 이미지를 빌드해 줍니다.

 

$ docker build . -t my-fluentd:0.0.1

 

** 여기서는 conf 파일을 포함하는 이미지를 미리 빌드해서 사용합니다. 

** 만약 docker-compose에서 새로 빌드하고자 한다면 dockerfile의 "COPY /conf/* /etc/"를 사용할 수 없으므로 별도로 conf 파일을 옮겨주는 작업이 필요합니다. 

 

 

 

4. 배포를 위한 docker-compose 작성.

 

이 글은 간단한 테스트를 위한 글이므로 테스트 프로그램, fluentd, Elasticsearch, Kibana 모두 한 docker-compose 파일 내에 작성해 배포하도록 진행하겠습니다.

 

version: '3.9'

volumes:
  test-logs:

services:
  fluentd-tester:
    image:  fluentdtester:latest
    volumes:
        - test-logs:/app/logs
    depends_on:
        - "fluentd"
    expose:
        - "8080"
    ports:
        - "8080:80"

  fluentd:
    image: my-fluentd:0.0.1
    user: root
    volumes:
      - test-logs:/app/logs/fluentd-tester
    depends_on:
      - "elasticsearch"
    ports:
      - "24224:24224"
      - "24224:24224/udp"

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
    environment:
      - "discovery.type=single-node"
    expose:
      - "9200"
    ports:
      - "9200:9200"

  kibana:
    image: kibana:7.10.1
    depends_on:
      - "elasticsearch"
    ports:
      - "5601:5601"

 

내용은 간단합니다. 앞서 빌드한 이미지인 fluentdtester:latest와 my-fluentd:0.0.1 그리고 elasticsearch와 kibana를 실행시킵니다. fluentd-tester와 fluentd 서비스는 test-logs라는 이름의 볼륨을 이용해 데이터를 공유하도록 해주었습니다.

 

이를 통해 fluentd-service에서 작성한 로그파일에 fluentd가 접근해 tail로 로그파일을 elasticsearch로 전송합니다.

 

다음 명령어를 통해 docker-compose를 실행시켜봅시다.

 

$ docker-copmpose up -d

 

 

정상적으로 컨테이너들이 실행된 것을 확인할 수 있습니다.

 

 

 

5. 동작 확인.

 

컨테이너가 정상적으로 실행되었다면 이제 테스트 로그를 남겨봅시다. 다음 주소로 이동해 swagger를 사용해 로그를 남깁시다.

 

http://localhost:8080/swagger/index.html

 

 

정상적으로 로그가 남았음을 확인하고 싶다면 컨테이너에 접속해 /app/logs 폴더에 들어가 확인해보시면 됩니다.

 

이제 키바나에 접속해 인덱스 패턴을 생성해야 합니다. 다음 주소로 접속해 인덱스 패턴을 생성합니다.

 

http://localhost:5601/app/management/kibana/indexPatterns

 

 

Create index 화면에서 "fluentd-*" 패턴을 생성해줍니다.

 

 

Time Field는 @timestamp를 선택합니다.

 

 

이제 discover로 이동합니다.

 

http://localhost:5601/app/discover/

 

 

앞서 남긴 로그를 확인할 수 있습니다.

 

 

 

 

 

반응형

 

docker-compose를 이용해 간단히 MongoDB ReplicaSet을 구성하는 방법에 대해 알아보도록 합니다.

 

참고 소스는 다음 git 저장소에서 확인할 수 있습니다: MongoDBReplicaSetTest

 

GitHub - smoh-dev/MongoDBReplicaSetTest: https://smoh.tistory.com/419

https://smoh.tistory.com/419. Contribute to smoh-dev/MongoDBReplicaSetTest development by creating an account on GitHub.

github.com

 

 

 

0. Docker Desktop 설치

 

Docker Container로 배포를 위해선 개발 환경에 docker가 설치되어 있어야 합니다. 공식 홈페이지로 이동해 Docker Desktop을 설치합니다: www.docker.com/products/docker-desktop

 

Docker Desktop for Mac and Windows | Docker

Learn why Docker Desktop is the preferred choice for millions of developers building containerized applications. Download for Mac or Windows.

www.docker.com

 

 

 

1. Replica set 구성을 위한 js 파일 작성.

 

MongoDB에서 ReplicaSet을 설정하기 위한 js 파일을 작성합니다.

 

// init/
config = {
  _id : "replication",
  members: [
    {_id:0,host : "mongo1:27017"},
    {_id:1,host : "mongo2:27017"},
    {_id:2,host : "mongo3:27017"},
  ]
}
rs.initiate(config);
rs.conf();

 

members를 보면 알 수 있듯이 mongo1, mongo2, mongo3의 세 개의 MongoDB를 사용할 예정입니다. 이번 예시에서는 mongo1 서버에서 해당 스크립트를 수행하도록 진행할 것입니다.

 

 

 

2. 쉘 스크립트 작성.

 

MongoDB 컨테이너가 올라오면 앞서 작성한 스크립트 파일을 수행 해 Replica set을 구성하도록 하는 쉘 스크립트를 작성합니다.

 

#init/setup.sh
sleep 5 | echo "Waiting for the servers to start..."
mongo mongodb://localhost:27017 /usr/src/configs/init/setReplication.js

 

 

3. dockerfile 작성

 

앞서 스크립트를 작성하면서 설명했듯이 mongo1 컨테이너에서는 우리가 작성한 스크립트가 실행되어야 합니다. 이를 위해 MongoDB 이미지를 가져와 컨테이너 실행 시 우리의 코드가 실행되는 새로운 이미지를 만들어 보도록 하겠습니다.

 

# dockerfile

FROM mongo

WORKDIR /usr/src
RUN mkdir configs
WORKDIR /usr/src/configs

COPY init/* init/

RUN chmod +x init/setup.sh

CMD ["/usr/src/configs/init/setup.sh"]

 

수행하는 내용은 간단합니다. mongo 이미지를 가져와 /usr/src/config 폴더를 만들고 그 안에 init 폴더를 그대로 복사합니다. 그리고 앞서 작성한 setup.sh 파일에 권한을 부여한 후 setup.sh를 실행시키는 게 전부입니다. 

 

 

 

4. docker-compose.yml 작성

 

이제 거의 다 끝나갑니다. 마지막으로 여러 mongodb 컨테이너를 동시에 실행시키고 ReplicaSet을 구성하기 위한 docker-compose.yml 파일을 작성합시다.

 

version: '3'
services:
  mongo1:
    image: mongo-rep:0.0.1
    build:
      context: .
      dockerfile: dockerfile
    volumes:
      - {SOMEWHERE_YOUR_VOLUME}/mongoRepl/mongo1:/data/db
    ports:
      - "27021:27017"
    networks:
      - mongo-networks
    command: mongod --replSet replication

  mongo2:
    image: "mongo"
    ports:
      - "27022:27017"
    volumes:
      - {SOMEWHERE_YOUR_VOLUME}/mongoRepl/mongo2:/data/db
    networks:
      - mongo-networks
    command: mongod --replSet replication
    depends_on:
      - mongo1

  mongo3:
    image: "mongo"
    ports:
      - "27023:27017"
    volumes:
      - {SOMEWHERE_YOUR_VOLUME}/mongoRepl/mongo3:/data/db
    networks:
      - mongo-networks
    command: mongod --replSet replication
    depends_on:
      - mongo2

networks:
  mongo-networks:
    driver: bridge

 

mongo2와 mongo3은 mongo 이미지를 그대로 가져와 사용합니다. 볼륨은 각각 자신이 설정한 볼륨 경로 내의 "mongoRepl/mongo2"와 "mongoRepl/mongo3"에 컨테이너 내부의 mongodb 데이터가 저장됩니다.

 

세 컨테이너는 depends_on으로 연결되어 있으며 bridge 네트워크를 사용해 서로 서비스 이름을 통해 통신할 수 있습니다. 추가적으로 mongo2와 mongo3은 replSet 명령어로 "replication"이라는 이름으로 ReplicaSet을 생성합니다. 이 이름은 앞서 작성한 js의 _id에 입력한 값과 동일해야 합니다.

 

mongo1은 다른 두 서비스와 달리 mongo 이미지를 그대로 사용하지 않고 앞서 작성한 dockerfile을 이용해 새로운 이미지를 빌드합니다. 이 서비스가 실행되면 다른 두 mongodb 서비스와 같이 ReplicaSet을 구성하게 됩니다.

 

이제 다음 명령어를 통해 docker-compose를 실행시켜 봅시다

 

$ docker-compose up -d

 

이제 ReplicaSet이 정상적으로 동작하는지 확인하기 위해 컨테이너에 접속해 봅시다. 먼저 컨테이너의 ID를 확인합니다.

 

$ docker ps -a

 

 

컨테이너 ID를 확인 후 아무 데나 접속해 봅니다.

 

$ docker exec -u 0 -it 51 mongo

 

 

위와 같이 "replication:PRIMARY" 혹은 "replication:SECONDARY"라고 표시되면 정상적으로 ReplicaSet이 구성된 겁니다.

 

 

 

 

반응형

https://www.newline.co/@esausilva/adding-a-react-app-to-a-.net-core-mvc-app--63008d15

 


.Net 5.0을 사용해 React 프로젝트에서 Docker Container를 사용해 프로젝트를 배포하는 방법에 대해 알아봅니다.

 

 

 

0. Docker Desktop 설치.

 

Docker Container로 배포를 위해선 개발 환경에 docker가 설치되어 있어야 합니다. 공식 홈페이지로 이동해 Docker Desktop을 설치합니다: www.docker.com/products/docker-desktop

 

Docker Desktop for Mac and Windows | Docker

Learn why Docker Desktop is the preferred choice for millions of developers building containerized applications. Download for Mac or Windows.

www.docker.com

 

 

 

1. 프로젝트 생성

 

Visual studio를 켜고 React.js 프로젝트를 생성합니다.

 

 

프로젝트 이름은 적당히 짓고 대상 프레임워크는 .Net 5.0을 선택합니다.

 

 

* IDE는 Visual studio 2019 CE를 사용하였습니다.

 

 

 

2. Docker 지원 추가.

 

Visual studio 2019의 다른 여러가지 Web 프로젝트는 대부분 기본적으로 Docker Container 배포를 지원합니다. 하지만 안타깝게도 포스팅을 올리는 현재 Visual studio 2019에서 React.js 프로젝트는 Docker Container 배포를 기본적으론 지원하지 않습니다. 앞서 프로젝트를 만들 때 docker 지원을 보지 못하셨을 겁니다.

 

React.js 프로젝트에 수동으로 docker 지원을 추가해 봅시다. 먼저 프로젝트를 우클릭한 뒤 추가 -> Docker 지원을 클릭합니다.

 

 

대부분의 경우는 Linux container일겁니다. 자신이 원하는 대상 OS를 선택합니다.

 

 

이제 IDE가 자동으로 "Dockerfile"을 생성해 .Net5.0에 맞는 dockerfile을 작성해 줍니다. "Dockerfile"을 우클릭 해 "Docker 이미지 빌드"를 클릭해 도커 이미지를 생성해 봅시다.

 

 

빌드가 잘 되시나요? 아마 다음과 같은 오류와 함께 빌드가 실패했을 것입니다.

 

 

이제 빌드 출력창을 한번 뒤져봅시다. 아마 다음과 같은 에러 메시지를 마주 할 수 있을 겁니다.

 

1>#16 2.809 /bin/sh: 2: /tmp/tmp1d7d426dff82428db5f0845ee787658f.exec.cmd: npm: not found
1>#16 2.814 /src/DockerDeployExample/DockerDeployExample.csproj(37,5): error MSB3073: The command "npm install" exited with code 127.
1>#16 ERROR: executor failed running [/bin/sh -c dotnet publish "DockerDeployExample.csproj" -c Release -o /app/publish]: exit code: 1

 

누가 봐도 어디서 문제가 생긴건지 찾으실 수 있을 겁니다 npm: not found 우리 이미지엔 npm이 없었습니다.

 

 

 

3. .Net5.0 이미지에 nodejs 추가하기.

 

사실 MSDN을 애용하는 개발자라면 이런 문제를 마주치지 않을 수도 있었을 겁니다. MSDN의 다음 글을 확인해 주세요: Quickstart: Use Docker with a React Single-page App in Visual Studio

 

Visual Studio Container Tools with ASP.NET Core and React.js

Learn how to create a containerized React SPA app with Visual Studio Container Tools and Docker

docs.microsoft.com

 

리눅스 컨테이너 항목을 보면 수동으로 nodejs를 설치해야 하는 것을 알 수 있습니다. 이제 우리 "Dockerfile"에 다음과 같은 명령어를 추가해 주도록 합니다.

 

RUN curl -sL https://deb.nodesource.com/setup_15.x | bash -
RUN apt-get install -y nodejs

 

* 현재 포스팅 일자 기준으로 nodejs의 최신 버전은 15.x 버전이며 LTS는 14.x 버전입니다.

 

MSDN페이지에선 base와 build 모두에 설치했지만 .Net5.0에선 base 이미지에 nodejs를 설치하면 에러가 발생하며 build 이미지에만 nodejs를 설치해 줘도 정상적으로 빌드가 됩니다.

 

수정한 Dockerfile은 다음과 같습니다.

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
RUN curl -sL https://deb.nodesource.com/setup_15.x | bash -
RUN apt-get install -y nodejs
WORKDIR /src
COPY ["DockerDeployExample/DockerDeployExample.csproj", "DockerDeployExample/"]
RUN dotnet restore "DockerDeployExample/DockerDeployExample.csproj"
COPY . .
WORKDIR "/src/DockerDeployExample"
RUN dotnet build "DockerDeployExample.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "DockerDeployExample.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "DockerDeployExample.dll"]

 

이제 다시 "Dockerfile"을 우클릭 해 "Docker 이미지 빌드"를 클릭해 도커 이미지를 생성해보면 정상적으로 이미지가 생성되는 것을 확인할 수 있습니다.

 

 

 

4. Docker image push

 

이제 빌드한 이미지를 "게시" 기능을 이용해 Docker Registry에 Push까지 해봅시다. Docker Registry는 DockerHub를 사용하거나 PrivateRegistry를 구축해 사용하시면 됩니다.

 

프로젝트를 우클릭 해 "게시"를 클릭합니다.

 

 

게시 대상을 선택합니다. "Docker 컨테이너 레지스트리"를 선택합니다.

 

 

원하는 컨테이너 레지스트리를 선택합니다. 저는 이전에 구축한 Harbor에 게시해 보도록 하겠습니다.

 

 

자격증명과 레지스트리 경로를 입력합니다.

 

 

"호스팅" 항목의 "..."을 클릭하면 "이미지 태그 편집"을 사용할 수 있습니다. 기본값은 latest인데 이 값을 0.0.1로 바꿔 게시해 보도록 하겠습니다.

 

 

잠시 기다리면 게시가 완료되었다는 메시지를 확인할 수 있습니다.

 

 

실제로 Harbor에 접속해보면 이미지가 정상적으로 push 되었음을 확인할 수 있습니다.

 

 

 

 

 

 

반응형

+ Recent posts