프로덕션 배포를 위한 Rails 애플리케이션 도커화

수년 동안 수동 도구를 사용하여 Ruby on Rails 애플리케이션을 배포한 후 몇 년 전에 Docker 컨테이너를 사용하도록 프로덕션 배포 전략을 변경했으며 이는 훌륭한 결정이었습니다!

이 튜토리얼은 새로운(또는 기존) Rails 애플리케이션을 고정화하려는 초보자를 위한 것입니다.

ℹ️ You can download all files on my Github repository.




목차


  • Why dockerize my Rails application?

  • Starting with a basic Rails application
  • The setup


  • Let's start!
  • The config/database.yml file
  • The Dockerfile
  • The .dockerignore
  • Building the container


  • Going production!
  • The Docker Compose file
  • Starting up our application
  • Acessing the Rails console

  • Updating the containers
  • Configure your web server
  • Final tip!

  • Rails 애플리케이션을 도커화하는 이유는 무엇입니까?

    Turn you Rails application into docker containers for production deployment can speed up your deployment, prevent errors and make it much easier to move from one service provider to another. It made my life easier (and I bet it can make yours too!).

    Once in a container, all dependencies will always be installed and the system already configured to run an optimized version of you application.

    It's also easy to update your container, run tests, use CI/CD and automatically deploy new version.

    기본 Rails 애플리케이션으로 시작하기

    For demonstration purposes, this Rails application is a simple contact list running Rails 6.1. The user can add, view, edit and delete records from the database. All records are saved on a local PostgreSQL instance.

    설정

    Everything is setup on the local machine. Rails connects to PostgreSQL through port 5432 and serves the application to browsers through port 3000.



    이 자습서를 따르기 위해 이미 Rails 애플리케이션이 작동하고 실행 중이라고 가정합니다. 그렇지 않은 경우 테스트에 the tutorial application을 사용할 수 있습니다.

    실행 중인 애플리케이션의 스크린샷을 따릅니다.



    시작하자!

    There are few steps to build a container to run our application.

    1. Adjust your database connection configuration.
    2. Write a dockerfile and build the container.
    3. Upload your container to any could provider (free and optional).
    4. Write a Docker Compose file to execute your application on production.

    config/database.yml 파일

    This is the basic Rails configuration to connect the application to the datbase. It assumes there's a local instance of PostgreSQL running with username and password configured as below.

    default: &default
      adapter: postgresql
      port: 5432
      pool: 5
      timeout: 5000
      host: localhost
      username: postgres
      password: postgres
    
    development:
      <<: *default
      database: devel_db
    
    test:
      <<: *default
      database: test_db
    
    production:
      <<: *default
      database: production_db
    

    As you can see, all database connection configuration is fixed to the current environment. This can work for local environments, but as a good practice we should change them to environment variables, so we can adjust easily for any new environment we publish our app.

    Let's change host , username and password for now. The others settings can also be changed, but I don't want this tutorial to be too complex 😉

    host: <%= ENV['DB_HOST'] || 'localhost' %>
    username: <%= ENV['DB_USERNAME'] || 'postgres' %>
    password: <%= ENV['DB_PASSWORD'] || 'postgres' %>
    

    ⚠️ Notice that we set default values for everything.

    도커파일

    The next step is create a file called Dockerfile on the root path of your application. This file will instruct docker on how to build the application based on a image you choose.

    I decided to use the image ruby:2.7.6-bullseye because it's based on Debian 11 (Bullseye) and I like (and I'm used to) this distribuition.

    FROM ruby:2.7.6
    
    # Directory where the app will be installed on the container
    WORKDIR /app
    
    # Install NodeJS 14 repository
    RUN curl -fsSL https://deb.nodesource.com/setup_14.x | bash -
    
    # Update the system and install NodeJS
    RUN apt-get update && apt-get -y install \
      nodejs \
      vim \
      && rm -rf /var/lib/apt/lists/*
    
    # Install ruby gems
    COPY Gemfile Gemfile.lock ./
    RUN bundle install
    
    # Install Yarn globally
    RUN npm install -g yarn
    
    # Run `yarn install`
    COPY package.json yarn.lock ./
    RUN yarn install
    
    # Copy the application file to the container
    COPY . .
    
    # Pre-compile assets for production
    RUN RAILS_ENV=production bundle exec rails assets:precompile
    
    # Sets the default command that will run when the container starts
    CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]
    

    ℹ️ More information of Dockerfile can be found on this link.



    .dockerignore 파일

    There are files and folders that we do not want to be copied to our docker container because they are not relevant to the application or they will be generated when the container is created. They are build folders, temporary files, log, etc.

    Create a .dockerignore file on your project root folder and add these lines:

    node_modules/
    log/
    tmp/
    

    컨테이너 빌드

    Now it's time to build our application container.

    ⚠️ IMPORTANT: The tag attribute is the name of the container. Be sure to change it to your Doker Hub repository name, or use any name if you do not intent to push it to a cloud.

    docker build . --tag fshayani/dockerizing_rails_application:latest
    

    After the container is built successfully, we will upload it to Docker Hub. This way I can download it automatically on my production server.

    ℹ️ This is a optional step. You can skip this step if you intent to build the container and use it on the same machine.

    docker push fshayani/dockerizing_rails_application:latest
    

    제작 들어갑니다!

    Now that we have built our app container (and maybe pushed it to a cloud; did you?), it's time to move to the production server and deploy that application!

    We need tell Docker how to pull and start the container and this can be done easly with docker compose .

    ℹ️ There are others technologies to deploy containers in production instead of Docker Compose, like Kubernetes, Docker Swarm, AWS ECS, etc; but that's not the scope of this tutorial.

    Docker Compose 파일

    Create a docker-compose.yml file on production server. It can be placed anywhere, but be organized! 😉

    services:
      app: # That's the name of our application container
        image: fshayani/dockerizing_rails_application:latest # The container Docker will use
        ports:
         - 3000:3000 # Map localhost:3000 to the container's port 3000
        environment:
          - DB_HOST=db # The name of our PostgreSQL container
          - DB_USERNAME=postgres # PostgreSQL credentials
          - DB_PASSWORD=postgres
          - RAILS_ENV=production # We are on Production now!
          - RAILS_SERVE_STATIC_FILES=true # Assets were already built by Dockerfile ;)
          - RAILS_LOG_TO_STDOUT=true # So we can see Rails logs with `docker compose logs` command
          - RAILS_MASTER_KEY=my_ultra_top_secret_master_key!! # Use you master key. There are better ways to keep this secret.
        depends_on:
          - db # Will start the container `db` before
    
      db:
        image: postgres:14
        environment:
          - POSTGRES_USER=postgres # Will create a instance of PostgreSQL with this credentials
          - POSTGRES_PASSWORD=postgres
        volumes:
          - postgres:/var/lib/postgresql/data # Map PostgreSQL data to a persistant volume called `postgres`
    
    volumes:
      postgres: # Create a persistant volume on local machine, so we do not loose our DB on restarts
    
    

    애플리케이션 시작하기

    Now that everything is ready, let's start our application on the production server!

    ⚠️ ATTENTION: If that's our first time to run the application on the server,
    probably your database will be empty. You have two options: dump and restore
    your database on the db container or create a new from scratch running this command first:
    docker compose run --rm app bundle exec rails db:setup

    docker compose up
    
    and open your browser on http://localhost:3000 😄 응용 프로그램이 실행되는 것을 볼 수 있습니다!

    ℹ️ TIP: Add the flag -d to the command to run it on the background.



    Rails 콘솔에 액세스

    With Docker Compose, we can interact with our container and run any command on it (including bash if necessary).

    docker compose exec app bundle exec rails console
    

    컨테이너 업데이트

    When you make a new version of your application and want to deploy it to the production, all you need to do is:

    1. Build the new image.
    2. Push it to the cloud again.
    3. Pull it on the production server the production server ( docker compose pull ).
    4. Rebuild your docker compose stack ( docker compose down; docker compose up ).

    웹 서버 구성

    Now that you application is deployed on the production server, you will have to configure any web server (Apache, Nginx, etc) to reverse proxy any calls to your domain to the port 3000 on localhost .

    That's a topic for another post ;)

    마지막 팁!

    There a application called Watchtower Docker 허브에 업로드하는 새 컨테이너를 자동으로 가져오고 자동으로 가져와 도커를 다시 빌드할 수 있습니다. 스택을 구성합니다. 한번 보세요 ;)

    좋은 웹페이지 즐겨찾기