Docker with rails app
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] ...
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/
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
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