Docker with rails app
Bài đăng này đã không được cập nhật trong 7 năm
Yêu cầu
Bạn cần phải cài đặt Docker, Docker có thể chạy trên hầu hết Linux distribution và có một số tool để chạy trên OSX cũng như trên windows. Bạn có thể cài docker thông qua các link sau :
- [Linux] https://docs.docker.com/linux/started/
- [Mac] http://docs.docker.com/mac/started/
- [Windows] http://docs.docker.com/windows/started/
Tạo một ứng dụng Rails mới
Ta sẽ tạo ra một Rails project mà không cần đến việc cài đặt Ruby bởi Rails Docker image đã hỗ trợ
docker run -it --rm --user "$(id -u):$(id -g)" \
-v "$PWD":/usr/src/app -w /usr/src/app rails:4 rails new --skip-bundle drkiq
Đầu tiên docker sẽ tìm images rails:4 trên local nếu không có nó sẽ download về. Sẽ mất một khoảng thời gian để nó download xong.
-v "$PWD":/usr/src/app -w /usr/src/app
Đoạn này sẽ connect local woking directory với /usr/src/app
trong docker image. Điều này cho phép container run Rails scaffold
--user
đảm bảo việc bạn có full quyền trên các file đã tạo, không phải là root.
Sửa Gemfile
gem 'unicorn', '~> 4.9'
gem 'pg', '~> 0.18.3'
gem 'sidekiq', '~> 4.0.1'
gem 'redis-rails', '~> 4.0.0'
Sửa file config/database.yml
development:
url: <%= ENV['DATABASE_URL'].gsub('?', '_development?') %>
test:
url: <%= ENV['DATABASE_URL'].gsub('?', '_test?') %>
staging:
url: <%= ENV['DATABASE_URL'].gsub('?', '_staging?') %>
production:
url: <%= ENV['DATABASE_URL'].gsub('?', '_production?') %>
Sửa config/screts.yml file
---
development: &default
secret_key_base: <%= ENV['SECRET_TOKEN'] %>
test:
<<: *default
staging:
<<: *default
production:
<<: *default
sửa file config/application.rb
config.log_level = :debug
config.log_tags = [:subdomain, :uuid]
config.logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
# vì chúng ta sử dụng redis cho sidekiq, nên ta cũng sử redis để lưu cacche.
config.cache_store = :redis_store, ENV['CACHE_URL'],
{ namespace: 'drkiq::cache' }
# config để active job biết ta dùng sidekiq
config.active_job.queue_adapter = :sidekiq
Tạo file unicon
worker_processes ENV['WORKER_PROCESSES'].to_i
listen ENV['LISTEN_ON']
# set timeout khi request page
timeout 30
preload_app true
GC.respond_to?(:copy_on_write_friendly=) && GC.copy_on_write_friendly = true
# fast LAN.
check_client_connection false
before_fork do |server, worker|
defined?(ActiveRecord::Base) && ActiveRecord::Base.connection.disconnect!
old_pid = "#{server.config[:pid]}.oldbin"
if old_pid != server.pid
begin
sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
Process.kill(sig, File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
end
end
end
after_fork do |server, worker|
defined?(ActiveRecord::Base) && ActiveRecord::Base.establish_connection
end
Tạo file config cho sidekiq
#config/initializers/sidekiq.rb
sidekiq_config = { url: ENV['JOB_WORKER_URL'] }
Sidekiq.configure_server do |config|
config.redis = sidekiq_config
end
Sidekiq.configure_client do |config|
config.redis = sidekiq_config
end
Tạo file env
#.drkiq.env
# để lấy token chạy câu lệnh sau`rake secret`
SECRET_TOKEN=900bb6bbff924de7a046532769196ec79512b749ed2994dda391528d72ed6a97a0d9ce1d649e9e8e2b2574561340873e9926bd3044d8863d3537276568b0a7ff
WORKER_PROCESSES=1
LISTEN_ON=0.0.0.0:8000
CACHE_URL=redis://redis:6379/0
JOB_WORKER_URL=redis://redis:6379/0
Dockerizing Your Rails Application
Tạo Dockerfile file
FROM ruby:2.2.3-slim
# Install dependencies:
# - build-essential: To ensure certain gems can be compiled
# - nodejs: Compile assets
# - libpq-dev: Communicate with postgres through the postgres gem
# - postgresql-client-9.4: In case you want to talk directly to postgres
RUN apt-get update && apt-get install -qq -y build-essential nodejs libpq-dev postgresql-client-9.4 --fix-missing --no-install-recommends
ENV INSTALL_PATH /drkiq
RUN mkdir -p $INSTALL_PATH
# Gán context của câu lệnh sẽ được chạy trên Docker
WORKDIR $INSTALL_PATH
# đảm bảo các gem được cached và chỉ update khi chúng thay đổi, giảm thời gian build khi gem không thay đổi
COPY Gemfile Gemfile
RUN bundle install
# Copy in the application code from your work station at the current directory
# over to the working directory.
COPY . .
# Cung cấp dummy data cho Rails
RUN bundle exec rake RAILS_ENV=production DATABASE_URL=postgresql://user:pass@127.0.0.1/dbname SECRET_TOKEN=pickasecuretoken assets:precompile
# Expose a volume so that nginx will be able to read in assets in production.
VOLUME ["$INSTALL_PATH/public"]
# start Unicorn server.
CMD bundle exec unicorn -c config/unicorn.rb
Tạo dockerignore file
dockerignore
.git
.dockerignore
Gemfile.lock
Tạo Docker Compose Configuration File
#docker-compose.yml
postgres:
image: postgres:9.4.5
environment:
POSTGRES_USER: user_name
POSTGRES_PASSWORD: yourpassword
ports:
- '5432:5432'
volumes:
- drkiq-postgres:/var/lib/postgresql/data
redis:
image: redis:3.0.5
ports:
- '6379:6379'
volumes:
- drkiq-redis:/var/lib/redis/data
drkiq:
build: .
links:
- postgres
- redis
volumes:
- .:/e-elearning
ports:
- '8000:8000'
env_file:
- .drkiq.env
sidekiq:
build: .
command: bundle exec sidekiq -C config/sidekiq.yml
links:
- postgres
- redis
volumes:
- .:/drkiq
env_file:
- .drkiq.env
Docker Compose cho phép bạn chạy một hoặc nhiều Docker container một cách dễ dàng. Bạn có thể định nghĩa mọi thứ trong YAML file.
Tạo Volumes
Trong docker-compose.yml ta đang tham chiếu tới volumn, nhưng chúng chưa được tạo ra. Chạy lệnh sau để create volumn
docker volume create --name drkiq-postgres
docker volume create --name drkiq-redis
Khi data được save vào db PostgreSQL hay Redis, nó cũng được lưu lại vào trong những volumn này ở workstation, nên bạn sẽ không lo việc mất data khi restart service bởi vì Docker container là staless
Chạy tất cả mọi thứ
docker-compose up
Lần đầu khi chạy câu lệnh này sẽ tốn thơi gian bởi nó cẩn phải pull tất cả các Docker images mà ứng dụng cần về
Khởi tạoi DB
# OSX/Windows users will want to remove --user "$(id -u):$(id -g)"
docker-compose run --user "$(id -u):$(id -g)" drkiq rake db:reset
docker-compose run --user "$(id -u):$(id -g)" drkiq rake db:migrate
Trong lúc chạy lệnh trên có thể sẽ thông báo command khởi động Redis và PostgreSQL một cách tự động, Điều này là vì khi bạn định docker-compose nó sẽ khởi động các dependencies
Chạy lại docker-compose lần 2
docker-compose up
sau đó access vào localhost:8000
nó sẽ mở rails introduction page
Nguồn tham khảo
https://semaphoreci.com/community/tutorials/dockerizing-a-ruby-on-rails-application
All rights reserved