Go 언어의 의존성 관리

Go 언어는 의존성 관리에 있어서 아티팩트 기반이 아닌 소스 기반의 독특한 방법을 채택합니다. 아티팩트 기반의 의존성 관리 시스템에서 패키지는 소스 코드에서 생성된 아티팩트로 이루어져 있으며, 소스 코드와는 별도의 저장소 시스템에 저장됩니다. 예를 들어, 많은 NodeJS 패키지는 패키지 저장소로 npmjs.org를 사용하고 소스 저장소로 github.com을 사용합니다. 반면 Go 언어의 패키지는 소스 코드 자체이며, 패키지 릴리스는 아티팩트 생성이나 별도의 저장소가 필요하지 않습니다. Go 패키지는 버전 관리 저장소(VCS)에 저장되어야 합니다. 의존성은 해당 VCS 서버에서 직접 가져오거나 중간 프록시를 통해 가져와야 합니다.

버전 관리

Go 1.11에서 모듈과 Go 생태계에 대한 일급 패키지 버전 관리가 소개되었습니다. 이전에는 Go에는 버전 관리를 위한 명확한 메커니즘이 없었습니다. 3rd 파티 버전 관리 도구가 존재했지만, 기본 Go 환경에서는 버전 관리를 지원하지 않았습니다.

Go 모듈은 의미 있는 버전을 사용합니다. 모듈의 버전은 v로 접두어가 붙은 유효한 의미 있는 버전 컨트롤 시스템(VCS) 태그로 정의됩니다. 예를 들어, gitlab.com/my/project1.0.0 버전을 릴리스하기 위해서는 개발자가 v1.0.0 Git 태그를 만들어야 합니다.

0과 1 이외의 주요 버전의 경우, 모듈 이름에는 반드시 /vX가 접미사로 붙어야 합니다. 예를 들어, gitlab.com/my/projectv2.0.0 버전은 gitlab.com/my/project/v2로 명명되고 가져와집니다.

Go는 특정 VCS 커밋을 참조하는 특별한 의미 있는 버전인 ‘의사 버전’을 사용합니다. 의미 있는 버전의 사전 릴리스 구성 요소는 타임스탬프와 커밋 식별자의 처음 12자여야 합니다.

  • X에 대한 이전 태그 커밋이 존재하지 않을 때: vX.0.0-yyyymmddhhmmss-abcdefabcdef
  • 최근 이전 태그가 vX.Y.Z-pre인 경우: vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef
  • 최근 이전 태그가 vX.Y.Z인 경우: vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef

VCS 태그가 이러한 패턴 중 하나와 일치하는 경우, 무시됩니다.

Go 모듈 및 버전 관리에 대한 자세한 내용은 공식 Go 웹사이트의 블로그 포스트 시리즈를 참조하십시오.

‘모듈’ 대 ‘패키지’

  • 패키지는 *.go 파일을 포함하는 폴더입니다.
  • 모듈은 go.mod 파일을 포함하는 폴더입니다.
  • 모듈은 대개 go.mod 파일과 *.go 파일을 포함하는 패키지이기도 합니다.
  • 모듈에는 하위 디렉토리가 있을 수 있으며, 해당 디렉토리는 패키지일 수 있습니다.
  • 모듈은 일반적으로 VCS 저장소(Git, SVN, Hg 등) 형태로 제공됩니다.
  • 모듈의 하위 디렉토리 중에서 모듈인 경우, 해당 하위 디렉토리는 별도의 모듈로 간주되며 포함되는 모듈에서 제외됩니다.
    • 모듈 repo가 있다면, repo/subgo.mod 파일이 있는 경우, repo/sub 및 해당 파일은 별도의 모듈로 간주되어 repo에 속하지 않습니다.

명명

표준 라이브러리를 제외한 모듈이나 패키지의 이름은 (sub.)*domain.tld(/path)* 형식이어야 합니다. 이는 URL과 유사하지만 URL은 아닙니다. 패키지 이름에는 https://와 같은 스킴이 없으며 포트 번호가 있어서는 안 됩니다. example.com:8443/my/package는 유효한 이름이 아닙니다.

패키지 가져오기

Go 1.12 이전에는 패키지를 가져오는 과정은 다음과 같았습니다:

  1. https://{package name}?go-get=1을 조회합니다.
  2. 응답에서 go-import 메타 태그를 찾습니다.
  3. 메타 태그에서 지정된 VCS를 사용하여 지정된 저장소를 가져옵니다.

메타 태그는 <meta name="go-import" content="{prefix} {vcs} {url}"> 형식을 취해야 합니다. 예를 들어, gitlab.com/my/project git https://gitlab.com/my/project.gitgitlab.com/my/project로 시작하는 패키지를 https://gitlab.com/my/project.git에서 Git을 사용하여 가져와야 함을 나타냅니다.

모듈 가져오기

Go 1.12에서는 체크섬 데이터베이스와 모듈 프록시가 도입되었습니다.

체크섬

go.mod 외에 모듈은 go.sum 파일을 가집니다. 이 파일은 모듈이나 모듈의 종속성 중 하나에서 참조하는 모든 버전의 코드와 go.mod 파일의 SHA-256 체크섬을 기록합니다. Go는 새로운 종속성이 참조될 때마다 go.sum을 계속해서 업데이트합니다.

Go가 모듈의 종속성을 가져올 때, 이러한 종속성이 이미 go.sum에 기록되어 있는 경우, Go는 이러한 종속성의 체크섬을 확인합니다. 체크섬이 go.sum에 있는 것과 일치하지 않으면 빌드가 실패합니다. 이를 통해 모듈의 특정 버전이 개발자나 악의적인 당사자에 의해 변경될 수 없도록 보장합니다.

Go 1.12+는 체크섬 데이터베이스를 사용하도록 구성할 수 있습니다. 이렇게 구성된 경우, Go는 종속성을 가져올 때 go.sum에 해당 항목이 없는 경우, 다운로드된 종속성에서 계산하는 대신 설정된 체크섬 데이터베이스에서 종속성의 체크섬을 질의합니다. 종속성이 체크섬 데이터베이스에서 찾을 수 없는 경우, 빌드가 실패합니다. 다운로드된 종속성의 체크섬이 체크섬 데이터베이스의 결과와 일치하지 않는 경우 빌드가 실패합니다. 이를 제어하는 환경 변수는 다음과 같습니다:

  • GOSUMDB는 체크섬 데이터베이스의 이름 및 선택적으로 공개 키 및 서버 URL을 식별합니다.
    • 값이 off이면 체크섬 데이터베이스 질의를 완전히 비활성화합니다.
    • Go 1.13+에서 GOSUMDB가 정의되지 않은 경우, sum.golang.org를 사용합니다.
  • GONOSUMDB는 체크섬 데이터베이스 질의가 비활성화되어야 하는 모듈 접미사의 쉼표로 구분된 목록을 나타냅니다. 와일드카드가 지원됩니다.
  • GOPRIVATE는 모듈 이름을 나타내는 쉼표로 구분된 목록을 통해 GONOSUMDB와 같은 기능 외에도 다른 기능을 비활성화합니다.

프록시

Go 1.12+는 모듈의 VCS에서 직접 가져오는 대신 Go 프록시에서 모듈을 가져오도록 구성할 수 있습니다. 이렇게 구성된 경우 Go가 종속성을 가져올 때 구성된 프록시에서 순서대로 종속성을 가져오려고 시도합니다. 다음 환경 변수들이 이를 제어합니다.

  • GOPROXY는 조회할 모듈 프록시의 쉼표로 구분된 목록입니다.
    • direct값은 모듈 프록시 조회를 완전히 비활성화합니다.
    • 목록의 마지막 항목이 direct인 경우, 프록시가 종속성을 제공하지 못하는 경우 Go는 위에서 설명한 프로세스로 되돌아갑니다.
    • GOPROXY가 정의되지 않은 경우 Go 1.13+는 proxy.golang.org,direct를 사용합니다.
  • GONOPROXY는 프록시에서 가져오지 않고 직접 가져와야 하는 모듈 접미사의 쉼표로 구분된 목록입니다. 와일드카드가 지원됩니다.
  • GOPRIVATEGONOPROXY와 동일한 기능을 하는 모듈 이름의 쉼표로 구분된 목록입니다.

가져오기

Go 1.12부터 모듈 또는 패키지를 가져오는 프로세스는 다음과 같습니다.

  1. GOPROXY가 프록시 목록이며 모듈이 GONOPROXY 또는 GOPRIVATE로 제외되지 않은 경우, 순서대로 조회하고 첫 번째 유효한 응답에서 중지합니다.
  2. GOPROXYdirect이거나 모듈이 제외되었거나, GOPROXY,direct로 끝나고 프록시가 모듈을 제공하지 않은 경우, 회귀합니다.
    1. https://{module 또는 package name}?go-get=1을 조회합니다.
    2. go-import 메타 태그를 위해 응답을 스캔합니다.
    3. 메타 태그에서 지정된 VCS를 사용하여 지시된 리포지토리를 가져옵니다.
    4. {vcs} 필드가 mod인 경우 URL은 VCS가 아닌 모듈 프록시로 취급되어야 합니다.
  3. 모듈이 직접적으로 가져오고 종속성이 아닌 경우 중지합니다.
  4. go.sum에 해당 모듈 항목이 있는 경우 체크섬을 확인한 후 중지합니다.
  5. GOSUMDB가 체크섬 데이터베이스를 식별하고 모듈이 GONOSUMDB 또는 GOPRIVATE에 의해 제외되지 않은 경우, 모듈의 체크섬을 검색하여 go.sum에 추가하고 다운로드한 소스를 확인합니다.
  6. GOSUMDBoff이거나 모듈이 제외된 경우, 다운로드한 소스에서 체크섬을 계산하고 go.sum에 추가합니다.

다운로드한 소스는 go.mod 파일을 포함해야 합니다. go.mod 파일은 모듈의 이름을 지정하는 module 지시문을 포함해야 합니다. go.mod에서 지정된 모듈 이름이 모듈을 가져오는 데 사용된 이름과 일치하지 않으면 모듈은 컴파일에 실패합니다.

모듈이 직접적으로 가져오되 버전이 지정되지 않은 경우나 종속성으로 추가되고 버전이 지정되지 않은 경우, Go는 모듈의 가장 최근 버전을 사용합니다. 모듈이 프록시에서 가져온 경우, Go는 프록시에게 버전 목록을 요청하고 최신 버전을 선택합니다. 모듈이 직접적으로 가져온 경우, Go는 저장소에 태그 목록을 요청하고 유효한 세맨틱 버전인 최신 버전을 선택합니다.

인증

Go 1.13 이전의 버전에서 Go가 수행하는 요청의 인증을 지원하는 것은 다소 일관성이 없었습니다. Go 1.13에서는 .netrc 인증의 지원이 향상되었습니다. HTTPS를 통해 요청을 보내고 일치하는 .netrc 항목을 찾을 수 있는 경우, Go는 요청에 HTTP 기본 인증 자격 증명을 추가합니다. Go는 HTTP를 통해 생성된 요청인 경우에는 인증을 수행하지 않습니다. 또한, GOPROXY에서 내장 자격 증명이 포함된 HTTP-only 항목을 거부합니다.

향후 버전에서 Go는 임의의 인증 헤더를 지원할 수 있습니다. 자세한 내용은 golang/go#26232를 참조하세요.