3주차 - 다양한 노드 그룹
개요
노드 그룹
다양한 cpu 아키텍쳐와 os를 활용해보자.
여태, 그냥 단순히 amazon 2023을 활용했다.
그러나 사실 다른 선택지로서 arm cpu 아키텍쳐를 가진 graviton과 컨테이너 최적화 os인 bottlerocket도 존재한다.
이들을 활용해보고 어떤 차이가 있는지 간략하게 짚어보자.
docker buildx를 통한 멀티 빌드
여기에서 멀티는 멀티 스테이지 빌드가 아니라, 멀티 플랫폼 빌드이다.
하나의 cpu 아키텍쳐에서 빌드를 하면 같은 아키텍쳐에서만 해당 이미지를 사용할 수 있다.
이때 다양한 아키텍쳐에서도 돌아갈 수 있도록, 다양한 플랫폼을 통해 동시에 이미지를 빌드하는 것을 멀티 플랫폼 빌드라고 한다.[1]
이렇게 만들어지는 이미지는 레지스트리에 등록될 때도 다르게 설정된다.
각 플랫폼에 맞는 구분자를 따로 두게 되는 격이다.
간혹 허브를 보면 이렇게 여러 아키텍쳐가 있는 게 눈에 띄는데, 이게 바로 멀티 플랫폼 빌드를 했기 때문에 이런 것이다.
그럼 구체적으로 멀티 플랫폼 빌드는 어떻게 이뤄지는 걸까?
docker의 buildx를 활용하면 간편하게 멀티 플랫폼 빌드를 수행할 수 있다.
빌드를 진행할 때, 임의의 다른 아키텍쳐를 가진 vm을 띄워서 그 친구를 이용해 빌드를 진행해주는 것이다.
흔히 qemu라고 하는 매우 경량의 vm을 에뮬레이션하여 빌드 단계를 진행한다.
간단 세팅
arch
docker buildx ls
먼저 현재 정보를 확인해보자.
현재 내 cpu 아키텍쳐는 x86_64이고, 기본적인 buildx가 하나 있다.
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker images
docker buildx create --use --name mybuilder
docker buildx ls
docker buildx inspect --bootstrap
이제 buildx를 위한 준비를 해보자.
먼저 qemu를 위한 바이너리를 받아오고, 이를 기반으로 나만의 builder를 만드는 것으로 시작한다.
여러 아키텍쳐들을 내 로컬에 받아오는 것이 보인다.
buildx를 진행할 때 내 빌더가 사용될 것이다.
또한 빌드될 수 있는 여러 플랫폼이 표시되고 있다.
이미지 제작 후 빌드 테스트
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
from datetime import datetime
import socket
import os
class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/plain')
self.end_headers()
image_tag = os.getenv("TAG", "unknown")
now = datetime.now()
hostname = socket.gethostname()
client_ip = self.client_address[0]
response_string = "This is test server made by Zerotay!\n"
response_string += now.strftime("The time is %-I:%M:%S %p\n")
response_string += f"TAG VERSION: {image_tag}\n"
response_string += f"Server hostname: {hostname}\n"
response_string += f"Client IP: {client_ip}\n"
response_string += "----------------------------------\n"
self.wfile.write(bytes(response_string, "utf-8"))
def startServer():
try:
server = ThreadingHTTPServer(('', 80), RequestHandler)
print("Listening on " + ":".join(map(str, server.server_address)))
server.serve_forever()
except KeyboardInterrupt:
server.shutdown()
if __name__ == "__main__":
startServer()
간단한 웹서버를 하나 만들었다.
현재 이미지의 버전, 들어온 ip 주소를 출력한다.
FROM python:3.12
ENV PYTHONUNBUFFERED=1
ENV TZ=Asia/Seoul
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY . /app
WORKDIR /app
ARG TAG
ENV TAG=${TAG}
CMD ["python3", "zero_server.py"]
도커파일에서는 TAG를 인자로 받고 이를 컨테이너 환경변수로 넣을 수 있도록 세팅했다.
docker pull python:3.12
TAG="0.0.1"
docker build --build-arg TAG=$TAG -t zero-web:$TAG -t zero-web:latest .
docker run -d -p 8080:80 --name=myweb zero-web
curl http://localhost:8080
docker rm -f myweb
빌드 시점에 ARG를 전달하도록 세팅했기 때문에, 위의 이미지에서도 캐시가 잘 되도록 ARG를 최대한 아래에 배치했다.
현재 컨테이너의 이름(호스트)과 시간, 버전, 클라 ip가 확인된다!
아마 클라 ip는 docker0에서 snat된 값인 것 같은데, 잘은 모르겠다.
멀티 플랫폼 빌드
DOCKERNAME=zerotay
TAG=0.0.5
docker buildx build --platform linux/amd64,linux/arm64 --push --build-arg TAG=$TAG --tag $DOCKERNAME/zero-web:$TAG .
두 amd64, arm64로 이미지가 빌드되고 있는 것이 확인된다.
바로 푸시를 하도록 설정했기 때문에 그대로 이미지가 올라간 것이 확인된다.
docker manifest inspect $DOCKERNAME/zero-web:multi | jq
docker buildx imagetools inspect $DOCKERNAME/zero-web:multi
이렇게 manifest를 받아와서도 확인할 수 있다.
이제 이 이미지를 토대로, 다양한 아키텍쳐를 가진 노드 그룹에서 테스트를 진행해보자!
zerotay/zero-web:multi
그라비톤
bottlerocket
이 각각은 무조건 성능 테스트를 해볼 것이다.
어떤 차이가 있는지, 비교하지 않으면 오늘 잠을 못잘 것 같다.
관련 문서
이름 | noteType | created |
---|