LDAP Account Manager를 설치하고 사용하는 방법에 대해 알아봅니다.

 

 

 

0. 사전 준비

 

다음 글을 참고해 LDAP를 미리 준비합니다: 2020/01/20 - [Linux] - [Ubuntu] LDAP: OpenLDAP 설치하기

 

 

 

1. LDAP Account Manager 설치.

 

저는 편의상 LDAP가 설치된 우분투 서버에 LAM을 설치하였습니다. 다음 명령어를 실행시켜 LAM을 설치합니다.

 

> sudo apt-get install ldap-account-manager

 

알아서 필요한 파일을 모두 설치해 줍니다. 하나의 명령어만 실행시키면 LAM의 설치가 모두 끝납니다!

 

 

 

2. LDAP Account Manager 설정.

 

설치가 완료되었으면 http://{Host or IP}/lam/ 로 이동합니다. 맨 위의 그림이 우리를 맞이할 겁니다. 가장 오른쪽 위의 "LAM Configuration"을 클릭합니다.

 

그러면 보이는 두개의 옵션 중 "Edit server profiles"를 선택합니다. 기본 비밀번호는 "lam"입니다.

 

 

먼저 서버 설정입니다. 서버정보를 입력하고 Tree suffix에는 기본 DN정보를 입력해 줍니다.

 

 

다음은 보안설정입니다. 유저 리스트에 LDAP 인증 공급자 계정 정보를 입력합니다. 

 

 

이제 기본 암호 대신 사용할 자신의 암호를 입력합니다. 그 뒤 어카운트 타입 탭으로 이동합니다.

 

 

유저와 그룹에 사용할 ou정보를 입력해 줍니다. 이제 저장한 후 메인 페이지에서 아까 변경한 암호를 입력한 후 로그인합니다.

 

 

 

3. LDAP Account Manager 사용

 

로그인하면 다음과 같은 화면을 볼 수 있습니다.

 

 

아까 우리가 설정한 어카운트 타입을 기억하시나요? 그때 우리는 "Users"와 "Groups"의 "ou"를 설정하였습니다. 그 탭이 여기 그대로 보이네요! 전 이미 LDAP를 만들고 테스트하였기에 "ou=users"가 이미 존재하며 그 ou 내애 있는 유저 리스트도 불러온 것을 확인할 수 있습니다. 

 

 

그에 반해 Groups에는 아직 우리가 정한 ou에 해당하는 유닛이 없어 에러가 발생하네요. NewGroup를 선택해 새로운 그룹을 만들어 봅시다.

 

 

아무런 설정을 하지 않고 단지 DefaultGroup라는 그룹을 생성합니다.

 

 

아무래도 ou값은 자동으로 생성해주질 않나 봅니다. 그럼 직접 생성해 보도록 합시다. 우측 상단의 TreeView를 클릭합시다.

 

 

여기선 우리의 LDAP의 현황을 트리 구조로 확인할 수 있으며 직접 추가할 수도 있습니다. 이제 필요한 ou를 생성합시다. Create new entry here를 누르세요.

우린 새로운 ou가 필요합니다. 따라서 탬플릿은 Generic: Organisational Unit를 선택하면 됩니다. 우린 위에서 Groups를 설정할 때 ou를 group로 했습니다. 따라서 여기에 group를 입력한 뒤 Create object를 눌러줍니다.

 

 

작성한 내용을 확인하시고 commit를 누르신 뒤 Group탭으로 이동해보세요. 

 

 

더 이상 에러 메시지가 보이지 않네요. 기본 그룹도 다시 한번 생성해 보도록 합시다.

 

 

새로운 그룹도 정상적으로 생성된 것을 확인할 수 있습니다.

 

 

 

 

 

 

우분투 서버 18.04.2에 Jira를 설치해 봅니다.

 

 

 

1. Jira SW Server 다운로드

 

공식 홈페이지로 이동해 JIRA SW Server 설치 파일을 다운로드합니다. 미리 준비한 우분투 서버로 설치 파일을 옮겨주세요.

 

우분투 서버에 FTP를 사용하는 방법은 다음 글을 참고해 주세요: 2020/01/14 - [Linux] - [Ubuntu] FTP: Filezilla 서버 설치하기

 

 

 

2. JIRA 설치.

 

먼저 디렉토리를 이동해 설치 파일이 있는 폴더로 이동합니다. 그 후 다음 명령어를 통해 설치 파일에 실행 권한을 부여합니다.

 

> sudo chmod a+x atlassian-jira-software-X.X.X-x64.bin

 

실행 권한을 부여했다면 다음 명령어로 실행파일을 실행시킵니다.

 

> sudo ./atlassian-jira-software-X.X.X-x64.bin

 

OpenJDK를 설치하라는 메시지와 함께 설치가 진행됩니다. 중간에 프롬프트로 설치 옵션을 묻는 절차가 있습니다.

 

 

1을 입력하고 설치를 계속해 줍니다. 설치가 완료되면 자동으로 실행시킬 건지 묻는 메시지와 함께 설치가 완료됩니다.

 

 

정상적으로 설치가 완료되었습니다.

 

 

 

3. JIRA 설정.

 

설치가 완료되었다면 http://Host:8080으로 이동해 봅시다. 사용자 언어는 우측 상단의 Language를 눌러서 한글로 변경할 수 있습니다.

 

 

자세한 설정은 추후에 다루기로 하고 우선 기본값으로 설정해 봅시다. "사용자를 위해 설정하십시오"를 누른 후 "MyAtlassian으로 계속"을 누릅니다.

 

Atlassian계정으로 로그인하면 라이선스를 선택하는 화면에 나옵니다. 제품당 90일의 무료 평가판이 제공되니 우선 써보고 라이선스를 구매하시면 됩니다. "Jira Software (Server)"를 선택한 후 평가판 라이선스를 등록합니다.

 

라이선스를 정상적으로 등록하면 이제 어드민 계정 설정 화면이 나옵니다.

 

 

관리자 계정 정보를 넣고 다음 버튼을 누릅니다. JIRA가 자동으로 설정 파일을 구성하고 설치합니다.

 

 

설치가 완료되면 위와 같은 화면이 보입니다. 이제 시작해봅시다를 클릭해 JIRA를 사용합니다. 계정에 대한 기본 설정을 한 뒤 테스트 프로젝트를 생성해 어떻게 사용되는지 사용 케이스를 확인해 봅시다.

 

 

정상적으로 JIRA가 동작함을 확인할 수 있습니다.

 

 

 

 

 

웹 서핑을 하다 흥미로운 주제를 발견하여 번역 글을 올립니다.

해당 글은 Rhea MoutafisWhy Python is not the programming language of the future를 번역한 글입니다.

 

Python - Photo by David Clode on Unsplash

 

0. 앞선 글

 

최근 몇 년간 파이썬은 아주 핫한 언어가 아닐 수 없습니다. 직접 사용도 해보고 주변 사람들에게서 전해 들은 내용도 있으며 심지어 요즘 대학 강의에서도 가장 처음 배우는 언어 중 하나로 꼽히기도 한답니다. 

 

실제로 스택 오버 플로우의 2015~2019년간 조사한 프로그래밍 언어의 인기도를 봐 보겠습니다.

 

 

차트에서 보듯이 C/C++, JAVA와 박빙의 승부를 벌이고 있습니다. 이러한 상황에서 왜 파이썬은 미래의 언어가 아니라고 한 걸까요? 원글의 저자는 글 제목에 "몇 년은 더 수요가 많을지라도"를 덧붙였습니다. 이 대세 언어가 왜 미래의 언어가 될 순 없는지 약간은 자극적인 제목의 글에 끌려 읽은 글의 내용을 공유해보고자 합니다.

 

 

 

1. 소개

 

프로그래밍 커뮤니티가 파이썬을 평가하는 데에는 수십 년이 걸렸습니다. 그러나 2010년 초부터 인기가 급격히 상승하며 C, C#, JAVA, JavaScript의 인기를 뛰어넘었습니다.
그런데 이러한 트렌드가 언제까지 지속될까요? 파이썬은 언제 그리고 왜 다른 언어로 교체될까요?
파이썬 세계의 정확한 만료일을 정하는 것은 공상 과학만큼 너무나도 추측일 뿐입니다. 그 대신에 현재 파이썬의 인기를 높이는 장점과 미래에 인기를 깨뜨릴 약점에 대해서 평가할 것입니다. 

 

 

 

 

2. 현재 파이썬이 인기 있는 이유

 

파이썬의 성공은 플랫폼의 포스트에 있는 태그의 수를 측정하는 스택 오버플로우 트렌드에 반영됩니다. 스택 오버플로우의 크기로 볼 때 이는 언어 인기에 꽤나 좋은 지표입니다.

 

 

Snapshot of tags on various programming languages

 

R은 수년간 정체되어 왔으며 다른 많은 언어들은 꾸준히 감소세에 있는 반면에 파이썬의 성장은 막을 수 없어 보입니다. 모든 스택 오버플로우 질문 중 거의 14%에 파이썬 태그가 붙어있으며 이러한 트렌드는 증가하는 추세입니다. 여기에는 몇 가지 이유가 있습니다.

 

 

2.1. 파이썬은 오래되었습니다.

 

파이썬은 1990년대부터 존재해 왔습니다. 그것은 성장에 충분한 시간이었을 뿐 아니라 대규모의 지원 커뮤니티까지 확보하였습니다. 

 

따라서 파이썬으로 코딩하는 동안 문제가 발생하면 구글 검색 한 번으로 문제를 해결할 가능성이 높습니다. 누가 이미 문제를 겪고 문제에 대해 도움이 되는 무언가를 적어 놨을 것이기 때문입니다.

 

 

2.2. 파이썬은 초보자가 배우기 좋습니다.

 

수십 년은 프로그래머들이 뛰어난 튜토리얼을 만들 시간이었습니다. 그 외에도 파이썬의 문법은 사람이 읽기 쉽습니다.

 

시작을 위해 데이터 유형을 지정할 필요가 없습니다. 단시 변수를 선언하기만 하면 됩니다. 파이썬은 콘텍스트에서 그것이 integer인지, float인지, boolean인지 혹은 또 다른 것인지 알아서 이해합니다. 이것은 초보자에게 매우 큰 장점입니다.  C++로 프로그래밍한 적이 있다면 float를 int로 바꿨을 때 프로그램이 컴파일되지 않는 게 얼마나 실망스러운지 알 것입니다. 

 

그리고 파이썬과 C++ 코드를 비교해가며 읽어본 적이 있다면 파이썬이 얼마나 이해하기 쉬운지 알 수 있을 것입니다. C++는 영어를 염두하고 설계되었지만, 파이썬 코드와 비교하면 읽기에 더 어렵습니다. 

 

 

2.3. 파이썬은 다목적으로 사용할 수 있습니다.

 

파이썬은 오랫동안 사용되어 왔기 때문에 개발자들은 모든 목적에 맞는 패키지를 만들었습니다. 요즘에는 거의 모든 것들을 위한 패키지를 찾을 수 있습니다. 

 

숫자, 벡터, 행렬을 다루고 싶습니까? NumPy가 있습니다.

테크 혹은 엔지니어링에 대한 계산을 원합니까? SciPy를 사용하시면 됩니다.

데이터를 다루거나 분석하는데 관심이 있습니까? Pandas로 가십시오.

인공지능을 시작하고 싶습니까? 왜 Scikit-Learn을 사용하지 않나요?


관리하려는 계산 작업이 무엇이든 그것을 위한 파이썬 패키지가 있을 수 있습니다. 이것은 지난 몇 년간 머신러닝의 수요가 급증할 때 파이썬 최근 개발 언어에서 최고에 머무르게 하였습니다.

 

 

 

3. 파이썬의 단점과 치명적인지에 대한 여부.

 

이전의 정교함으로 완성된 작업으로 인해 파이썬이 앞으로 몇 년간은 계속될 것으로 상상할 수 있습니다. 그러나 모든 기술이 그렇듯이 파이썬에는 약점이 있습니다. 가장 중요한 결점들을 하나씩 살펴본 후 이것이 치명적인가를 평가하겠습니다.

 

 

3.1. 속도

 

파이썬은 느립니다. 진짜 느려요. 파이썬으로 작업을 완료하는데 드는 시간은 다른 언어보다 평균적으로 2~10배나 더 필요합니다.

 

느린 이유는 여러 가지가 있습니다. 그중 하나는 타입이 동적으로 정해진다는 것입니다. 앞서 적은 내용 중에 다른 언어처럼 데이터 유형을 지정할 필요가 없다는 것을 기억하시나요? 이건 프로그램이 어떤 경우에도 동작하는 변수에 대해 충분한 공간을 점유해야 하기 때문에 많은 메모리를 사용해야 함을 의미합니다. 그리고 많은 메모리 사용은 많은 컴퓨팅 시간으로 이어집니다.

 

또 다른 이유는 파이썬이 한 번에 하나의 작업만 수행할 수 있기 때문입니다. 이는 유연한 데이터 타입의 결과입니다. 파이썬은 각 변수에 하나의 데이터 타입만 있는 것을 보장해야 하며 병렬 프로세스는 이를 망칠 수 있습니다. 

 

이에 비해 일반적인 웹 브라우저는 열두 개의 다른 스레드를 동시에 실행할 수 있습니다.  그리고 몇몇 다른 이론들 또한 있습니다. 그러나 날이 지나면 속도 문제는 중요하지 않습니다. 컴퓨터와 서버는 너무 저렴해져서 초단위 미만에 대해 이야기하고 있습니다. 그리고 엔드유저는 앱이 0.001초 또는 0.01초 만에 로드되는지 전혀 신경 쓰지 않습니다.

 

 

3.2. 범위(Scope)

 

원래 파이썬은 동적으로 범위가 지정되었습니다. 이건 기본적으로 모든 표현식을 평가하기 위해 컴파일러가 먼저 현재 플록을 검색한 뒤 연속적으로 모든 호출 함수를 검색한다는 걸 의미합니다.

 

동적 범위 지정의 문제점은 모든 표현식이 모든 가능한 상황에서 테스트되어야 한다는 점입니다. 그렇기 때문에 대부분의 모던 프로그래밍 언어는 정적 범위를 사용합니다. 

 

파이썬은 정적 범위로 전환을 시도하였으나 실패하였습니다. 일반적으로 내부 범위(예를 들면 함수 내의 함수)는 외부 범위를 보고 외부 범위를 변경할 수 있습니다. 파이썬에서 내부 범위는 외부 범위를 볼 순 있지만 외부 범위를 변경할 순 없습니다. 이것은 많은 혼란을 초래합니다.

 

 

3.3. 람다

 

파이썬의 모든 유연성에도 불구하고 람다의 사용은 제한적입니다. 람다는 파이썬에서 표현식(Expression)에서만 사용될 수 있고 구문(Statement)에선 사용할 수 없습니다.

 

반면에 변수 선언과 구문은 항상 구문입니다. 이는 람다를 변수 선언에 사용할 수 없음을 의미합니다. 표현식과 구문의 구별은 약간 멋대로이며 다른 언어에서는 발생하지 않습니다. 

 

 

3.4. 공백

 

파이썬에서 다른 레벨의 코드를 공백과 들여 쓰기를 사용하여 나타냅니다. 이는 시각적으로 매력적이고 직관적으로 이해할 수 있도록 만듭니다.

 

C++와 같은 다른 언어에서는 중괄호와 세미콜론에 의존합니다. 이는 시작적으로 매력적이지 않고 초보자에게 친숙하지 않지만 코드를 유지 관리하기 훨씬 쉽습니다. 대규모 프로젝트에서 이는 매우 유용합니다. Haskell과 같은 최신 언어는 이러한 문제를 다음과 같이 해결합니다: 공백에 의존하지만 공백을 대체할 문법을 제공합니다.

 

 

3.5. 모바일 개발

 

데스트톱에서 스마트폰으로의 움직임이 보임에 따라 우리는 모바일 소프트웨어를 구축하기 위해 견고한 언어가 필요합니다.

 

하지만 많은 모바일 앱들이 파이썬으로 개발되지 않습니다. 그렇다고 그것이 알 수 없다는 의미는 아닙니다. 모바일 앱 개발을 위해 파이썬은 Kivy라는 패키지를 제공합니다.

 

그러나 파이썬은 모바일을 염두하고 만들어지지 않았습니다. 그래서 기본적인 작업애 대해서는 적합한 결과를 얻을 수도 있지만 모바일 앱 개발을 위해 만들어진 언어를 사용하는 것이 가장 좋습니다. 모바일을 위해 널리 사용하는 프로그래밍 프레임워크에는 React Native, Flutter, Iconic, Cordova가 있습니다.

 

명백히 랩톱과 데스크톱 컴퓨터는 다가울 수년간 존재할 것입니다. 그러나 모바일은 오랫동안 데스크톱 트래픽을 뛰어넘었기 때문에 파이썬을 배우는 것 만으로는 숙달된 만능 개발자가 되기에는 부족합니다. 

 

 

3.6. 런타임 에러

 

파이썬 스크립트는 먼저 컴파일된 뒤에 실행되는 것이 아닙니다. 그 대신 실행할 때마다 컴파일됩니다. 그러므로 런타임에 코딩 에러가 나타납니다. 이러한 점은 낮은 성능, 시간 소비, 많은 테스트를 요구하게 됩니다. 

 

테스팅은 초보자에게 많은 것을 가르쳐 주기 때문에 초보자들에게는 좋습니다. 그러나 숙련된 개발자에게는 파이썬으로 된 복잡한 프로그램을 디버그 해야 하기 때문에 잘못된 결과를 만들게 합니다.

 

 

 

4. 언제 그리고 무엇이 미래에 파이썬을 대체할 수 있을까.

 

프로그래밍 언어 시장에는 몇 개의 새로운 경쟁자가 나타났습니다:

  • Rust는 파이썬이 가진 것과 동일한 종류의 안전성을 제공합니다 - 실수로 덮어쓸 수 있는 변수는 존재하지 않습니다. 하지만 Rust는 소유권과 빌리는 개념으로 성능 문제를 해결합니다. 스택 오버플로우 인사이트에 따르면 지난 몇 년간 가장 사랑받는 프로그래밍 언어이기도 합니다.
  • Go는 파이썬과 같이 초보자에게 좋습니다. 그리고 심지어 코드를 유지보수 하기가 매우 간단합니다. 재미있는 점은 Go 개발자는 시장에서 가장 많은 보수를 받는 프로그래머 중 하나입니다. 
  • Julia는 파이썬과 정면에서 경쟁하는 매우 새로운 언어입니다. Julia는 매우 큰 기술적 계산의 간극을 채웁니다: 일반적으로 파이썬 또는 Matlab을 사용하고 모든 것을 C++ 라이브러리로 패치했습니다. 이제 Julia 하나로 다른 두 언어로 저글링을 할 필요가 없어졌습니다.

시장에 다른 언어들이 존재하지만 Rust, Go, Jilia는 파이썬을 조금만 수정하는 언어들입니다. 이러한 언어들은 모두 아직 오지 않은 기술들에 있어서 뛰어납니다. 특히 인공지능 분야에서 가장 주목할만합니다.  스택 오버플로우 태그의 수에 반영된 것처럼 아직 시장 점유율은 낮지만 이러한 언어들 모두의 트렌드는 상승할 것이 명확합니다.

 

Snapshot of tags on various programming languages

 

어디에서나 인기 있는 파이썬의 인기를 볼 때, 새로운 언어 중 하나가 파이썬을 대체할 때 까지는 분명히 5년이 걸릴 것이며 심지어는 10년이 걸릴 수도 있습니다.

Rust, Go, Julia 또는 미래의 새로운 언어 중 어떤 것이 파이썬을 대체할 것인지는 이 시점에서 말하기 어렵습니다. 그러나 파이썬 아키텍처에서 근본적인 성능 문제를 생각해 본다면 그중 하나는 반드시 파이썬을 대체할 것입니다. 

 

 

 

5. 마무리

 

글을 읽으면서, 읽고 나서 여러 의문점이 떠올랐습니다. 아니나 다를까 이 글에는 분명히 논쟁의 여지가 있습니다. 원문의 댓글창에서도 많은 의견들이 올라오고 있습니다. 

 

원 글은 올라온 지 2일 만에 8600여 개의 박수를 받았고 댓글도 120여 개에 달합니다. 그만큼 파이썬에 대한 인기와 그 문제점에 대해 명확히 지적하고 있음을 느낄 수 있습니다. 

 

이 글이 100% 완벽하고 비판의 여지가 없다고 생각하지는 않습니다. 읽고 계시는 분들도 자신이 파이썬을 바라보는 시각과 느끼고 계신 단점이 있을 테고 파이썬을 사용하는 장점 또한 당연히 갖고 계실 겁니다. 다만 이러한 글을 읽고 새로운 시각으로 파이썬을 보게 되거나 새로운 영감이 떠오르셨으면 좋겠습니다.

 

 

 

 

GraphQL에 대해 알아보는 글을 포스팅합니다. 이 글에선 GraphQL의 구조에 대해 알아봅니다. 

이전 글인 Graphql에 대한 기본적인 소개와 REST API와의 비교를 통한 차이점은 이 글에서 확인해 볼 수 있습니다.

 

 

 

 

 

1. 쿼리(Query)와 뮤테이션(Mutation)

 

쿼리는 읽기를 요청하는 구문이며 뮤테이션은 수정을 요청하는 구문입니다. gql에서는 굳이 쿼리와 뮤테이션을 나누는데 사실상 이 둘은 별 차이가 없어 보입니다. 쿼리는 데이터를 읽는데(R) 사용하고, 뮤테이션은 데이터를 변조(CUD) 하는 데 사용한다는 개념 적인 규약을 정해 놓은 것뿐입니다.

 

다만 쿼리가 실행되는 순서에 중요한 차이점이 있는데 Query 필드가 병렬로 실행되는 동안 Mutation 필드는 순차적으로 실행됩니다. 즉, 하나의 요청에서 두 개의 Mutation를 보내면 순차적으로 실행되어 경쟁 상태가 되지 않도록 합니다. (GraphQL의 구현 조건입니다.)

 

다음 두 쿼리문을 한번 봅시다.

{
  human(id: "1000") {
    name
    height
  }
}

query HeroNameAndFriends($episode: Episode) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}

 

두 쿼리 문의 차이가 보이시나요? 결론부터 말하면 위의 쿼리는 오퍼레이션 이름(Operation name)이 붙지 않은 일반적이 인 오퍼레이션 즉, gql의 기본 쿼리문이고 아래의 쿼리는 오퍼레이션 이름이 붙은 쿼리입니다.

** 오퍼레이션(Operation)은 GraphQL 실행 엔진으로 해석할 수 있는 단일 쿼리(Queyr), 뮤테이션(Mutation) 또는 구독(Subscription)을 의미합니다.

 

일반적인 경우 클라이언트에서 static 한 쿼리문을 작성하지는 않을 것입니다. 주로 정보를 불러올 때 id 값이나, 다른 인자 값을 가지고 데이터를 불러올 것입니다. gql을 구현한 클라이언트에서는 이 변수에 프로그래밍으로 값을 할당할 수 있는 함수 인터페이스가 존재합니다. 

 

오퍼레이션 이름이 있는 쿼리

 

위의 그림을 통해 오퍼레이션에 대해 좀 더 자세히 알아보겠습니다. 

  • 오퍼레이션 타입: 어떤 유형의 작업을 수행하고자 하는지 표시합니다. query, mutation 또는 subscription입니다. 
  • 오퍼레이션 이름: 오퍼레이션에 이름을 부여합니다. 프로그래밍 언어의 함수 이름과 유사합니다. 이름을 정해두면 네트워크 로그나 GraphQL 서버에서 문제가 발생했을 시 내용을 해독할 필요 없이 코드 베이스에서 해당 쿼리를 쉽게 찾을 수 있습니다.
  • 변수 정의: 쿼리에 필요한 변수입니다. GraphQL 서버로 쿼리를 보낼 때 실제 쿼리는 동일하지만 요청마다 변경되는 동적 부분이 있을 수 있습니다. 이때 변수가 사용됩니다. 이 변수는 쿼리와 별도로 전송되며 전송 포맷은 JSON입니다.

 

오퍼레이션 이름이 붙은 쿼리는 데이터베이스에서의 프로시저(Procedure) 개념과 유사하다고 생각하면 됩니다.

이 개념 덕분에 REST API를 호출할 때와 다르게, 한 번의 인터넷 네트워크 왕복으로 여러분이 원하는 모든 데이터를 가져올 수 있습니다.

 

데이터베이스의 프로시저는 DBA 혹은 백앤드 프로그래머가 작성하고 관리하였지만, gql 오퍼레이션은 는 클라이언트 프로그래머가 작성하고 관리합니다.

이전 협업 방식(REST API)에서는 프런트 앤드 프로그래머는 백앤드 프로그래머가 작성하여 전달하는 API의 request / response의 형식에 의존하게 됩니다. 그러나, gql을 사용한 방식에 서는 이러한 의존도가 많이 사라집니다만 여전히 데이터 스키마에 대한 협업 의존성은 존재합니다.

 

 

2. 스키마(Schema)와 타입(Type)

 

데이터베이스 스키마(Schema)를 작성할 때의 경험을 SQL 쿼리 작성으로 비유한다면, gql 스키마를 작성할 때의 경험은 C, C++의 헤더 파일 작성에 비유가 됩니다. 그러므로, 프로그래밍 언어(C, C++, JAVA 등)에 익숙한 프로그래머라면 스키마 정의 또한 쉽게 배울 수 있습니다.

 

GraphQL 스키마의 가장 기본적인 구성 요소는 객체(Object) 타입입니다. 객체 타입은 서비스에서 가져올 수 있는 객체의 종류와 그 객체의 필드를 나타냅니다. GraphQL 스키마 언어에서는 다음과 같이 표현할 수 있습니다.

 

type Character {
  name: String!
  appearsIn: [Episode]!
}

 

위 스키마에 대해 좀 더 자세히 알아봅시다.

  • Character: GraphQL의 객체 타입. 즉, 필드가 있는 타입이 됩니다. 대부분의 스키마는 객체 타입입니다.
  • name과 appersIn: Character 타입의 필드.  name과 appearsIn은 GraphQL 쿼리의 Character 타입 어디서든 사용할 수 있는 필드가 됩니다.
  • String: 내장된 스칼라 타입 중 하나. 스칼라 객체로 해석되는 타입을 의미하며 쿼리에서 하위 선택을 할 수 없습니다.
  • !: 해당 필드가 NULL을 허용하지 않음을 의미합니다. 이 필드를 쿼리 할 때 GraphQL 서비스가 항상 값을 반환함을 의미합니다. 
  • [Episode]!: Episode 객체의 배열을 나타내며 NULL이 아님을 의미합니다. 따라서 appearIn 필드를 쿼리 하면 항상 0개 이상의 아이템을 가진 배열을 기대할 수 있습니다.

 

 

3.3 리졸버(Resolver)

 

데이터베이스 사용 시, 데이터를 가져오기 위해서 sql을 작성했습니다. 또한, 데이터베이스에는 데이터베이스 애플리케이션을 사용하여 데이터를 가져오는 구체적인 과정이 구현되어 있습니다. 그러나 gql에서는 데이터를 가져오는 구체적인 과정을 직접 구현해야 합니다. 


gql 쿼리문 파싱은 대부분의 gql 라이브러리에서 처리를 하지만, gql에서 데이터를 가져오는 구체적인 과정은 resolver(이하 리졸버)가 담당하고, 이를 직접 구현해야 합니다.  프로그래머는 리졸버를 직접 구현해야 하는 부담은 있지만, 이를 통해서 데이터 source의 종류에 상관없이 구현이 가능합니다. 


예를 들어서, 리졸버를 통해 데이터를 데이터베이스에서 가져올 수 있고, 일반 파일에서 가져올 수 있고, 심지어 http, SOAP와 같은 네트워크 프로토콜을 활용해서 원격 데이터를 가져올 수 있습니다. 
이러한 특성을 이용하면 legacy 시스템을 gql 기반으로 바꾸는데 활용할 수 있습니다.

gql 쿼리에서는 각각의 필드마다 함수가 하나씩 존재한다고 생각하면 됩니다. 이 함수는 다음 타입을 반환합니다. 이러한 각각의 함수를 리졸버(resolver)라고 합니다. 다시 말하자면 리졸버는 쿼리에서 특정 필드에 대한 요청이 있을 때, 그것을 어떤 로직으로 처리할지 GraphQL에게 알려주는 역할을 맡습니다. 만약 필드가 스칼라 값(문자열이나 숫자와 같은 primitive 타입)인 경우에는 실행이 종료됩니다. 즉 더 이상의 연쇄적인 리졸버 호출이 일어나지 않습니다. 
하지만 필드의 타입이 스칼라 타입이 아닌 우리가 정의한 타입이라면 해당 타입의 리졸버를 호출되게 됩니다.

 

다음 예시를 통해 리졸버에 대해 좀 더 알아봅시다.

 

Query: {
  human(obj, args, context, info) {
    return context.db.loadHumanByID(args.id).then(
      userData => new Human(userData)
    )
  }
}

 

이 예시에서 Query 타입은 인자 id를 받아 human 필드를 반환합니다. 이 필드의 리졸버 함수는 데이터베이스에 접근한 다음 Human 객체를 생성하고 반환합니다. 이 예시는 자바스크립트로 작성되었지만 GraphQL 서버는 다양한 언어로 만들 수 있습니다. 

 

리졸버 함수는 네 개의 인수를 받습니다.

  • obj: 루트 Query 타입 이전의 객체.
  • args: GraphQl 쿼리의 필드에 제공된 인수들.
  • context: 모든 리졸버 함수에 전달되며 현재 로그인한 사용자, 데이터베이스 액세스 등 중요한 컨텍스트 정보를 갖고 있는 값.
  • info: 현재 쿼리, 스키마 정보와 관련된 빌드 별 정보를 갖고 있는 값.

 

예시에서 볼 수 있듯이 각각의 리졸버 함수에는 내부적으로 데이터베이스 쿼리가 존재합니다. 이 말인즉, 쿼리에 맞게 필요한 만큼만 최적화하여 호출할 수 있다는 의미입니다.

기존에 REST API 시대에는 정해진 쿼리는 무조건 전부 호출이 되었습니다. 이러한 리졸버 체인을 잘 활용한다면, 효율적인 설계가 가능합니다. 

 

 

 

4. 인스트로펙션(Instropection, 스키마 확인)

 

기존 서버-클라이언트 협업 방식에서는 연동 규격서라고 하는 API 명세서를 주고받는 절차가 반드시 필요했습니다. 프로젝트 관리 측면에서 관리해야 할 대상의 증가는 작업의 복잡성 및 효율성 저해를 의미합니다. 이 API 명세서는 때때로 관리가 제대로 되지 않아, 인터페이스 변경 사항을 제때 문서에 반영하지 못하기도 하고, 제 타이밍에 전달 못하곤 합니다.

이러한 REST의 API 명세서 공유와 같은 문제를 해결하는 것이 gql의 인트로스펙션 기능입니다. gql의 인트로스펙션은 서버 자체에서 현재 서버에 정의된 스키마의 실시간 정보를 공유를 할 수 있게 합니다. 이 스키마 정보만 알고 있으면 클라이언트 사이드에서는 따로 연동 규격서를 요청할 필요가 없게 됩니다. 클라이언트 사이드에서는 실시간으로 현재 서버에서 정의하고 있는 스키마를 의심할 필요 없이 받아들이고, 그에 맞게 쿼리문을 작성하면 됩니다.

이러한 인트로스펙션용 쿼리가 따로 존재합니다. 일반 gql 쿼리문을 작성하듯이 작성하면 됩니다. 다만 실제로는 굳이 스키마 인트로스펙션을 위해 gql 쿼리문을 작성할 필요가 없습니다. 대부분의 서버용 gql 라이브러리에는 쿼리용 IDE를 제공합니다. 

 

프로그래머는 인트로스펙션을 활용하여, 직접 쿼리 및 뮤테이션, 필드 스키마를 확인할 수 있습니다. 물론 보안상의 이슈로 상용 환경에서는 이러한 스키마의 공개는 신중해야 합니다. 대부분의 라이브러리는 해당 기능을 켜고 끄게 하는 옵션이 존재합니다.

 

아래의 예시로 인스트로펙션 쿼리와 그에 대한 결과를 확인해 봅시다.

일반적으로 타입 시스템을 사용하기 때문에 우리는 유효한 타입이 무엇인지 알고 있지만, 그렇지 않은 경우에는 Query의 루트 타입에서 항상 사용할 수 있는 __schema 필드를 쿼리 하여 GraphQL에 요청할 수 있습니다. 아래의 쿼리는 그 예시입니다.

 

{
  __schema {
    types {
      name
    }
  }
}

 

더보기

{
  "data": {
    "__schema": {
      "types": [
        {
          "name": "Query"
        },
        {
          "name": "Episode"
        },
        {
          "name": "Character"
        },
        {
          "name": "ID"
        },
        {
          "name": "String"
        },
        {
          "name": "Int"
        },
        {
          "name": "FriendsConnection"
        },
        {
          "name": "FriendsEdge"
        },
        {
          "name": "PageInfo"
        },
        {
          "name": "Boolean"
        },
        {
          "name": "Review"
        },
        {
          "name": "SearchResult"
        },
        {
          "name": "Human"
        },
        {
          "name": "LengthUnit"
        },
        {
          "name": "Float"
        },
        {
          "name": "Starship"
        },
        {
          "name": "Droid"
        },
        {
          "name": "Mutation"
        },
        {
          "name": "ReviewInput"
        },
        {
          "name": "__Schema"
        },
        {
          "name": "__Type"
        },
        {
          "name": "__TypeKind"
        },
        {
          "name": "__Field"
        },
        {
          "name": "__InputValue"
        },
        {
          "name": "__EnumValue"
        },
        {
          "name": "__Directive"
        },
        {
          "name": "__DirectiveLocation"
        }
      ]
    }
  }
}

* 접은 글을 펼치면 예시 결과를 확인할 수 있습니다.

 

  • Query, Character, Human, Episode, Droid: 타입 시스템에서 정의한 것들입니다.
  • __Schema, __Type, __TypeKind, __Field, __InputValue, __EnumValue, __Directive: 모두 앞에는 두 개의 밑줄이 붙어있는데, 이것은 인스트로펙션 시스템의 일부임을 나타냅니다.

 

어떤 객체가 어떤 필드를 사용할 수 있는지 알아보기 위해 예시로 Droid를 인스트로펙션 시스템에 요청해 봅시다.

 

{
  __type(name: "Droid") {
    name
    fields {
      name
      type {
        name
        kind
      }
    }
  }
}
더보기

{
  "data": {
    "__type": {
      "name": "Droid",
      "fields": [
        {
          "name": "id",
          "type": {
            "name": null,
            "kind": "NON_NULL"
          }
        },
        {
          "name": "name",
          "type": {
            "name": null,
            "kind": "NON_NULL"
          }
        },
        {
          "name": "friends",
          "type": {
            "name": null,
            "kind": "LIST"
          }
        },
        {
          "name": "friendsConnection",
          "type": {
            "name": null,
            "kind": "NON_NULL"
          }
        },
        {
          "name": "appearsIn",
          "type": {
            "name": null,
            "kind": "NON_NULL"
          }
        },
        {
          "name": "primaryFunction",
          "type": {
            "name": "String",
            "kind": "SCALAR"
          }
        }
      ]
    }
  }
}

* 접은 글을 펼치면 예시 결과를 확인할 수 있습니다.

 

결과를 확인해 보면 "NON_NULL" 타입의 경우 "name"에 null인 것을 확인할 수 있습니다. 종류가 "NON_NULL"인 wrapper 타입으로 인식하기 때문입니다.

비슷하게, friends와 appearIn 둘 다 LIST wrapper 타입이기 때문에 이름이 없습니다. 이 타입에 대해 ofType을 쿼리 할 수 있습니다. 그러면 이 list 가 어떤 list 인지 알 수 있습니다.

 

{
  __type(name: "Droid") {
    name
    fields {
      name
      type {
        name
        kind
        ofType {
          name
          kind
        }
      }
    }
  }
}
더보기

{
  "data": {
    "__type": {
      "name": "Droid",
      "fields": [
        {
          "name": "id",
          "type": {
            "name": null,
            "kind": "NON_NULL",
            "ofType": {
              "name": "ID",
              "kind": "SCALAR"
            }
          }
        },
        {
          "name": "name",
          "type": {
            "name": null,
            "kind": "NON_NULL",
            "ofType": {
              "name": "String",
              "kind": "SCALAR"
            }
          }
        },
        {
          "name": "friends",
          "type": {
            "name": null,
            "kind": "LIST",
            "ofType": {
              "name": "Character",
              "kind": "INTERFACE"
            }
          }
        },
        {
          "name": "friendsConnection",
          "type": {
            "name": null,
            "kind": "NON_NULL",
            "ofType": {
              "name": "FriendsConnection",
              "kind": "OBJECT"
            }
          }
        },
        {
          "name": "appearsIn",
          "type": {
            "name": null,
            "kind": "NON_NULL",
            "ofType": {
              "name": null,
              "kind": "LIST"
            }
          }
        },
        {
          "name": "primaryFunction",
          "type": {
            "name": "String",
            "kind": "SCALAR",
            "ofType": null
          }
        }
      ]
    }
  }
}

* 접은 글을 펼치면 예시 결과를 확인할 수 있습니다.

 

 

 

 

 

References

GraphQL에 대해 알아보는 글을 포스팅합니다. 이 글에선 Graphql에 대한 기본적인 소개와 REST API와의 비교를 통한 차이점을 알아보도록 합니다.

 

 

 

1. 소개

 

 

GraphQL은 페이스북에서 만든 쿼리 언어입니다. GrpahQL은 JavaScript 개발 환경에서 Data Layer와 관련하여 항상 언급되는 주제입니다만, 현재를 기준으로 아직 성숙한 쿼리 언어라곤 할 수 없습니다. 하지만 등장한 지 얼마 되지 않았음에도 불구하고, GraphQL의 인지도와 인기는 매우 빠르게 상승하고 있음을 확인할 수 있습니다.

 

JS - DataLayer 인지도, 관심도, 만족도 순위

 

GraphQL 설문 응답 자료

 

Graph QL(이하 gql)은 Structed Query Language(이하 sql)와 마찬가지로 쿼리 언어입니다. 하지만 gql과 sql의 언어적 구조 차이는 매우 큽니다. 또한 gql과 sql이 실전에서 쓰이는 방식의 차이도 매우 큽니다. 

gql과 sql의 언어적 구조 차이가 활용 측면에서의 차이를 가져왔습니다. 이 둘은 애초에 탄생 시기도 다르고 배경도 다릅니다. 

sql은 데이터베이스 시스템에 저장된 데이터를 효율적으로 가져오는 것이 목적이고, gql은 웹 클라이언트가 데이터를 서버로부터 효율적으로 가져오는 것이 목적입니다. sql의 문장(statement)은 주로 백앤드 시스템에서 작성하고 호출하는 반면, gql의 문장은 주로 클라이언트 시스템에서 작성하고 호출합니다.

 

sql 쿼리 예시

SELECT USER_EMAIL, USER_NAME FROM USERS WHERE USER_KEY = 1;

 

gql 쿼리 예시

query{
    users(user_key: "1"){
        user_email
        user_name
    }
}

 

서버사이드 gql 애플리케이션은 gql로 작성된 쿼리를 입력으로 받아 쿼리를 처리한 결과를 다시 클라이언트로 돌려줍니다. 

HTTP API 자체가 특정 데이터베이스나 플랫폼에 종속적이지 않은것 처럼 마찬가지로 gql 역시 어떠한 특정 데이터베이스나 플렛폼에 종속적이지 않습니다. 심지어 네트워크 방식에도 종속적이지 않습니다. 

일반적으로 gql의 인터페이스 간 송수신은 네트워크 레이어 L7의 HTTP POST 메서드와 웹소켓 프로토콜을 활용합니다. 필요에 따라서는 얼마든지 L4의 TCP/UDP를 활용하거나 심지어 L2 형식의 이더넷 프레임을 활용할 수도 있습니다.

 

gql 파이프 라인

 

 

 

2. GraphQL과 REST API

 

기존의 웹 혹은 모바일 애플리케이션의 API 를 구현할 때는, 통상적으로 REST API 가 사용됩니다.

기존의 REST API 를 사용하여 API를 구현을 한다면 우리가 클라이언트 사이드에서 어떠한 기능이 필요할 때마다 그때그때 새로운 API를 만들어야 했습니다.

문제는 나중에 어플리케이션의 규모가 커지면 수많은 Endpoint가 생성되게 됩니다. REST API는 URL, METHOD 등을 조합하기 때문에 다양한 Endpoint가 존재하게 되는 것입니다. 

 

일반적인 HTTP API 적용 스택

 

반면, gql은 단 하나의 Endpoint가 존재합니다. 또한, gql API에서는 불러오는 데이터의 종류를 쿼리 조합을 통해서 결정합니다.

예를 들면, REST API에서는 각 Endpoint마다 데이터베이스 SQL 쿼리가 달라지는 반면, gql API는 gql 스키마의 타입마다 데이터베이스 SQL 쿼리가 달라집니다.

 

GraphQL 적용 스택

 

아래의 그림과 같이 gql API를 사용하면 여러 번 네트워크 호출을 할 필요 없이, 한 번의 네트워크 호출로 처리할 수 있습니다.

 

REST API와 GraphQL API 사용의 차이점

 

 

 

 

 

 

* References

 

 

 

SqlDeveloper에서 DATE 타입 컬럼 조회 시 시간까지 나오도록 하는 방법에 대해 알아봅니다.

 

 

 

1. 기본 조회 방식

 

SqlDeveloper에서 DATE 타입을 조회하면 기본값으로 년-월-일만 노출시켜줍니다.

등록된 시간까지 알고싶다면 직접 설정에 가서 조회 포맷을 변경시켜야 합니다.

 

 

 

2. 조회 포맷 수정

 

도구 > 환경설정으로 이동해서 수정해 봅시다.

 

환경설정에서 데이터베이스 > NLS > 날짜 형식을 다음과 같이 수정합니다.

 

YYYY/MM/DD HH24:MI:SS (해당 포맷은 원하는 대로 변경하셔도 됩니다.)

 

 

 

3. 수정된 포맷으로 조회하기

 

이제 다시 DATE 타입의 컬럼을 조회하면 다음과 같이 시간까지 보이는 것을 확인할 수 있습니다.

 

 

 

 

이 글은 "Container Registries You Might Have Missed"을 번역한 글 입니다.

 

 

 

 

1. Intro

 

레지스트리는 주로 Docker와 같은 컨테이너 작업을 수행하는데에 있어서 주요 구성 요소 중 하나이므로 대중들에게 매력적입니다. 

 

레지스트리는 컨테이너 엔진의 호스트에서 다운로드되고 실행되는 이미지를 호스팅합니다. 컨테이너는 단순히 특정 이미지가 실행중인 인스턴스입니다. 이미지는 Microsoft Windows의 MSI 또는 Red Hat Enterprise Linux의 RPM과 같이 바로 사용할 수있는 패키지로 생각하면 됩니다.

 

여기서는 레지스트리가 어떻게 작동하는지 자세히 설명하지 않겠지만 더 자세히 알고 싶다면 이 기사를 읽어 보세요. 그 대신 제가 이 글에서 하고 싶은 것은 여전히 레이더 아래에 남아있는 몇몇의 컨테이너 레지스트리를 강조하는것 입니다. 

 

널리 알려진 이름의 레지스트리는 Docker를 사용하는 대부분의 사람들에게 이미 익숙하지만 이미지를 호스팅 할 위치를 결정할 때 고려해야 할 가치가 있는 작은 레지스트리도 있습니다. 

 

잘 알려지지 않은 컨테이너 레지스트리에 대한 설명은 계속 읽으시면 됩니다.

 

 

 

2. 잘 알려진 레지스트리들

 

먼저 잘 알려진 레지스트리를 식별해 잘 알려지지 않은 레지스트리와 비교할 내용을 명확히 하겠습니다.

 

현재 모든 계정에서 가장 인기있는 레지스트리는 Docker Hub입니다. Docker Hub는 알려진 레지스트리 세계의 중심입니다. 이건 모든 Docker 설치가 참조하도록 구성된 기본 호스팅 된 레지스트리입니다. 

 

그 외의 다른 임기 있는 레지스트리는 다음과 같습니다:

 

 

 

3. 당신이 놓치고 있을지도 모르는 레지스트리들

 

이제 흥미로운 부분으로 넘어 갑니다. 덜 알려진 레지스트리의 개요는 다음과 같습니다.

  • Amazon EC2 Container Registry (ECR)
  • FlawCheck Private Registry
  • GitLab Container Registry
  • Portus by SUSE
  • Sonatype Nexus
  • VMware Harbor Registry

 

3.1. 아마존 EC2 컨테이너 레지스트리(ECR)

 


아마존이 Amazon EC2 Container Service (ECS)라는 호스트 된 컨테이너 서비스를 제공한다는 것을 이미 알고 있을겁니다. 그러나 아마존이 ECS를 완성하기 위해 제공하는 레지스트리는 덜 관심을받는 경향이 있습니다. 

 

Amazon EC2 Container Registry (ECR)라고 불리는 레지스트리이며 호스트 된 Docker 컨테이너 레지스트리입니다. ECR은 ECS와 통합됩니다. 

 

2015 년 12 월에 도입 된이 솔루션은 잘 알려진 대부분의 레지스트리보다 새로운 레지스트리 옵션으로인해  일부 사용자에게 익숙하지 않다고 설명합니다. 

 

ECS는 ECR과 호환되는 유일한 컨테이너 레지스트리가 아닙니다. ECS는 외부 레지스트리도 지원합니다. 그러나 ECR의 주요 이점은 완전히 호스트 되고 관리되는 레지스트리이므로 배포 및 관리가 간단하다는점 입니다. 또한 ECR은 다른 ECS 인프라만큼 확장 가능하므로 확장성이 매우 뛰어납니다. 

 

최고의 사용 사례는 다음과 같습니다: AWS 서비스를 많이 사용하거나 사용할 계획을 갖고 있으며 개인 이미지를 호스팅 할 장소를 찾고 있다면 ECR을 사용하는 것이 좋습니다. 대규모 레지스트리 배포가 있거나 시간이 지남에 따라 레지스트리가 크게 확장 될 것으로 예상되는 경우에도 좋은 선택입니다. 이 경우 사실상 제한없이 ECR을 확장할 수 있습니다.

 

 

 

3.2. FlawCheck Private Registry

 

 

FlawCheck Private Registry (보안 업체 Tenable이 FlawCheck의 나머지 비즈니스와 함께 최근에 인수 함)는 보안을 중점으로 한 레지스트리 옵션입니다.

 

이 레지스트리는 컨테이너 이미지에 대한 통합 취약성 검색 및 말웨어 탐지 기능을 제공합니다. 컨테이너 이미지에 악성 코드가 없어지게 하거나 레지스트리에 악성 이미지가 삽입되는 것을 막는 만능 도구는은 아니지만 FlawCheck의 스캔 기능은 위험을 줄이는데 도움이 될 수 있습니다.

 

최상의 사용 사례는 다음과 같습니다: 보안에 민감한 회사의 경우이 방법이 정말 좋습니다. 규제가 심한 산업에서는 이 레지스트리를 많이 채택 할 것으로 예상됩니다.

 

 

 

3.3. GitLab Container Registry

 


호스트 또는 온-프레미스 레지스트리로 실행할 수있는 GitLab Container Registry는 컨테이너 이미지 호스팅을위한 GitLab의 솔루션입니다. GitLab에 내장되어 있으며 나머지 GitLab의 도구들과 완벽하게 호환되므로 GitLab 딜리버르 파이프 라인에 직접 통합 될수도 있습니다. 

 

팀이 가능한 한 적은 움직이는 부품으로 완벽한 DevOps 워크 플로우를 탐색하고 있다면 이를 채택하는것이 좋습니다. 

 

최상의 사용 사례는 다음과 같습니다: 일부 개발자는 Docker 이미지를 소스 코드와 동일한 플랫폼에 저장하는 것이 편리하다는 것을 알게 될 것입니다. 소스 코드에 GitLab을 사용한다면 GitLab Container Registry가 유용 합니다. 그러나 GitLab Container Registry는 대부분의 다른 레지스트리에서 사용할 수없는 킬러 기능을 제공하지 않습니다.

 

 

 

3.4. SUSE의 Portus

 


Portus는 기술적으로 레지스트리는 아니지만 Docker Registry의 온-프레미스 배포를 위해 기본 UI를 대체하는 프런트 엔드를 제공합니다. 

 

Portus는 추가 액세스 제어 옵션을 제공하여 Docker Registry에 가치를 더하도록 설계되었습니다. 여기에는 팀 또는 레지스트리 사용자를 서로 다른 액세스 수준을 설정하여 구성하는 기능이 포함됩니다.(여러 가지면에서이 기능은 Unix 계열 시스템의 사용자 그룹과 유사합니다.) 

 

또한 Portus는 레지스트리 네임스페이스를 제공해 팀의 사용자 뿐 아니라 개인 사용자에게 다른 저장소에 대해 세부적으로 수행할 수 있는 수정 유형 구성을 만드는것을 가능하게 합니다. 

 

그리고 Portus는 레지스트리 설정 및 액세스 제어를 구성 할 수있는 사용자 친화적 인 웹 인터페이스를 제공합니다. CLI 구성 도구 인 portusctl도 사용 가능합니다. 

 

최상의 사용 사례는 다음과 같습니다: Docker Registry를 좋아하지만 추가 보안 제어가 필요하거나 세분화 된 액세스 제어를 사용해야하는 이유가있는 경우 Portus는 강력한 솔루션입니다.

 

 

 

3.5. Sonatype Nexus

 


호스트 및 온-프레미스 배포를 지원하는 Sonatype Nexus는 범용 리포지토리입니다. 이는 Docker 이미지 호스팅보다 훨씬 많은 것을 지원하지만 Docker 레지스트리로도 사용될 수 있습니다. 

 

Docker보다 훨씬 오래 되었으며 이전에 컨테이너 레지스트리를 사용하지 않았더라도 노련한 관리자에게는 익숙 할 것입니다. 

 

핵심 Nexus 플랫폼은 오픈 소스이지만 상용 옵션 또한 제공됩니다. 

 

최상의 사용 사례는 다음과 같습니다: 많은 회사에서 Nexus를 Maven의 저장소로 몇 년 동안 배포해 왔습니다. 플랫폼의 최신 릴리스로 업그레이드하기 만하면 조직에서 Docker 이미지 호스팅을 추가하여 새로운 제품에 대한 개발 또는 운영 직원을 교육하지 않고도 자체 Docker 레지스트리를 만들 수 있습니다. 또한 Docker 이미지와 함께 다른 유형의 제작물를 호스팅 할 수 있습니다.

 

 

 

3.6. VMware Harbor Registry

 

 

Docker 생태계에서 VMware를 주요 플레이어로 생각하지는 않지만 이 회사는 확실히 새로운 시도를 하고 있습니다. Harbor Registry는 Docker 이미지 호스팅에 대한 VMware의 결과입니다. 

 

이 레지스트리는 Docker Distribution을 기반으로 구축되었지만 보안 및 ID 관리 기능을 추가하였습니다. 또한 단일 호스트에서 여러 레지스트리를 지원합니다. 

 

최상의 사용 사례는 다음과 같습니다: Harbour는 보안 및 사용자 관리에 중점을두고 있기 때문에 이 옵션은 기업이 추구하는 중요한 레지스트리 기능을 제공하며 이 기능은 다른 모든 레지스트리에서 사용할 수 있는것은 아닙니다. 이는 기업에서 좋은 선택입니다. 

 

Harbor는 Docker 컨테이너로 실행되기 때문에 Docker 환경이있는 모든 서버에 쉽게 설치할 수 있으며 개발자에게 오프라인 설치 프로그램을 제공하기 때문에 보안 고려 사항 또는 기타 요인이있는 상황(공용 인터넷에 연결할 수 없는 경우을 의미합니다.)에서 유용 할 수 있습니다.

 

 

 

4. Conclusion

 

서로 다른 레지스트리 오퍼링 사이의 주요 변수에는 지원하는 배포 환경 유형 (호스트, 온 프레미스 또는 둘 다)이 포함됩니다. 액세스 제어 옵션을 얼마나 미세하게 조정했는지; 컨테이너 레지스트리에 대한 추가 보안 수준. 

 

물론 필요에 맞는 레지스트리를 선택하는 것은 이러한 기능이 우선 순위에 어떻게 부합하는지에 달려 있습니다. 그러나 선택의 폭이 넓기 때문에 특정 조직의 요구에 완벽한 균형을 제공하는 레지스트리를 찾는 것은 어렵지 않을겁니다.

 

 

 

 

 

 

 

 

 

 

Redmin에 LDAP 인증을 추가해 계정관리를 해봅니다.

 

 

 

1. Redmine 및 OpenLDAP 준비

 

미리 Redmine과 OpenLDAP 서버를 준비합니다.

 

Redmine은 Docker를 이용하면 매우 간편하게 설치할 수 있습니다.

 

LDAP 서버를 설치하는 방법은 여기를 참고해 주시기 바랍니다.

 

 

 

2. LDAP 설정

 

Redmine에 들어가 설정 > LDAP 인증 > 새 인증 공급자를 눌러줍니다.

 

 

차근차근 채워봅시다.

 

  • 이름: 이 LDAP 인증 공급자의 이름입니다.
  • 호스트: LDAP 인증 서버의 호스트를 적습니다.
  • 포트: LDAP 인증 서버의 LDAP 포트를 적습니다.
  • LDAPS: 보안 프로토콜 사용 여부를 선택합니다.
  • 계정: LDAP 인증 공급자의 계정을 입력합니다.
  • 비밀번호: 위 계정의 암호를 입력합니다.
  • 기본 DN: LDAP의 BaseDN을 입력합니다.
  • LDAP 필터: 비워둡니다.
  • 타임아웃: 타임아웃 시간을 설정합니다
  • 동적 사용자 생성: Redmine에서 LDAP를 이용하기 위해 체크합니다.
  • 로그인 속성: 로그인 id로 사용될 LDAP의 타입입니다.
  • 이름 속성: 이름으로 보일 LDAP의 타입입니다.
  • 성 속성: 성으로 보여질 LDAP의 타입입니다.
  • 메일 속성: 메일로 보여질 LDAP의 타입입니다.

위와 같은 내용으로 다음과 같이 채워줍니다.

 

 

저장 후 테스트를 진행해 봅니다.

 

 

연결 성공 메시지가 보이면 제대로 설정된 것입니다.

 

 

 

3. 유저 생성하기

 

LDAPAdmin을 통해 LDAP로 접속해 유저를 생성합니다.

 

기본적으로 로그인하면 다음과 같은 화면을 확인할 수 있습니다.

 

 

홈 > 우클릭 > New > Organizational unit을 클릭해 새 조직을 생성합니다.

 

새로 생성한 조직을 우클릭한 후 New > User를 선택해 새 유저를 생성합니다.

 

 

다음과 같이 유저 정보를 입력해 줍니다.

 

이제 생성한 유저의 비밀번호를 설정해 줍시다.

 

생성한 유저 우클릭 > Set Password를 클릭한 후 암호를 설정해 저장합니다.

 

 

 

 

4. Redmin 로그인하기

 

이제 생성한 유저로 Redmine에서 로그인을 시도해 봅시다.

 

 

Set Password에서 입력한 비밀번호를 넣어주면

 

 

정상적으로 로그인 되는것을 확인할 수 있습니다.

 

 

 

 

 

 

윈격 접속을 위해 Putty를 쓰는데 vi 에디터에서 주석 처리된 글이 진짜 하나도 안 보인다.

 

 

좀 읽을 수 있도록 폰트의 컬러를 변경해 봅니다.

 

폰트 컬러 설정은 다음과 같이 설정 > Wondow > Colours에서 변경할 수 있습니다.

 

 

가장 안보였던 ANSI Blue를 찾아 RGB를 (100, 100, 255)로 변경해줬습니다.

 

 

그리고 Apply를 눌러 적용해주면 

 

 

이제 글이 제대로 보입니다.

 

 

 

 

 

이 글은 Janelle WongAtomic Design Pattern: How to structure your React application를 번역한 글입니다.

 

 

 

리액트에서 애플리케이션을 확장해 나감에 따라 종종 컴포넌트 구조의 복잡도가 올라가는 것을 관리하는 것에 대한 어려움에 직면합니다. 필자가 이 포스트에서 빼버리고 싶은 것은 왜 전형적인 디자인 패턴(아토믹 디자인)을 구현하는 것이 애플리케이션 코드의 가독성, 확장성, 유연성에 중요한지 이해하는 것입니다. 아토믹 디자인 패턴은 리액트 컴포넌트 특징에 있어서 대단히 적합하다고 증명되었습니다.

 

 

 

Atomic Design

Brad Frost 와 Dave Olsen에 의해 개발된 아토믹 디자인은 다섯 가지 기초 블록으로 시스템 설계를 만들기 위한 방법론이며 이 블록을 합치면 일관성, 모듈성, 확장성을 촉진시킵니다. 이글에서는 이러한 원리들이 어떻게 React에서 인터페이스를 만들 때 자연스럽게 적합한지, 그리고 추상적 생태계 안에서 동적 수명주기의 컴포넌트를 매핑할 수 있는 것과 같이 어떻게 아토믹 은유(Atomic metaphor)를 유용한 방법으로 확장하는지에 대해 알아보겠습니다.

 

 

 

Atomic Development

아토믹 디자인은 다섯개의 레벨로 구분되어 있으며 React의 컴포넌트 기반 구조에 놀라울 정도로 잘 매핑됩니다. - 원자(Atoms) > 분자(Molcules) > 유기체(Organisms) > 탬플릿(Templates) > 페이지(Pages)

 

 

  • 원자: 버튼, 인풋, 폼라벨 등과 같은 기본적인 블록입니다. 그 자체로는 유용하지 않습니다.
  • 분자: 버튼, 인풋, 폼라벨을 묶어 기능을 만드는 것과 같이 원자 아이템을 그룹화합니다.
  • 유기체: 분자를 묶어 네비게이션 바와 같은 인터페이스에서 구분되는 부분인 유기체를 만듭니다. 
  • 탬플릿: 페이지는 주로 유기체의 그룹으로 구성되며 클라이언트가 볼 수 있는 최종 디자인입니다.
  • 페이지: 다른 템플릿의 렌더를 보는 생태계 입니다. 단일 환경(애플리케이션)에 여러 생태계 생성할 수 있습니다.

 

 

 

File Structure

리액트가 컴포넌트 기반의 구조기 때문에 컴포넌트를 기능보다 유형에 따라 구성하는 것은 꽤 일반적입니다. 만약 각각의 컴포넌트 기능에 대해 하위 생태계를 만들고 싶다면 어떻게 해야 할까요?

 

 

각각의 컴포넌트나 서비스는 자신의 인스턴스가 동작하는데 필요한 모든 것이 포함된 독립된 환경을 갖습니다. 각각의 컴포넌트, 버튼, 폼은 앱에서 독립된 요소들과 같이 동작하는 자신들의 스타일, 액션, 단위 또는 통합 테스트를 갖고 있으며 이미지나 다른 로컬 변수를 추가할 수도 있습니다. 이것은 효율적이고 일관적이며 코드 테스트를 더 쉽게 만들고 노력을 줄여줍니다.


이런 유형의 조직은 한 컴포넌트 안에 다른 컴포넌트를 중첩시킬 수 있습니다. 만약 /Delete, /Submit, /Login 또는 /Register 내부에 새 컴포넌트를 정의한다면 내부의 컴포넌트는 사촌 컴포넌트는 사용이 불가하며 바로 위의 부모 컴포넌트만 사용할 수 있습니다. 

 

 

 

왜 이런 걸 하나요?

React 파일 구조를 조직할 때 아토믹 디자인 패턴을 따르는 주요한 목적은 각각의 컴포넌트를 독립된 환경에 두는 것입니다. 부작용이 독립되어 있을 때 코드는 더 읽기 쉬워지고 모듈화 됩니다. 기능의 단일 인스턴스 테스트는 좀 더 직관적이 될 것이고 그러면 애플리케이션의 전체 품질 보증이 향상됩니다. 애플리케이션의 상태 관리의 복잡도가 증가함에 따라 이런 패턴의 파일 구조는 상태를 확인하고 다루는 데 있어서 도움이 될 것입니다.

 

 

 

아래에 정보를 얻기에 좋은 자료가 있습니다.

 

 

 

+ Recent posts