Go의 의존성 관리
GitLab v19.1Go는 아티팩트(artifact) 기반이 아닌 소스 기반의 방식으로 의존성을 관리하는 독특한 접근 방식을 사용합니다. Go 1.11에서는 모듈과 일급(first-class) 패키지 버전 관리 기능이 Go 생태계에 도입되었습니다.
Go는 아티팩트(artifact) 기반이 아닌 소스 기반의 방식으로 의존성을 관리하는 독특한 접근 방식을 사용합니다.
아티팩트 기반 의존성 관리 시스템에서는 패키지가 소스 코드로부터 생성된 아티팩트로 구성되며,
소스 코드와는 별도의 리포지터리 시스템에 저장됩니다.
예를 들어, 많은 NodeJS 패키지는 패키지 리포지터리로 npmjs.org를, 소스 리포지터리로 github.com을 사용합니다.
반면 Go의 패키지는 소스 코드 자체이며, 패키지를 릴리즈하더라도 아티팩트 생성이나 별도의 리포지터리가 필요하지 않습니다.
Go 패키지는 VCS 서버의 버전 관리 리포지터리에 저장되어야 합니다.
의존성은 해당 VCS 서버에서 직접 가져오거나, VCS 서버에서 직접 페치하는 중간 프록시를 통해 가져옵니다.
버전 관리#
Go 1.11에서는 모듈과 일급(first-class) 패키지 버전 관리 기능이 Go 생태계에 도입되었습니다. 이전에는 Go에 버전 관리를 위한 명확한 메커니즘이 없었습니다. 서드파티 버전 관리 도구가 존재하기는 했지만, 기본 Go 환경에는 버전 관리 기능이 지원되지 않았습니다.
Go 모듈은 시맨틱 버전 관리(semantic versioning)를 사용합니다.
모듈의 버전은 v를 접두사로 붙인 유효한 시맨틱 버전인 VCS(버전 관리 시스템) 태그로 정의됩니다.
예를 들어, gitlab.com/my/project의 1.0.0 버전을 릴리즈하려면 개발자가 Git 태그 v1.0.0을 생성해야 합니다.
0과 1이 아닌 주요(major) 버전의 경우, 모듈 이름 뒤에 /vX를 붙여야 하며, 여기서 X는 주요 버전입니다.
예를 들어, gitlab.com/my/project의 v2.0.0 버전은 gitlab.com/my/project/v2로 명명하고 임포트해야 합니다.
Go는 특정 VCS 커밋을 참조하는 특별한 시맨틱 버전인 '유사 버전(pseudo-versions)'을 사용합니다. 시맨틱 버전의 프리릴리즈 컴포넌트는 타임스탬프와 커밋 식별자의 첫 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)'과 '패키지(Package)'#
-
패키지는
*.go파일을 담고 있는 폴더입니다. -
모듈은
go.mod파일을 담고 있는 폴더입니다. -
모듈은 보통 패키지이기도 합니다. 즉,
go.mod파일과*.go파일을 모두 담고 있는 폴더입니다. -
모듈에는 하위 디렉터리가 있을 수 있으며, 이 하위 디렉터리들도 패키지가 될 수 있습니다.
-
모듈은 보통 VCS 리포지터리(Git, SVN, Hg 등)의 형태로 제공됩니다.
-
모듈의 하위 디렉터리 중 자체적으로 모듈인 것은 별개의 독립적인 모듈이며, 상위 모듈에서 제외됩니다.
모듈 repo가 있을 때, repo/sub에 go.mod 파일이 있으면
repo/sub와 그 안에 포함된 모든 파일은 별도의 모듈이며 repo의 일부가 아닙니다.
명명 규칙#
표준 라이브러리를 제외한 모듈이나 패키지의 이름은 (sub.)*domain.tld(/path)* 형식이어야 합니다.
이는 URL과 유사하지만 URL은 아닙니다.
패키지 이름에는 스킴(예: https://)이 없으며, 포트 번호를 포함할 수 없습니다.
example.com:8443/my/package는 유효한 이름이 아닙니다.
패키지 페치#
Go 1.12 이전에는 패키지 페치 절차가 다음과 같았습니다:
-
https://{패키지 이름}?go-get=1에 쿼리를 보냅니다. -
응답에서
go-import메타 태그를 스캔합니다. -
메타 태그가 지정한 VCS를 사용하여 해당 리포지터리를 페치합니다.
메타 태그는 <meta name="go-import" content="{prefix} {vcs} {url}"> 형식이어야 합니다.
예를 들어, gitlab.com/my/project git https://gitlab.com/my/project.git은
gitlab.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.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 1.13 이상에서는
GOPROXY가 정의되지 않은 경우proxy.golang.org,direct를 사용합니다. -
GONOPROXY는 프록시를 사용하지 않고 직접 페치해야 하는 모듈 접미사의 쉼표로 구분된 목록입니다. 와일드카드를 지원합니다. -
GOPRIVATE는GONOPROXY와 동일한 기능을 수행하면서 다른 기능도 추가로 비활성화하는 모듈 이름의 쉼표로 구분된 목록입니다.
페치 절차#
Go 1.12 이상에서 모듈이나 패키지를 페치하는 절차는 다음과 같습니다:
-
GOPROXY가 프록시 목록이고 모듈이GONOPROXY또는GOPRIVATE에 의해 제외되지 않은 경우, 순서대로 조회하고 첫 번째 유효한 응답에서 중지합니다. -
GOPROXY가direct이거나, 모듈이 제외되었거나,GOPROXY가,direct로 끝나면서 어떤 프록시도 모듈을 제공하지 않은 경우, 대체 절차로 넘어갑니다.
https://{모듈 또는 패키지 이름}?go-get=1에 쿼리를 보냅니다.
-
응답에서
go-import메타 태그를 스캔합니다. -
메타 태그가 지정한 VCS를 사용하여 해당 리포지터리를 페치합니다.
-
{vcs}필드가mod이면, URL은 VCS가 아닌 모듈 프록시로 처리해야 합니다. -
모듈이 의존성으로서가 아닌 직접 페치되는 경우, 중지합니다.
-
go.sum에 모듈에 해당하는 항목이 있으면, 체크섬을 검증하고 중지합니다. -
GOSUMDB가 체크섬 데이터베이스를 지정하고 모듈이GONOSUMDB또는GOPRIVATE에 의해 제외되지 않은 경우, 모듈의 체크섬을 검색하여go.sum에 추가하고 다운로드된 소스와 대조하여 검증합니다. -
GOSUMDB가off이거나 모듈이 제외된 경우, 다운로드된 소스에서 체크섬을 계산하여go.sum에 추가합니다.
다운로드된 소스에는 go.mod 파일이 있어야 합니다.
go.mod 파일에는 모듈 이름을 지정하는 module 지시어가 포함되어야 합니다.
go.mod에 지정된 모듈 이름이 모듈을 페치하는 데 사용된 이름과 일치하지 않으면 모듈 컴파일이 실패합니다.
모듈이 직접 페치되고 버전이 지정되지 않은 경우, 또는 모듈이 의존성으로 추가되고 버전이 지정되지 않은 경우, Go는 가장 최신 버전의 모듈을 사용합니다. 모듈이 프록시에서 페치되는 경우, Go는 프록시에 버전 목록을 요청하고 최신 버전을 선택합니다. 모듈이 직접 페치되는 경우, Go는 리포지터리에 태그 목록을 요청하고 유효한 시맨틱 버전 중 최신 버전을 선택합니다.
인증#
Go 1.13 이전 버전에서는 Go가 요청 인증을 지원하는 방식이 다소 일관되지 않았습니다.
Go 1.13에서는 .netrc 인증 지원이 개선되었습니다.
HTTPS를 통한 요청이 이루어지고 일치하는 .netrc 항목을 찾을 수 있으면, Go는 요청에 HTTP Basic 인증 자격 증명을 추가합니다.
Go는 HTTP를 통한 요청에는 인증을 하지 않습니다.
Go는 GOPROXY에서 자격 증명이 내장된 HTTP 전용 항목을 거부합니다.
Go 1.24 이상에서는 GOAUTH를 사용하여 인증 자격 증명을 제공할 수 있습니다.
자세한 내용은 비공개 프로젝트에 대한 Go 요청 인증을 참고하세요.