Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

기존 Rails 애플리케이션 컨테이너화

소프트웨어를 컨테이너화하는 것은 개발 및 배포의 용이성을 위해 표준화된 단위로 패키징하는 것입니다. 컨테이너는 모든 종속성과 함께 애플리케이션의 코드를 함께 묶습니다. 컨테이너는 완전히 단독으로 사용할 수 있습니다. 여기에는 소프트웨어, 런타임 환경 및 시스템 라이브러리가 포함된 패키지가 포함되어 있습니다. 컨테이너는 개발자와 운영 팀이 환경에 관계없이 소프트웨어가 동일하게 실행되도록 돕습니다. 코드를 인프라에서 분리함으로써 "컨테이너화된" 앱은 로컬 환경, 테스트 환경 및 프로덕션에서 동일하게 실행됩니다.

Docker는 소프트웨어 개발 및 배포에 가장 널리 사용되는 플랫폼 중 하나입니다. Docker는 소프트웨어를 "이미지"로 패키징하며, 이는 Docker 이미지에서 실행될 때 런타임에 컨테이너로 바뀝니다. 격리를 통해 개발자는 단일 호스트에서 동시에 많은 컨테이너를 실행할 수 있습니다.

Rails 개발자는 기존 애플리케이션을 컨테이너화할 때 고유한 문제에 직면합니다. 이 기사는 기능적인 Rails 앱을 컨테이너화하는 과정을 제공하고 그 과정에서 중요한 개념과 함정을 설명합니다. 이 문서는 컨테이너 또는 Docker에 대한 기본 설명이 아닙니다. 대신 프로덕션 애플리케이션을 컨테이너화할 때 개발자가 직면하는 문제에 대한 설명입니다.

전제조건

따라가는 경우 아직 고정되지 않은 Rails 애플리케이션이 필요합니다('컨테이너화'에 대한 도커별 용어). 저는 방금 설명한 모든 기능을 갖춘 사이드 프로젝트인 RailsWork를 사용할 것입니다. 런칭. Rails로 작성되고 Heroku에 배포된 작업 게시판이지만 컨테이너화되지 않습니다.

그 외에도 Docker가 설치되어 있어야 합니다. 널리 사용되는 설치 방법은 공식 웹사이트를 통해 다운로드할 수 있는 Docker Desktop을 사용하는 것입니다.

기존 Rails 애플리케이션 컨테이너화

앱이 다운로드되면 설치 프로그램을 실행합니다. 실행 후 응용 프로그램을 응용 프로그램 폴더로 끌어다 놓으라는 메시지가 표시됩니다. 그런 다음 응용 프로그램 폴더에서 앱을 실행해야 합니다. 요청한 권한 있는 권한을 부여합니다. Docker가 제대로 설치되었는지 확인하기 위한 마지막 검사로 다음을 실행하여 터미널에서 컴퓨터에서 실행 중인 컨테이너를 나열해 보십시오.

docker ps

Docker가 설치되어 있고 컨테이너를 실행하지 않는 경우 다음과 같은 헤더만 있는 빈 목록이 표시됩니다.

CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

도커파일

너무 깊이 들어가기 전에 명확한 용어부터 시작하는 것이 중요합니다.

Rails 애플리케이션이 "도커화"되면 컨테이너에서 실행됩니다. . 컨테이너는 단독으로 사용 가능하고 교체 가능하며 종종 재건됩니다.

컨테이너는 이미지에서 빌드됩니다. . 이미지는 메타데이터와 쌍을 이루는 파일 시스템의 가상 스냅샷입니다.

도커파일 이미지를 생성하는 방법을 설명하는 소스 코드입니다. Dockerfile은 종종 Dockerized 앱의 리포지토리에 포함되며 나머지 앱과 함께 버전 제어에서 추적됩니다.

Dockerfile을 만드는 것은 생각보다 쉽습니다! Docker는 무언가를 컨테이너화하는 힘든 작업을 추상화하는 특별한 구문을 제공합니다. 먼저 컨테이너화하려는 앱의 루트 디렉터리로 이동합니다. 이제 작업을 시작할 준비가 되었으므로 git을 사용하는 경우 새 분기를 만드는 것이 좋습니다. dockerize-this-app라는 이름으로 새 브랜치를 쉽게 만들 수 있습니다. 다음을 실행하여:

git checkout -b dockerize-this-app

그런 다음 Dockerfile을 만들고 Ruby 애플리케이션을 기반으로 이미지를 빌드하도록 지시합니다. 다음을 실행하여 명령줄에서 수행할 수 있습니다.

echo "FROM ruby:3.0.0" > Dockerfile

여기에서는 Dockerfile을 만들고 Ruby 컨테이너 이미지를 찾을 위치를 지정하는 줄을 추가합니다. 내 프로젝트는 Ruby 3.0.0을 사용하므로 적절한 이미지를 사용했습니다. 다른 버전의 Ruby를 사용 중이라면 문제가 되지 않습니다. Docker에는 지원되는 모든 이미지 목록이 있습니다.

다음으로 Docker에 Docker 이미지를 생성하도록 수동으로 지시합니다.

docker build -t rails_work .

여기에서 rails_work를 대체할 수 있습니다. 이미지에 원하는 이름으로. 또한 끝에 마침표를 포함해야 합니다!

이미지가 생성되었는지 확인하려면 다음을 사용하여 시스템에 이미지를 나열할 수 있습니다.

docker image list

이 이미지는 대부분 비어 있습니다. 그것은 현재 우리의 응용 프로그램을 포함하지 않습니다. Dockerfile 끝에 다음을 추가하여 앱의 코드를 추가하도록 지시할 수 있습니다.

ADD . /rails_work
WORKDIR /rails_work
RUN bundle install

이렇게 하면 애플리케이션의 파일이 복사되고 애플리케이션의 종속성이 설치됩니다. (여기서 rails_work 앱 이름으로.)

이 시점에서 명령을 다시 실행하여 이미지를 생성해야 합니다.

docker image list

여기에 문제가 있을 가능성이 있습니다. , 특히 기존 프로덕션 애플리케이션에 이 작업을 수행하는 경우. Bundler는 이미지가 사용하려는 Bundler의 버전이 Gemfile.lock을 생성한 버전과 다르다고 불평할 수 있습니다. 파일. 이 경우 두 가지 분명한 옵션이 있습니다.

  • 이미지가 사용 중인 버전을 변경합니다.
  • Gemfile.lock 삭제 전적으로. **이렇게 하면 잠금 파일이 완전히 재생성되므로 특정 버전에 필요한 모든 버전의 보석을 고정해야 합니다.

번들 설치가 여전히 실패하면 Dockerfile에 추가 설치가 필요할 수 있습니다. :

RUN apt-get update && apt-get install -y shared-mime-info

여전히 문제가 발생하는 경우 기반으로 사용할 잘못된 Ruby 이미지를 선택했을 수 있습니다. , 그래서 거기에서 조사를 시작할 가치가 있습니다.

환경 변수를 설정할 수 있는 좋은 기회입니다. :

ENV RAILS_ENV production
ENV RAILS_SERVE_STATIC_FILES true

다음으로 Rails가 기본적으로 실행되는 포트 3000을 노출하는 줄을 추가합니다.

EXPOSE 3000

마지막으로 컨테이너가 시작될 때 bash 셸을 열도록 지시합니다.

CMD ["bash"]

전체적으로 Dockerfile은 다음과 같아야 합니다(rails_work 이름이 대체됨).

FROM ruby:3.0.0

ADD . /rails_work
WORKDIR /rails_work
RUN bundle install

ENV RAILS_ENV production
ENV RAILS_SERVE_STATIC_FILES true

EXPOSE 3000
CMD ["bash"]

도커 명령 설명

가장 일반적인 Dockerfile 명령 중 일부를 완전히 이해하는 것이 확실히 도움이 될 것입니다.

  • FROM -> 기반으로 할 이미지를 정의합니다.
  • RUN -> 내부 명령을 실행합니다. 컨테이너.
  • ENV -> 환경 변수를 정의합니다.
  • WORKDIR -> 컨테이너가 사용 중인 디렉토리를 변경합니다.
  • CMD -> 컨테이너가 시작될 때 실행할 프로그램을 지정합니다.

도커 작성

Docker의 문서에 따르면 "Compose"는 여러 Docker 컨테이너로 애플리케이션을 생성(및 시작)하기 위한 도구입니다. 애플리케이션의 필수 컨테이너를 가동하는 데 필요한 모든 것이 YAML에 요약되어 있습니다. 누군가가 docker-compose up을 실행할 때 , 컨테이너가 생성됩니다! Docker-compose를 사용하면 컨테이너 구성을 선언적으로 설명할 수 있습니다.

Docker Compose 파일을 만들기 전에 빌드되는 이미지에서 제외해야 하는 파일을 Docker에 지정하는 것이 중요합니다. .dockerignore라는 파일을 만듭니다. . (마침표에 유의하세요!) 이 파일에 다음을 붙여넣습니다.

.git
.dockerignore
.env

빌드 프로세스에서 Gemfile을 유지 관리하는 경우 Gemfile.lock을 추가해야 합니다. 위의 무시에.

다음으로 docker-compose.yml이라는 파일을 만듭니다. . 여기에서 컨테이너 구성을 설명합니다. 파일 내용부터 시작하겠습니다.

version: '3.8'
services:
  db:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - postgres:/var/lib/postgresql/data
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/Rails-Docker
    ports:
      - "3000:3000"
    depends_on:
      - db
volumes:
  postgres:

이 파일은 db라는 두 개의 서비스를 생성합니다. 다른 하나는 web . db 컨테이너는 postgres용으로 미리 만들어진 이미지에서 빌드되며 POSTGRES_USER에 대한 관련 값을 대체해야 합니다. 및 POSTGRES_PASSWORD . 제작비밀을 넣지 않도록 주의해야 합니다. 이 파일에서 - 이에 대한 자세한 내용은 아래의 "비밀 관리" 섹션을 참조하십시오.

웹 컨테이너는 Dockerfile에서 빌드된 다음 IP 주소 0.0.0.0의 포트 3000에서 Rails 서버를 시작합니다. 그러면 내부 포트 3000이 실제 포트 3000에 매핑됩니다.

마지막으로 데이터를 유지하기 위한 Postgres 볼륨이 있습니다.

비밀 관리

빌드 시 인증은 프로덕션 애플리케이션에서 문제가 될 수 있습니다. 애플리케이션이 개인 저장소에서 Gem을 찾거나 데이터베이스 자격 증명을 저장하기만 하면 됩니다.

Dockerfile에 직접 있는 모든 정보는 컨테이너 이미지에 영구적으로 적용되며 일반적인 보안 문제입니다.

Rails의 자격 증명 관리자를 사용하는 경우 Docker(또는 해당 문제에 대한 모든 호스트)에 액세스 권한을 부여하는 것은 비교적 간단합니다. Docker Compose 파일에서 RAILS_MASTER_KEY를 제공하기만 하면 됩니다. 환경 변수. 주어진 작성 대상에 대해 environment 아래에 키를 지정합니다. 아직 생성하지 않은 경우 생성해야 하는 헤더입니다. 그러면 위의 docker-compose 파일은 다음과 같이 됩니다.

version: '3.8'
services:
  db:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - postgres:/var/lib/postgresql/data
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/Rails-Docker
    ports:
      - "3000:3000"
    depends_on:
      - db
    environment:
      - RAILS_MASTER_KEY=this_would_be_the_key
volumes:
  postgres:

자, 이것은 당신을 갈림길에 서게 합니다. 이 파일을 소스 제어에 커밋하고 싶지만 마스터 키나 데이터베이스 비밀번호조차 소스 제어에 의해 추적되는 것을 확실히 원하지 않습니다. , 이것은 또 다른 위험한 보안 문제가 될 수 있습니다. 지금까지 가장 좋은 해결책은 dotenv gem을 활용하여 프록시를 통해 이러한 자격 증명에 액세스하여 다른 파일에 저장하는 것입니다. 소스 제어에 의해 추적되지 않습니다.

도커화된 애플리케이션 실행

마지막으로 다음 명령을 사용하여 도커화된 애플리케이션을 실행할 수 있습니다.

docker compose up

믿거나 말거나, 그게 다야! Docker-compose를 사용하면 특히 명령줄 인수와 관련하여 컨테이너를 쉽게 실행할 수 있습니다.

실행 중인 컨테이너 목록을 보려면 다음을 실행하기만 하면 됩니다.

docker ps

Rails 컨테이너 이름이 web인 경우 , 오히려 간단한 방법으로 명령을 실행할 수 있습니다. 예를 들어 Rails 콘솔을 실행하려면 다음을 실행하기만 하면 됩니다.

docker exec -it web rails console

컨테이너 내부에 bash 셸을 원하면 대신 다음을 실행합니다.

docker exec -it web bash

여기에 나열된 것과 같은 더 많은 함정

프로덕션 환경에서 Docker화된 Rails 애플리케이션의 일반적인 문제 중 하나는 로그를 처리하는 것입니다. 장기간 컨테이너 시스템에 있으면 안 됩니다. Docker는 로그가 단순히 STDOUT으로 리디렉션되도록 제안합니다. 이는 config/application.rb에서 명시적으로 구성할 수 있습니다. .

또 다른 일반적인 문제는 메일러의 문제입니다. 애플리케이션에서 메일러를 사용하는 경우 연결 설정을 명시적으로 정의해야 합니다 . SMTP는 완벽하게 훌륭한 전달 방법이며 일반적으로 기본값으로 잘 작동하지만 컨테이너 구성과 일치하도록 서버 위치 및 기타 설정을 주의해서 지정해야 합니다.

sidekiq와 같은 작업자 또는 백그라운드 작업이 있는 경우 , 그러면 자체 컨테이너에서 실행해야 합니다.

결론

프로덕션 Rails 애플리케이션을 컨테이너화하는 것은 의심의 여지 없이 일련의 도전과제를 수반합니다. 애플리케이션이 성장함에 따라 이와 같은 마이그레이션을 어렵게 만드는 많은 종속성이 축적되었을 수 있습니다. 백그라운드 작업자, 메일러 또는 비밀 여부에 관계없이 대부분의 함정을 처리하기 위해 확립된 패턴이 있습니다. Docker와 함께 작동하는 프로덕션 애플리케이션의 초기 작업이 완료되면 향후 변경 및 배포가 용이하므로 투자 가치가 있습니다.