-
Notifications
You must be signed in to change notification settings - Fork 3
Dockerode를 이용한 컨테이너 사용
mjh000526 edited this page Dec 1, 2024
·
1 revision
📌
node에서 docker을 관리하기위한 라이브러리
이전 기수에서 sh를 이용해 도커를 관리했었는데, node로 docker관리하는 것이 새로울 것 같아서 선택했다.
-
Docker create - 일종의 dockerfile이라고 생각하면 편할듯하다
// 컨테이너 생성 const container = await docker.createContainer({ Image: 'node:latest', // 이미지 Tty: true, //가상 터미널 OpenStdin: true, //표준 입력으로 상호작용준비 AttachStdout: true, // 표준 출력 연결 AttachStderr: true, // error 표준 출력 연결 Env: [ 'NODE_DISABLE_COLORS=true', 'TERM=dumb' ] });
- cmd로 바로 했을때 오류
- tty는 터미널 스타일을 위한 색 옵션이 함께 출력되기때문에 env로 해당 기능들을 비활성화 해야한다.
-
Docker에 gist 파일 넣기
- docker에 값을 삽입할때는 tar형식으로 넣어야한다. 안하면 컨테이너에서 해당 파일을 읽지 못함
await container.start(); //desciption: tar 아카이브를 생성 const tarBuffer = await new Promise<Buffer>((resolve, reject) => { const pack = tar.pack(); for (const file of files) { //desciption: 파일 이름과 내용을 tar 아카이브에 추가 pack.entry({ name: file.name }, file.content, (err) => { if (err) reject(err); }); } //desciption: 아카이브 완료 pack.finalize(); //desciption: Buffer로 변환 const buffers: Buffer[] = []; pack.on('data', (data) => buffers.push(data)); pack.on('end', () => resolve(Buffer.concat(buffers))); pack.on('error', reject); }); //desciption: tarBuffer를 Docker 컨테이너에 업로드 await container.putArchive(tarBuffer, { path: '/' });
-
컨테이너에 파일이 모두 업로드 됬으니 실행파일을 그대로 실행
//desciption: 실행 결과를 캡처하기 위한 Exec 생성 const exec = await container.exec({ AttachStdin: true, //표준 입력 AttachStdout: true, //표준 출력 AttachStderr: true, //표준 에러 Tty: false, Cmd: ['node', mainFileName], });
-
코드 실행 결과를 메모리에 저장
const stream = await exec.start(); let output = ''; //desciption: 스트림에서 데이터 수집 stream.on('data', (chunk) => { output += chunk.toString(); }); //desciption: 스트림 종료 후 결과 반환 return new Promise((resolve, reject) => { stream.on('end',async () => { //리소스 반환 await container.remove({ force: true }); resolve(output .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\r]/g, '') .replaceAll('\n)', '\n') .trim()); stream.on('error', reject); });
- output에서 \r\n) \u0000처럼 제어코드들이 함께 이어지기때문에 정규식으로 제거하고 반환
동적실행에서는 옵션은 정적파일 실행과 비슷했다.
const stream = await exec.start({hijack: true,stdin: true});
let output = '';
const inputContent = "처음\n둘\n셋\n넷\n다섯"; // 입력값 배열
const inputs = inputContent.split("\n")
for (const input of inputs) {
await this.delay(50);//각 입력 term
stream.write(input + '\n');
}
stream.end();
hijack 설정
- true - 하나의 스트림으로 입출력을 동시에 처리(Socket객체)
- false - http통신에서 사용되는 송수신스트림을 관리 (httpDuplex객체)
delay 사용
- 실행파일의 readline에 한번에 여러 데이터가 들어가면 처음 데이터를 처리하는 과정동안 전송된 데이터들을 readline에서 읽지 못하는 오류가 있어서 약간의 delay를 추가
실패했던 과정은 Dockerord Trouble Shooting에 기록되어있음
도커로 돌리기 때문에 로컬에서 실행할 때와 다르게 docker 명령어를 인식하지 못하는 문제가 있음
- DinD(Docker in Docker)
- 도커안에서 여러 컨테이너를 만들어서 사용하는 방법
- DooD(Docker out fo Docker)
- 도커 컨테이너가 실행되고 있는 호스트 서버(parent)에 컨테이너를 생성하는 방법
💡 각 도커마다 환경이 다르고 독립적으로 실행시키기 때문에 DinD로 하여 nestjs컨테이너의 리소스를 늘릴 필요가 없다고 판단하여 DooD 적용