시도했던 이유
- Knative Function은 paketo buildpack을 기본 빌드팩으로 채택해서 쓰고 있다.
- 빌드팩은 runtime version과 같은 정보를 동적으로 입력받은 뒤
실행 시점에서 binary를 다운로드받는다. - 그런데, 신규 함수를 생성할 때마다 CPython이나 Node같은 runtime을 매번 다운로드받는 방식은
빌드 속도가 느려지는 원인이 된다. - 빌드팩이 실행될 환경인 builder 이미지에서 특정 runtime은 미리 다운로드 받아두고,
buildpack에서 빌드를 시도할 때 builder 이미지에 해당 runtime이 있다면 재사용하도록 만들 수 있지 않을까?
cf. 원래 Buildpack은 애초에 'runtime을 동적으로 관리할 수 있도록 한다'는 철학에서 출발한 프로덕트이기 때문에,
매번 같은 runtime을 다운받는 데서 발생하는 빌드 시간은 사용자가 감내해야 할 요소다.
그럼에도 혹시나 싶어서 해봤던 거고, 결과적으로는 실패했다. 어떻게 했는지, 왜 안됐는지를 기록하는 글.
실행환경은 Mac 기준이다.
CPython binary를 builder stack에 포함해보기 위한 작업
https://paketo.io/docs/howto/create-custom-stack/
https://buildpacks.io/docs/operator-guide/create-a-stack/
위 문서들을 참고해서 진행했다.
23.03.17일 기준으로
builder / buildpackless-base-builder 이미지에서 사용하는 default stack 이미지는 bionic-base-stack (ubuntu 18.04).
ubuntu 18.04에 build에 쓰일 기본 binary (openssl 등)를 설치된 두 개의 이미지가 있다.
https://github.com/paketo-buildpacks/bionic-base-stack/tree/main/stack
- base-image: build.Dockerfile
- run-image: run.Dockerfile
build.Dockerfile에 cpython binary를 추가한다.
FROM ubuntu:bionic
ARG sources
ARG packages
ARG package_args='--allow-downgrades --allow-remove-essential --allow-change-held-packages --no-install-recommends'
RUN echo "$sources" > /etc/apt/sources.list
RUN echo "Package: $packages\nPin: release c=multiverse\nPin-Priority: -1\n\nPackage: $packages\nPin: release c=restricted\nPin-Priority: -1\n" > /etc/apt/preferences
RUN echo "debconf debconf/frontend select noninteractive" | debconf-set-selections && \
export DEBIAN_FRONTEND=noninteractive && \
apt-get -y $package_args update && \
apt-get -y $package_args upgrade && \
apt-get -y $package_args install locales && \
locale-gen en_US.UTF-8 && \
update-locale LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_ALL=en_US.UTF-8 && \
apt-get -y $package_args install $packages && \
rm -rf /var/lib/apt/lists/* /tmp/* /etc/apt/preferences
# customized cpython을 이미지에 설치, 경로는 buildpack이 binary 저장하는 경로인 /layers/paketo-buildpacks_cpython/cpython 로 지정
WORKDIR /workspace
ARG PYTHON_VERSION=3.10.8
RUN wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz && \
tar -xzf Python-${PYTHON_VERSION}.tgz && \
cd Python-${PYTHON_VERSION} && \
./configure --prefix=/layers/paketo-buildpacks_cpython/cpython && \
make && \
make install && \
cd .. && \
rm -rf Python-${PYTHON_VERSION}.tgz Python-${PYTHON_VERSION}
RUN for path in /workspace /workspace/source-ws /workspace/source; do git config --system --add safe.directory "${path}"; done
RUN curl -sSfL -o /usr/local/bin/yj https://github.com/sclevine/yj/releases/latest/download/yj-linux-amd64 \
&& chmod +x /usr/local/bin/yj
stack.toml를 사용해서 OCI image를 빌드, container registry에 push한다.
paketo 공식문서를 보면 jam과 skopeo를 사용해서 OCI 이미지를 생성하라고 안내하고 있다.
- skopeo: mac 기준
brew install skopeo
로 설치 가능 - jam: https://github.com/paketo-buildpacks/jam 를 받아서 써야 한다.
- repo를 로컬에 clone하고
- go build main.go 실행해서 소스코드를 빌드한 다음
- 빌드 결과인 binary를 /usr/local/bin 으로 옮겨서 터미널로 실행 가능하도록 한다.
이미지를 커스텀한 root 경로로 와서
jam create-stack --config stack.toml --build-output test-cpython.oci.tar --run-output test-cpython-run.oci.tar
명령어를 실행한다. (공식문서 명령어대로 하면 동작을 안 한다. --build-output과 --run-output의 확장자를 .tar로 명시해야 한다.)
정상적으로 실행되었다면, .tar 파일 두 개가 생성된다.
skopeo login -u <docker.io id> <your-container-registry>
로 registry에 로그인한다. private registry라면 docker.io 대신 private registry domain을 입력하면 된다.
skopeo copy oci-archive:test-cpython.oci.tar docker://<your-registry-path>/base-image
skopeo copy oci-archive:test-cpython-run.oci.tar docker://<your-registry-path>/run-image
명령어를 수행하면, local path에 있는 tar 파일을 container registry에 push할 수 있다.
새로 만들어진 build-image, run-image로 paketo builder를 생성한다
https://github.com/paketo-buildpacks/buildpackless-base-builder/blob/main/builder.toml
위의 repo를 로컬에 clone한 뒤, builder.toml 파일을 아래와 같이 수정한다.
description = "Ubuntu bionic base image with no buildpacks included. To use, specify buildpacks at build time."
[lifecycle]
version = "0.16.0" # 23.03.17 기준 main브랜치의 lifecycle 버전이 0.16.0으로 설정되어 있었음.
[stack]
build-image = "<your-registry-path>/base-image"
id = "io.buildpacks.stacks.bionic"
run-image = "<your-registry-path>/base-image"
run-image-mirrors = ["<your-registry-path>/base-image"]
수정한 builder.toml와 pack cli를 사용해서 새 builder image를 생성한다.
pack builder create <docker-registry-image>/buildpackless-base-builder-customize --config ./builder.toml --publish
--publish 옵션을 주면 빌드 후 registry push까지 진행된다.
커스텀한 builder image를 사용해서 knative function을 빌드한다.
knative function의 빌드에 쓰이는 func.yaml 파일을 대략 아래와 같이 변경한다.
specVersion: 0.25.0
name: ## name
namespace: ## namespace
runtime: python
image: <your-knative-function-image>
imageDigest: ""
build: local
git: {}
builderImages: ## 0.25.0 이후 버전부터는 이 필드의 이름이 약간 달라졌다.
pack: <docker-registry-image>/buildpackless-base-builder-customize # buildpackless-builder에 cpython binary 추가한 커스텀 builder
buildpacks:
- gcr.io/paketo-buildpacks/python:2.5.0 # python buildpack
volumes: []
buildEnvs:
- name: BP_DISABLE_SBOM
value: "True"
envs: []
annotations: {}
options: {}
labels: []
healthEndpoints:
liveness: /health/liveness
readiness: /health/readiness
created: 2022-10-13T10:05:09.494481+09:00
invocation:
format: cloudevent
이걸로 knative function 빌드를 시도하면, 아래와 같은 에러가 발생한다.
설치된 binary를 사용하지 않음 + metadata.toml 정보와 일치하지 않는 binary이므로 삭제 시도한다.
포기한 이유
paketo buildpack의 경우, 빌드에 사용된 binary의 무결성 확인 용도로 metadata.toml 파일이 image 내부에 생성된다. 대략 아래와 같은 구조.
buildpack-default-process-type = "web"
[[bom]]
name = "helper"
[bom.metadata]
layer = "helper"
names = ["ca-certificates-helper"]
version = "3.4.0"
[bom.buildpack]
id = "paketo-buildpacks/ca-certificates"
version = "3.4.0"
[[bom]]
name = "CPython"
[bom.metadata]
cpe = "cpe:2.3:a:python:python:3.10.8:*:*:*:*:*:*:*"
licenses = ["0BSD", "CNRI-Python-GPL-Compatible", "PSF-2.0"]
purl = "pkg:generic/python@3.10.8?checksum=f400c3fb394b8bef1292f6dc1292c5fadc3533039a5bc0c3e885f3e16738029a&download_url=https://www.python.org/ftp/python/3.10.8/Python-3.10.8.tgz"
uri = "https://artifacts.paketo.io/python/python_3.10.8_linux_x64_bionic_b38c22eb.tgz"
version = "3.10.8"
[bom.metadata.checksum]
algorithm = "SHA-256"
hash = "b38c22eb18d000f88267ab8c845ad88362d05834e0c076be076e290344f3d0e6"
[bom.metadata.source]
uri = "https://www.python.org/ftp/python/3.10.8/Python-3.10.8.tgz"
[bom.metadata.source.checksum]
algorithm = "SHA-256"
hash = "f400c3fb394b8bef1292f6dc1292c5fadc3533039a5bc0c3e885f3e16738029a"
[bom.buildpack]
id = "paketo-buildpacks/cpython"
version = "1.7.2"
[[buildpacks]]
id = "paketo-buildpacks/ca-certificates"
version = "3.4.0"
api = "0.7"
homepage = "https://github.com/paketo-buildpacks/ca-certificates"
[[buildpacks]]
id = "paketo-buildpacks/cpython"
version = "1.7.2"
api = "0.7"
[[buildpacks]]
id = "paketo-buildpacks/pip"
version = "0.16.1"
api = "0.7"
[[buildpacks]]
id = "paketo-buildpacks/pip-install"
version = "0.5.7"
api = "0.7"
[[buildpacks]]
id = "paketo-buildpacks/python-start"
version = "0.14.0"
api = "0.8"
homepage = "https://github.com/paketo-buildpacks/python-start"
[[buildpacks]]
id = "paketo-buildpacks/procfile"
version = "5.4.0"
api = "0.7"
homepage = "https://github.com/paketo-buildpacks/procfile"
[[processes]]
type = "web"
command = "python -m parliament ."
args = []
direct = false
buildpack-id = "paketo-buildpacks/procfile"
빌드 과정에서 다운로드받은 python buildpack binary와 CPython 정보가 담겨 있다. pack에서 binary를 동적으로 관리할 수 있도록 만들어주는 역할을 하는 것으로 보인다.
여기 있는 metadata.toml 파일까지 커스텀하게 건드린다면 가능할지도 모르겠지만...
- pack과 buildpack에서 동적으로 binary를 관리하는 핵심 기능을 이 정도까지 수정해가며 무력화시킬 필요가 있을까?
- 위 metadata.toml는 builder나 buildpack 이미지가 아니라, pack build로 수행된 후 knative function로 배포할 이미지에 저장된다.
- pack build 프로세스를 하나하나 따라가면서 수정할 부분을 파악해야 하는데, 이 정도까지 할 거라면 그냥 빌드팩을 쓰지 말고 다른 방식으로 이미지 빌드하는 법을 찾는 게 낫다.
기타 참고자료
https://www.altoros.com/blog/cloud-native-buildpacks-creating-custom-components/
https://www.altoros.com/blog/cloud-native-buildpacks-how-to-create-a-custom-builder/
https://eggboy.medium.com/cloud-native-buildpack-inside-out-e282233206d2
'프로그래밍 > 이것저것_개발일지' 카테고리의 다른 글
FastAPI, SQLAlchemy 프로덕트에서 alembic을 쓰지 않은 이유 (0) | 2024.01.29 |
---|---|
2023 서울디지털재단 주최 생성AI 해커톤 - 상담부문 최우수상 후기 (0) | 2023.07.15 |
Streamlink로 유튜브 멤버십 스트리밍 영상 다운로드하기 (2) | 2021.09.27 |
화상 모의면접 연습 플랫폼 개발 프로젝트 (2) - KeyCloak 활용해서 서비스 DB에 OAuth 인증 붙이기 (0) | 2021.04.18 |
화상 모의면접 연습 플랫폼 개발 프로젝트 (1) - 채팅 DB 아키텍처 고민하기 (0) | 2021.02.20 |