Go 의존성 관리

Go는 의존성 관리에 대해 이례적인 방식을 취하는데, 이는 패키지와 관련된 아티팩트가 아닌 소스 기반으로 이루어진다는 점이다. 아티팩트 기반 의존성 관리 시스템에서는 패키지가 소스 코드에서 생성된 아티팩트로 구성되며 소스 코드와는 별도의 리포지터리 시스템에 저장된다. 예를 들어, 많은 NodeJS 패키지는 패키지 리포지터리로 npmjs.org을 사용하고 소스 리포지터리로 github.com을 사용한다. 반면, Go의 패키지는 소스 코드이며, 패키지 릴리스는 아티팩트 생성이나 별도의 리포지터리가 관여하지 않는다. Go 패키지는 반드시 VCS 서버에 있는 버전 관리 리포지터리에 저장되어야 한다. 의존성은 VCS 서버에서 직접 가져오거나 중간 프록시를 통해 가져온다.

버전 관리

Go 1.11에서 모듈과 Go 생태계에 대한 첫 번째 클래스 패키지 버전 관리가 도입되었다. 이전에는 Go에는 버전 관리에 대한 명확한 메커니즘이 없었다. 3rd party 버전 관리 도구가 존재했지만, 기본 Go 경험에는 버전 관리를 위한 지원이 없었다.

Go 모듈은 의미 있는 버전를 사용한다. 모듈의 버전은 VCS(버전 관리 시스템) 태그로 정의되며 v로 시작하는 유효한 의미 있는 버전으로 구성된다. 예를 들어, gitlab.com/my/project의 버전 1.0.0을 릴리스하기 위해서는 개발자가 v1.0.0 태그를 생성해야 한다.

0과 1 이외의 주 버전에 대해, 모듈 이름은 반드시 /vX로 끝나야 한다. 예를 들어, gitlab.com/my/project의 버전 v2.0.0gitlab.com/my/project/v2로 명명되고 가져와야 한다.

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 웹사이트의 이 블로그 시리즈를 참조하십시오.

‘모듈’ vs ‘패키지’

  • 패키지는 *.go 파일을 포함하는 폴더이다.
  • 모듈은 go.mod 파일을 포함하는 폴더이다.
  • 모듈은 보통 go.mod 파일과 *.go 파일을 포함하는 패키지이다.
  • 모듈은 서브디렉터리를 가질 수 있으며, 해당 서브디렉터리는 패키지일 수 있다.
  • 모듈은 대개 VCS 리포지터리(Git, SVN, Hg 등) 형태로 제공된다.
  • 모듈의 서브디렉터리 중 모듈인 경우, 해당 모듈은 별도의 모듈로 취급되어 모듈에 포함되지 않는다.
    • 모듈 repo가 주어지면, repo/subgo.mod 파일을 포함하는 경우 repo/sub 및 해당 파일은 별도의 모듈로 취급되어 repo의 일부가 아니다.

명명

표준 라이브러리를 제외한 모듈 또는 패키지의 이름은 일련의 규칙을 따라야 한다. 이는 URL과 유사하지만 URL은 아니다. 패키지 이름에는 https://와 같은 스킴이 없어야 하며 포트 번호가 있어서는 안 된다. example.com:8443/my/package는 유효한 이름이 아니다.

패키지 가져오기

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

  1. https://{package name}?go-get=1을 쿼리한다.
  2. go-import 메타 태그를 위한 응답을 스캔한다.
  3. go-import 메타 태그에 표시된 VCS를 사용하여 메타 태그가 가리키는 리포지터리를 가져온다.

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

모듈 가져오기

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

체크섬

go.mod 외에도 모듈은 go.sum 파일을 가진다. 이 파일은 모듈이나 모듈의 의존성 중 하나가 참조하는 모든 버전의 코드와 go.mod 파일의 SHA-256 체크섬을 기록한다. Go는 새로운 의존성이 참조됨에 따라 지속적으로 go.sum을 업데이트한다.

Go는 모듈의 의존성을 가져올 때, 만약 이러한 의존성에 대한 go.sum 항목이 이미 존재한다면 해당 체크섬을 확인한다. 체크섬이 go.sum에 있는 것과 일치하지 않으면 빌드가 실패한다. 이를 통해 모듈의 특정 버전이 개발자에 의해 또는 악의적인 당사자에 의해 변경될 수 없도록 보장한다.

Go 1.12+는 체크섬 데이터베이스를 사용하도록 구성할 수 있다. 이렇게 구성된 경우 모듈의 의존성을 가져올 때 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는 위에서 설명된 프로세스로 되돌아간다.
    • Go 1.13+에서는 GOPROXY가 정의되지 않은 경우 proxy.golang.org,direct를 사용한다.
  • GONOPROXY는 직접 가져와야 하는 모듈 접미사의 쉼표로 구분된 디렉터리이다. 와일드카드를 지원한다.
  • GOPRIVATE는 다른 기능들 뿐만 아니라 GONOPROXY와 유사한 기능을 하는 모듈 이름의 쉼표로 구분된 디렉터리이다.

가져오기

Go 1.12부터 모듈 또는 패키지를 가져오는 과정은 다음과 같다:

  1. GOPROXY가 프록시 디렉터리이고 모듈이 GONOPROXYGOPRIVATE에 의해 제외되지 않은 경우, 순서대로 요청하고 첫 번째 유효한 응답에서 중단한다.
  2. GOPROXYdirect인 경우 또는 모듈이 제외될 경우 또는 GOPROXY,direct로 끝나고 어떤 프록시도 해당 의존성을 제공하지 않은 경우, 돌아간다.
    1. https://{module or package name}?go-get=1을 쿼리한다.
    2. go-import 메타 태그를 위한 응답을 스캔한다.
    3. go-import 메타 태그에 표시된 VCS를 사용하여 메타 태그가 가리키는 리포지터리를 가져온다.
    4. {vcs} 필드가 mod인 경우, URL은 VCS 대신 모듈 프록시로 취급해야 한다.
  3. 모듈이 직접 가져오는 경우이고 버전이 지정되지 않았거나, 의존성으로 추가되는 모듈인 경우이고 버전이 지정되지 않았을 때, Go는 모듈의 가장 최근 버전을 사용한다. 모듈이 프록시에서 가져오는 경우, Go는 프록시에 버전 디렉터리을 쿼리하고 가장 최신 버전을 선택한다. 모듈이 직접 가져오는 경우, Go는 리포지터리에서 태그 디렉터리을 쿼리하고 가장 최신의 유효한 의미 있는 버전을 선택한다.

인증

Go 1.13 이전 버전에서는 Go에 의해 수행된 요청의 인증 지원이 다소 일관성이 없었습니다. Go 1.13에서는 .netrc 인증의 지원이 향상되었습니다. HTTPS를 통해 요청이 이루어지고 .netrc 항목이 일치하는 경우, Go는 HTTP 기본 인증 자격 증명을 요청에 추가합니다. Go는 HTTP를 통해 이루어지는 요청에 대해 인증을 수행하지 않습니다. 또한 GOPROXY에서 임베디드 자격 증명을 가진 HTTP 전용 항목은 Go에서 거부합니다.

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