2MB REST API 구축 -- 스크래치 이미지 에피소드 III

11370 단어 gotutorialdocker
📓 The Gist

마지막 에피소드는 히트를 쳤습니다. 계속하기 전에 확인하십시오.

여기에서 간단한 Go REST API 프록시를 빌드하여 더 설명적이고 유용한 작업을 수행할 것입니다. 이것은 우리가 hello world 이상의 것을 할 수 있음을 보여주고 스크래치 이미지에 다른 종속성을 추가하는 방법을 보여줍니다.

REST API



이 프록시는 url에서 리소스를 가져와 반환합니다. 이것은 원격 리소스를 캐싱하기 위한 일반적인 패턴입니다.

예:

$ curl  'http://localhost:8080/?url=https%3A%2F%2Fwww.httpbin.org%2Fget' \
| jq .headers
{
  "Accept-Encoding": "gzip",
  "Host": "www.httpbin.org",
  "User-Agent": "Go-http-client/1.1"
}

main.go
package main

import (
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        url := r.FormValue("url")
        if url == "" {
            w.WriteHeader(http.StatusBadRequest)
            w.Write([]byte("\"url\" param is required"))
            return
        }
        resp, err := http.Get(url)
        if err != nil {
            w.WriteHeader(http.StatusInternalServerError)
            w.Write([]byte(fmt.Sprintf("Error fetching url [%s]: %s", url, err.Error())))
            return
        }
        // stream the resp body to our HTTP response, w
        writtenCount, err := io.Copy(w, resp.Body)
        if err != nil || writtenCount == 0 {
            w.WriteHeader(http.StatusInternalServerError)
            w.Write([]byte("Response was empty from url  " + url))
            return
        }
    })
    if port := os.Getenv("PORT"); port != "" {
        http.ListenAndServe(":"+port, nil)
    } else {
        log.Panic("PORT not set")
    }
}


높은 수준에서 HandleFunc 쿼리 매개변수에서 http.Get(url)를 호출하는 url에 전달된 핸들러를 구현한 다음 url 의 본문을 클라이언트로 스트리밍합니다.

마지막으로 우리는 환경에 의해 전달된 PORT를 듣습니다.

도커파일



FROM golang:stretch AS build
WORKDIR /build
RUN apt-get update && \
    apt-get install -y xz-utils
ADD https://github.com/upx/upx/releases/download/v3.95/upx-3.95-amd64_linux.tar.xz /usr/local
RUN xz -d -c /usr/local/upx-3.95-amd64_linux.tar.xz | \
    tar -xOf - upx-3.95-amd64_linux/upx > /bin/upx && \
    chmod a+x /bin/upx
COPY . .
RUN GO111MODULE=off CGO_ENABLED=0 GOOS=linux \
    go build  -a -tags netgo -ldflags '-w -s'  main.go && \
    upx main

FROM scratch
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=build /build/main /main
WORKDIR /
CMD ["/main"]

다음은 몇 가지 새로운 개념을 보여줍니다.
  • go의 경우 정적 빌드에는 -tags netgo 가 필요합니다. 빌드가 다른 동적 라이브러리로 끝나는 경우 C 도구 체인이 필요한 CGO_ENABLED=1 ... -extldflags "-static"를 사용할 수 있습니다.
  • upx -- Ultimate Packer for Exes은 약 70%를 줄이는 데 사용됩니다
  • .
  • https 요청을 할 때(http.Get() 호출 중) https 서버의 인증서를 인증할 수 있는 클라이언트 인증서 번들ca-certificates.crt이 필요합니다.

  • 이미지 구축



    docker build . -t go-http-proxy
    



    docker images |grep go-http-proxy | awk '{print $7}'   
    2.16MB
    

    100kb가 조금 넘지만 2MB도 나쁘지 않습니다! 이것은 우리가 사용했던 806MB 스트레치 이미지보다 99.5% 작습니다.

    docker images |grep c0167164f9fa | awk '{print $7}' 
    806MB
    

    실행 및 테스트



    운영...

    docker run -ePORT=8080 -p8080:8080 go-http-proxy
    

    테스트...

    curl  'http://localhost:8080/?url=https%3A%2F%2Fwww.httpbin.org%2Fget' | jq .headers
    {
      "Accept-Encoding": "gzip",
      "Host": "www.httpbin.org",
      "User-Agent": "Go-http-client/1.1"
    }
    

    안에 뭐가 들어있어



    이 이미지에는 두 개의 레이어가 있습니다(COPY당 하나씩) -- 살펴보겠습니다.

    $ mkdir go-http-proxy &&  cd go-http-proxy 
    $ docker save go-http-proxy |tar -x
    $ find . -iname layer.tar|xargs -n 1 tar -tf
    main
    etc/
    etc/ssl/
    etc/ssl/certs/
    etc/ssl/certs/ca-certificates.crt
    

    ... 여전히 두 개의 파일만 있습니다.

    다음 단계



    이 시점에서 우리는 게임을 nodejs와 같은 스크립팅 언어로 레벨 업해야 합니다. 이 언어는 앱과 런타임 모두에서 훨씬 더 많은 종속성을 포함합니다.

    ➡️ 도커 이미지 축소에 대한 팁을 들어보겠습니다. 그리고 어떤 플랫폼이 처음부터 구축되기를 원하십니까?

    좋은 웹페이지 즐겨찾기