Go モジュール:ファイルプロキシと vendor で閉域網ビルド
한국어 원문으로 표시합니다.
목표
Go 모듈을 연결된 쪽에서 새 모듈 캐시로 받아 파일 프록시로 옮기고, 폐쇄망 쪽에서 GOPROXY=file:// 와 vendor 두 길로 빌드한다. go.sum 을 반입 매니페스트로 쓰는 법과, GOFLAGS 한 줄이 vendor 를 무시하게 만드는 함정을 직접 확인한다.
왜 중요한가
Go 는 기본으로 proxy.golang.org 에서 받고 sum.golang.org 에 해시를 묻는다. 폐쇄망에서는 둘 다 닿지 않는다. 모듈 캐시의 cache/download 는 그 자체가 프록시 프로토콜 모양이라 옮기기만 하면 프록시가 되고, go.sum 이 완전하면 체크섬 데이터베이스에 물을 일이 없다. 이 파드는 인터넷(80/443)에 닿으므로 받는 쪽 역할을 하고, 폐쇄망 쪽 확인은 채점기가 바깥으로 가는 HTTP(S)를 닫힌 프록시로 보내 막은 채로 한다.
단계
/root/goair/app에 모듈example.com/airgap-hello를 만들고rsc.io/quotev1.5.2 의quote.Hello()를 출력하는 main.go 를 쓴다. 새 모듈 캐시GOMODCACHE=/root/goair/outside-cache로 받고go mod tidy까지 한다./root/goair/outside-cache/cache/download의 내용을/srv/goproxy로 옮긴다.- 폐쇄망 쪽 설정
/root/goair/inside.env에GOPROXY=file:///srv/goproxy와GOFLAGS=-mod=readonly를 적는다. - 그 설정을 읽고 바깥을 막은 채 새 모듈 캐시
/root/goair/inside-cache로 빌드해/root/goair/bin/hello-proxy를 만든다. /root/goair/app에서 vendor 디렉터리를 만든다.- 이미지의
GOFLAGS=-mod=mod를 그대로 둔 채GOPROXY=off와 빈 모듈 캐시로 빌드해 본다. 실패 메시지를/root/goair/gomod-trap.txt에 저장한다. GOPROXY=off에서 vendor 만으로 빌드해/root/goair/bin/hello-vendor를 만든다.- go.sum 에서 모듈 zip 의 해시 줄(
/go.mod가 붙지 않은 줄)을모듈 버전 해시로 옮긴 반입 기록/root/goair/intake.txt를 쓴다. 각 해시는/srv/goproxy의.ziphash와 같아야 한다.
참고
- 지금 값:
go env GOPROXY GOFLAGS GOMODCACHE GOSUMDB - 환경 파일 읽기:
set -a; . /root/goair/inside.env; set +a - 바깥 막기:
HTTPS_PROXY=http://127.0.0.1:9 HTTP_PROXY=http://127.0.0.1:9 go build ...(Go 는 이 변수를 따릅니다) - 흔한 실수 1: 평소 모듈 캐시로 빌드해 성공하고 끝내기. 이미 받아 둔 캐시가 도와준 것이라 프록시를 시험하지 않은 셈입니다.
- 흔한 실수 2: vendor 를 만들고도 GOFLAGS 를 확인하지 않기. 이 이미지에서는 vendor 가 무시됩니다.
받는 쪽: 새 모듈 캐시로 의존성 받기
/root/goair/app 에 모듈 example.com/airgap-hello 와 main.go 를 만들고, GOMODCACHE=/root/goair/outside-cache 로 rsc.io/quote v1.5.2 를 받아 go mod tidy 까지 한다.
go mod init 으로 모듈을 만들고 go get 으로 버전을 정확히 받습니다. 새 캐시 디렉터리를 GOMODCACHE 로 주면 이번에 받은 것만 그 안에 쌓입니다. tidy 는 쓰이는 의존성을 직접 의존으로 정리합니다.
모듈 캐시를 파일 프록시로 옮기기
/root/goair/outside-cache/cache/download 의 내용을 /srv/goproxy 로 옮긴다.
모듈 캐시의 cache/download 아래는 이미 프록시 프로토콜 모양(@v/list, .info, .mod, .zip)입니다. 디렉터리 구조를 그대로 유지해 복사하세요. 풀린 소스가 있는 캐시의 다른 디렉터리는 필요 없습니다.
폐쇄망 쪽 Go 환경 파일
/root/goair/inside.env 에 GOPROXY=file:///srv/goproxy 와 GOFLAGS=-mod=readonly 를 적는다.
셸이 그대로 읽을 수 있는 이름=값 줄입니다. file 스킴 뒤에는 절대 경로가 오므로 슬래시가 세 개가 됩니다. -mod=readonly 는 빌드가 go.mod 를 몰래 고치지 못하게 합니다.
바깥을 막고 파일 프록시로 빌드
inside.env 를 읽고 바깥을 막은 채 새 모듈 캐시 /root/goair/inside-cache 로 빌드해 /root/goair/bin/hello-proxy 를 만든다.
환경 파일을 export 되게 읽은 뒤 GOMODCACHE 를 새 디렉터리로 주고, 바깥 주소는 닫힌 프록시로 보내세요. 이미 받아 둔 캐시로 빌드하면 프록시를 시험한 것이 아닙니다.
두 번째 길: vendor
/root/goair/app 에서 vendor 디렉터리를 만든다.
go mod 의 하위 명령 가운데 의존성 소스를 저장소 안으로 복사하는 것이 있습니다. 결과로 vendor/modules.txt 가 생기는지 보세요.
vendor 가 있는데도 실패하는 빌드
이미지의 GOFLAGS=-mod=mod 를 그대로 둔 채 GOPROXY=off 와 빈 모듈 캐시로 빌드해 보고, 실패 메시지를 /root/goair/gomod-trap.txt 에 저장한다.
이 단계는 실패를 기록하는 단계입니다. go env GOFLAGS 로 지금 값을 먼저 보세요. -mod=mod 가 vendor 를 어떻게 다루는지 읽기 자료를 떠올리면 메시지가 이해됩니다.
GOPROXY=off 에서 vendor 로 빌드
GOPROXY=off 에서 vendor 만으로 빌드해 /root/goair/bin/hello-vendor 를 만든다.
vendor 를 쓰게 하는 -mod 값이 있습니다. 환경의 GOFLAGS 를 덮어쓰거나 명령줄에서 직접 주세요. 모듈 캐시가 비어 있어도 되어야 합니다.
go.sum 으로 반입 기록 쓰기
go.sum 의 모듈 zip 해시 줄을 모듈 버전 해시 로 옮긴 /root/goair/intake.txt 를 쓴다. 각 해시는 /srv/goproxy 의 .ziphash 와 같아야 한다.
go.sum 의 줄은 모듈, 버전, h1: 해시 세 칸입니다. 버전 뒤에 /go.mod 가 붙은 줄은 go.mod 파일의 해시라 zip 과 다릅니다. 프록시 디렉터리의 .ziphash 파일과 한 줄씩 대조해 보세요.