Go의 의존성 관리

Go는 의존성 관리에서 아티팩트 기반 대신 소스 기반의 독특한 접근을 취합니다. 아티팩트 기반의 의존성 관리 시스템에서 패키지는 소스 코드에서 생성된 아티팩트로 구성되어 소스 코드와 별도의 저장소 시스템에 저장됩니다. 예를 들어 많은 NodeJS 패키지는 패키지 저장소로 npmjs.org를 사용하고 소스 저장소로 github.com을 사용합니다. 그러나 Go의 패키지는 소스 코드이며, 패키지 릴리스에는 아티팩트 생성이나 별도의 저장소가 필요하지 않습니다. Go 패키지는 반드시 VCS 서버의 버전 관리 저장소에 저장되어야 합니다. 의존성은 VCS 서버에서 직접 또는 VCS 서버로부터 가져오는 중간 프록시를 통해 가져올 수 있습니다.

버전 관리

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

Go 모듈은 의미론적 버전을 사용합니다. 모듈의 버전은 VCS(버전 관리 시스템) 태그로 정의되며 v로 접두어가 붙은 유효한 의미론적 버전입니다. 예를 들어 gitlab.com/my/project의 버전 1.0.0을 릴리스하려면 개발자는 Git 태그 v1.0.0을 생성해야 합니다.

0과 1 이외의 주 버전을 위해서는 모듈 이름 뒤에 /vX가 추가되어야 합니다. 예를 들어, gitlab.com/my/project의 버전 v2.0.0gitlab.com/my/project/v2로 명명되고 import되어야 합니다.

Go는 VCS 커밋을 참조하는 특별한 의미론적 버전인 ‘의사 버전’을 사용합니다. 의미론적 버전의 사전 릴리스 구성 요소는 타임스탬프 또는 커밋 식별자의 처음 12자로 끝나거나 끝나야합니다.

  • vX.0.0-yyyymmddhhmmss-abcdefabcdef: X에 대해 더 이상 이전 태그된 커밋이 존재하지 않는 경우.
  • vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef: 가장 최근의 이전 태그가 vX.Y.Z-pre인 경우.
  • vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef: 가장 최근의 이전 태그가 vX.Y.Z인 경우.

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

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

‘Module’ vs ‘Package’

  • 패키지는 *.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로 시작하는 패키지가 Git을 사용하여 https://gitlab.com/my/project.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에 해당 항목이 없는 경우, Go는 다운로드한 종속성의 체크섬을 계산하는 대신 구성된 체크섬 데이터베이스에 대한 체크섬을 쿼리합니다. 종속성이 체크섬 데이터베이스에서 찾을 수 없는 경우 빌드가 실패합니다. 다운로드한 종속성의 체크섬이 체크섬 데이터베이스의 결과와 일치하지 않는 경우 빌드가 실패합니다. 다음 환경 변수가 이를 제어합니다:

  • GOSUMDB는 체크섬 데이터베이스를 쿼리하기 위한 이름 및 옵션으로 공개 키 및 서버 URL을 식별합니다.
    • 값이 off인 경우 체크섬 데이터베이스 쿼리를 완전히 비활성화합니다.
    • Go 1.13+에서는 GOSUMDB가 정의되지 않은 경우 sum.golang.org를 사용합니다.
  • GONOSUMDB는 체크섬 데이터베이스 쿼리가 비활성화될 모듈 접미사의 쉼표로 구분된 목록입니다. 와일드카드를 지원합니다.
  • GOPRIVATE는 다른 기능을 비활성화하는 것 외에도 GONOSUMDB와 동일한 기능을 하는 모듈 이름의 쉼표로 구분된 목록입니다.

프록시

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

  • GOPROXY는 쿼리할 모듈 프록시의 쉼표로 구분된 목록입니다.
    • direct로 설정하면 모듈 프록시 쿼리를 완전히 비활성화합니다.
    • 목록의 마지막 항목이 direct인 경우, 프록시 중 하나도 해당 의존성을 제공할 수 없는 경우, Go는 에 설명된 프로세스로 되돌아갑니다.
    • Go 1.13 이상에서는 GOPROXY가 정의되지 않은 경우 proxy.golang.org,direct를 사용합니다.
  • GONOPROXY는 프록시에서 가져오지 말아야 하는 모듈 접미사의 쉼표로 구분된 목록입니다. 와일드카드가 지원됩니다.
  • GOPRIVATE는 같은 기능을 하는 모듈 이름의 쉼표로 구분된 목록입니다. 추가로 다른 기능을 비활성화합니다.

가져오기

Go 1.12부터 모듈이나 패키지 가져오는 프로세스는 다음과 같습니다:

  1. GOPROXY가 프록시 목록이고 모듈이 GONOPROXYGOPRIVATE에 의해 제외되지 않은 경우, 유효한 응답을 처음으로 발견할 때까지 해당 순서대로 쿼리합니다.
  2. GOPROXYdirect이거나, 모듈이 제외되었거나, GOPROXY,direct로 끝나고 프록시가 해당 모듈을 제공하지 않은 경우, 아래를 따릅니다.
    1. https://{module or package name}?go-get=1을 쿼리합니다.
    2. go-import 메타 태그를 위한 응답을 스캔합니다.
    3. 메타 태그에 표시된 VCS를 사용하여 표시된 저장소를 가져옵니다.
    4. {vcs} 필드가 mod인 경우, URL은 VCS가 아닌 모듈 프록시로 취급되어야 합니다.
  3. 모듈이 직접 가져와져 종속성이 아닌 경우, 그대로 중지합니다.
  4. 만약 go.sum이 모듈에 해당하는 항목을 포함하고 있으면, 체크섬을 유효성 검사하고 중지합니다.
  5. GOSUMDB가 체크섬 데이터베이스를 식별하고 모듈이 GONOSUMDBGOPRIVATE에 의해 제외되지 않은 경우, 모듈의 체크섬을 검색하여 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를 통해 이루어지는 요청에 대해 인증하지 않습니다. Go는 GOPROXY에서 HTTP-only 항목에 포함된 자격 증명을 거부합니다.

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