关于在此过程中遇到的坑先不说了…… 新人仅作记录,请批评指正。
首先要感谢 @saiga 在 用 docker-compose 部署 Rails , 静态资源加载不了,浏览器显示 404 贴中指点迷津。 看那个贴子,你就知道我有多新啦……
限于篇幅,还有一篇: 《长文慎入:将 Rails 程序部署到 Docker 容器中(Q&A)》。
在整个过程中,基本上按照下面这篇文章实现的,但中间还是有许多不一样的问题。 Docker for an Existing Rails Application
如果你对 Docker 技术不了解,可以去 Docker 官网或 Google 检索一下,这样有助于阅读本文。
网站托管的技术实现,大概经历这样几种方式或阶段:
1 放到实体的计算机(服务器) 2 放到虚拟的计算机当中,将硬件虚拟化(VM) 3 放到容器当中,将所需服务虚拟化(Docker )
而 Docker 最大的好处则是:让开发环境与生产环境一致 。
而 Docker 的原意为「码头工人」,其实是很形像的说法。你需要什么样的程序或服务,Docker 把你搬过来就可以了。
docker-compose
将多个容器串起来,各司其职,协同服务。Nginx
在最前面解析请求并处理静态资源; Unicorn
位于 Nginx 于 Rails 程序之间,用于处理动态的请求;最后面还有一个数据存储的 Postgresapp
:存放 Rails
和 Unicorn
程序web
:存放 nginx
,负责解析各种外部请求,处理静态的资源
rake assets:precompile
生成在 public/assets
中的内容db
:即数据存储,使用 Postgres我找了一张图,大概是这样(后面还少了一个 db 的):
$ git clone https://github.com/2liu/eshop
代码会存在 eshop 文件夹中
在上述 eshop 目录中创建一个名为 Dockerfile
的文件,用于创建 Rails 环境
1 # 使用安装了最少的软件的镜像,也有使用 ruby:alpine
2 FROM ruby:2.3.3-slim
3
4 # Ruby 使用的是 Debian 系统
5 # 刷新 debian 的软件管理源,否则,慢得让人抓狂
6 RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak && \
7 echo "deb http://mirrors.163.com/debian/ jessie main non-free contrib" >/etc/apt/sources.list && \
8 echo "deb http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib" >>/etc/apt/sources.list && \
9 echo "deb-src http://mirrors.163.com/debian/ jessie main non-free contrib" >>/etc/apt/sources.list && \
10 echo "deb-src http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib" >>/etc/apt/sources.list
12
13 # 安装必要套件
14 RUN apt-get update -qq && apt-get install -y build-essential
15
16 # 安装 postgres
17 RUN apt-get install -y libpq-dev
18 # 安装 sqlite3,这个用于test,development
19 RUN apt-get install -y libsqlite3-dev
20
21 # 安装 JS runtime,一定要装
22 RUN apt-get install -y nodejs
23
24 # 用于图片上传
25 RUN apt-get install -y imagemagick
26 # 方便进到容器编辑、查看代码
27 RUN apt-get install -y vim
28
29 # 设置环境变量,即在后面可以用 $RAILS_ROOT
30 # 来指代容器中的 rails 程序放的目录
31 ENV RAILS_ROOT /var/www/eshop
32
33 # 创建 rails 程序目录和程序运行所需要的 pids 的目录
34 RUN mkdir -p $RAILS_ROOT/tmp/pids
35
36 # 设置容器里的工作目录
37 WORKDIR $RAILS_ROOT
38
39 # 备份 Gemfile 及 lock到容器的工作目录中
40 # 当Gemfile 没有改变时,省略下面的 bundle install
41 COPY Gemfile Gemfile
42 COPY Gemfile.lock Gemfile.lock
43
44 # 安装 Rails 环境
45 RUN gem install bundler
46 RUN bundle install
47
48 # 将 Dockerfile 目录下所有内容复制到容器工作目录
49 COPY . .
50
51 # 比较重要的一步,对静态资源进行 precompile
52 RUN bundle exec rake RAILS_ENV=$RAILS_ENV DATABASE_URL=postgresql://$POSTGRES_USER:[email protected]/$POSTGRES_PRODUCT_DB assets:precompile
53
54 # 当容器启动时运行的脚本,即 unicorn
55 CMD ["config/containers/app_cmd.sh"]
容器启动之后,unicorn 会启动,启动时加载预设的配置文件和环境变量
app_cmd.sh
在 config
下创建 containers
目录,也有直接放在 config
中的
但这种方式将所有与容器相关的配置文件都放在一个文件夹当中,更直观
config/containers/app_cmd.sh
#!/usr/bin/env bash
exec bundle exec unicorn -c config/containers/unicorn.rb -E $RAILS_ENV;
保存好该文件之后,修改文件属性为可执行
$ chmod 775 app_cmd.sh
Gemfile
gem ‘unicorn'
这个配置文件我没有改动,直接拿来就用 所以注释,就直接用原文了。 文件:config/containers/unicorn.rb
# Where our application lives. $RAILS_ROOT is defined in our Dockerfile.
app_path = ENV['RAILS_ROOT']
# Set the server's working directory
working_directory app_path
# Define where Unicorn should write its PID file
pid "#{app_path}/tmp/pids/unicorn.pid"
# Bind Unicorn to the container's default route, at port 3000
listen "0.0.0.0:3000"
# Define where Unicorn should write its log files
stderr_path "#{app_path}/log/unicorn.stderr.log"
stdout_path "#{app_path}/log/unicorn.stdout.log"
# Define the number of workers Unicorn should spin up.
# A new Rails app just needs one. You would scale this
# higher in the future once your app starts getting traffic.
# See https://unicorn.bogomips.org/TUNING.html
worker_processes 1
# Make sure we use the correct Gemfile on restarts
before_exec do |server|
ENV['BUNDLE_GEMFILE'] = "#{app_path}/Gemfile"
end
# Speeds up your workers.
# See https://unicorn.bogomips.org/TUNING.html
preload_app true
#
# Below we define how our workers should be spun up.
# See https://unicorn.bogomips.org/Unicorn/Configurator.html
#
before_fork do |server, worker|
# the following is highly recomended for Rails + "preload_app true"
# as there's no need for the master process to hold a connection
if defined?(ActiveRecord::Base)
ActiveRecord::Base.connection.disconnect!
end
# Before forking, kill the master process that belongs to the .oldbin PID.
# This enables 0 downtime deploys.
old_pid = "#{server.config[:pid]}.oldbin"
if File.exists?(old_pid) && server.pid != old_pid
begin
Process.kill("QUIT", File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
# someone else did our job for us
end
end
end
after_fork do |server, worker|
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
end
end
原文说,此时就可以运行下面命令,
$ docker build -t eshop_app .
(注意最后有一个 .
表示从 Dockerfile 所在目录开始。
创建 Rails 程序的镜像了,虽然不能运行,但可以通过 docker images
查看。
但实际操作过程中,都是设置好,最后执行一步 docker-compose build
完事。
所以说,这一步可以不执行。
Nginx 在另一个容器里,也需要创建一个 Dockerfile
config/containers/Dockerfile-nginx
1 # build from the official Nginx image
2 FROM nginx
3
4 # 更新 163 源
5 RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak && \
6 echo "deb http://mirrors.163.com/debian/ jessie main non-free contrib" >/etc/apt/sources.list && \
7 echo "deb http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib" >>/etc/apt/sources.list && \
8 echo "deb-src http://mirrors.163.com/debian/ jessie main non-free contrib" >>/etc/apt/sources.list && \
9 echo "deb-src http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib" >>/etc/apt/sources.list
10
11
12 # install essential Linux packages
13 RUN apt-get update -qq && apt-get -y install apache2-utils vim
14
15 # establish where Nginx should look for files
16 ENV RAILS_ROOT /var/www/eshop
17
18 # Set our working directory inside the image
19 WORKDIR $RAILS_ROOT
20
21 # create log directory
22 RUN mkdir log
23
24 # copy over static assets
25 # 这一步实做时,复制是复制到 nginx 容器中的 public 文件夹下
26 # 但静态资料却显示不了,最后在 docker-compose 文件中设置了 volumes 才可以
27 # 可能是哪个地方我没有设置正确。
28 COPY public public/
29
30 # copy our Nginx config template
31 COPY config/containers/nginx.conf /tmp/eshop.nginx
32
33 # substitute variable references in the Nginx config template for real values from the environment
34 # put the final config in its place
35 RUN envsubst '$RAILS_ROOT' < /tmp/eshop.nginx > /etc/nginx/conf.d/default.conf
36
37 # Use the "exec" form of CMD so Nginx shuts down gracefully on SIGTERM (i.e. `docker stop`)
38 CMD [ "nginx", "-g", "daemon off;" ]
有了 nginx 镜像,我们还需要配置一下 Nginx
config/containers/nginx.conf
# define our application server
# Nginx 处理不了由 Rails 产生的动态的请求,所以我们要告诉它如何将这些请求传递给 Unicorn。
# 这里我们将它指向将会在后面 docker-compose 中定义的 app 这个服务的 3000 端口
# 其实就是 Unicorn
upstream unicorn {
server app:3000;
}
# 处理对www.xxx.com 的网址请求
server {
# default - 如果请求的网址没有找到匹配的 sever 模式,就用这个 server
# deferred - 在 Linux 上用,为了优化性能
listen 80 default deferred;
server_name www.xxx.com;
# 静态文件就保存在这里
root $RAILS_ROOT/public;
index index.html;
# 定义日志文件保存位置
access_log $RAILS_ROOT/log/nginx.access.log;
error_log $RAILS_ROOT/log/nginx.error.log;
# 上面的 server_name 是处理对域名的请求
# location - 负责处理对特定文件或文件夹的请求
# 禁止诸如 .env .git 之类的文件或目录被访问
location ~ /\. {
deny all;
}
# 禁止访问 .rb .log 文件
location ~* ^.+\.(rb|log)$ {
deny all;
}
# serve static (compiled) assets directly if they exist (for rails production)
# 这里其实是个正则表达式,
# 匹处理类似网址: `domain.com/assets/aaaa.jpg` 这样的请求
# 加上了 uploads
location ~ ^/(assets|images|javascripts|stylesheets|swfs|system|uploads)/ {
# $uri : 地址栏里输入,abc.com/def/hig.html,则 $uri 为 `/def`
# @rails : 在后面定义的 named location
# 如果地址匹配进来,则先按 $uri 处理,若没有找到,则交给 @rails 处理
try_files $uri @rails;
# 关闭访问记录
access_log off;
# `gzip_static` :设置为 `on` ,在处理压缩之前,先查找已经预压缩的文件(.gz)
# 避免每次对同一个文件进行重复的压缩处理
gzip_static on; # to serve pre-gzipped version
# 对请求进行缓存,并设为最长失效日期
# 这种做法已过时,放在这里是为了兼容性
# 替代的做法就是下面的设置 `Cache-Control` 头
expires max;
# public 对每个用户有效; private 对当前用户有效
add_header Cache-Control public;
# Some browsers still send conditional-GET requests if there's a
# Last-Modified header or an ETag header even if they haven't
# reached the expiry date sent in the Expires header.
add_header Last-Modified "";
add_header ETag "";
break;
}
# send non-static file requests to the app server
location / {
try_files $uri @rails;
}
location @rails {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
# 阻止 Nginx 做其它别的重定向请求
proxy_redirect off;
# 将所有不符合上面的 server_name 或 location 的请求全部发送到这里
# 交由最上面定义的 `unicorn` 这个 upstream 服务来处理
# 而 unicorn 又交给我们下面会定义的 app 来处理
proxy_pass http://unicorn;
}
}
database.yml
这个不需要过多的配置
所以,我们直接使用 postgres: 9.4.5
这个镜像文件,所以不用创建 Dockerfile 文件了。
但我们需要设置 database.yml
文件
config/database.yml
default: &default
adapter: postgresql
host: db
port: 5432
username: postgres
password: <%= ENV['POSTGRES_PASSWORD'] %>
timeout: 5000
test:
<<: *default
database: eshop_dd_test
development:
<<: *default
database: eshop_dd_development
production:
<<: *default
database: eshop_dd_production
整个文件还是比较简单的,就说一下 password: <%= ENV['POSTGRES_PASSWORD'] %>
的设置
这里将密码保存到环境变量当中,
而环境变量的设置方法既可以在 Shell 中 通过 export ENV_VAR=value
来设置
又可以将环境变量写到 .env 文件中,这也是我采用的方法
$ vi Gemfile
添加
group :production do
gem 'pg'
end
.env
文件出于安全因素的考虑,所以建议将隐密信息,如数据库用户名、密码等保存到环境变量中。
采用的方法是使用了 dotenv-rails
这个 Gem
gem ‘dotenv-rails’
config/application.rb
中 Bundler.require(*Rails.groups)
下面添加一句:Dotenv::Railtie.load
.env
文件(注意变量名大写,=
号两边没有空格)RAILS_ENV=production
APP_HOME=/var/www/eshop
SECRET_KEY_BASE=long_long_code
OSTGRES_USER=postgres
POSTGRES_PASSWORD=keep_secret_ps
…...
别的还好,可以直接输入,就是那个 secret_key_base
这个可以通过 RAILS_ENV=production rake secret
来生成
而我们后面要用到 docker-compose
,那么可以这样运行
docker-compose exec -e RAILS_ENV=production app rake secret
(不太确定是不是条命令了)
生成是一个长长的字符串,复制,粘贴到,本来是要放在 config/secrets.yml
中
但 在 production
那一块提示,要放到环境变量中
也就是上面的 .evn
文件中
.dockerignore
.git
.env
.dockerignore
.gitignore
.env
public/
到目前为止,上面三个容器还是各自为战的,而我们要用 将它们合体,从而超强变身
注意 yml 文件是严格缩进的,一定要注意层级关系
且 yml
或 yaml
(好像推荐用这个)禁止用 tab 键缩进,就是用两个空格
与 Dockerfile 一样,都在根目录下 docker-compose.yml
version: '2'
services:
app:
build: .
env_file: .env
environment:
RAILS_ENV: $RAILS_ENV
# 在 version : 2 中这一项,好像是可以去掉的,下同
links:
- db
expose:
- "3000"
# 这一步很重要,让宿主的程序目录加载到容器里的 `/var/www/eshop`
# 这样当容器运行后,我们修改代码后,不需要重新 build
# 只需要停止再启动 `docker-compose` 即可。
volumes:
- .:/var/www/eshop
db:
image: postgres:9.4.5
volumes:
- eshop-postgres:/var/lib/postgresql/data
web:
build:
context: .
dockerfile: config/containers/Dockerfile-nginx
links:
- app
ports:
- "80:80"
volumes_from:
- app
# 在 version 2 中 命名的 volume 要放到 顶级的 volumes 下
volumes:
eshop-postgres:
docker-compose build
就可以创建相关容
config/routes.rb
中的 devise_for :users
注释掉build
结束之后,再打开docker-compose run app rake db:create
docker-compose run app rake db:migrate
docker-compose run app rake db:seed
docker-compose up -d
-d
选项,会显示更多信息docker-compose stop
,不带 -d
时,按 Ctrl + Cdocker-compose ps
来查看容器运行状态运行时状态
$ dc ps
Name Command State Ports
------------------------------------------------------------------------------------
eshopdd_app_1 config/containers/app_cmd.sh Up 3000/tcp
eshopdd_db_1 /docker-entrypoint.sh postgres Up 5432/tcp
eshopdd_web_1 nginx -g daemon off; Up 443/tcp, 0.0.0.0:80->80/tcp
docker build -t app_name_app .
: 创建带标签的镜像docker exec -it container_name /bin/bash
:进入容器里面docker-compose run service_name env
:查看服务容器的环境变量进到 容器里使用命令:
docker exec -it container_name /bin/bash
Learn to use Docker in Development - Part 1
有两种方法:
docker-compose
的 shell 下运行export ENV_VAR=value
.env
文件中
docker-compose
的 shell 下创建 .env
文件export ENV_VAR=value
存疑
### 使用 环境变量docker run -d -e POSTGRES_USER=$POSTGRES_USER -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD —net-blog —name db postgres
在 Dockerfile 中第 4 行最后,添加 libsqilte3-dev
$ docker-compose run app rake db:create
Starting eshop_db_1
rake aborted!
Bundler::GemRequireError: There was an error while trying to load the gem 'uglifier'.
Gem Load Error is: Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes.
解决:
in Ubuntu: apt-get install nodejs
In OSX : brew install nodejs
gem 'pg'
to your Gemfile$ vi Gemfile
添加
group :production do
gem 'pg'
end
Devise.secret_key was not set. Please add the following to your Devise initializer:
config.secret_key = '9c8abd0f6a9257625ad384ce95467d106811141bf6792345ab06c45028dfb4520f2184a3ef1a4c2aa46882e5f2f810656899a715b6e91b759cabebd88a3f3b10'
解决: 在 stackoverflow 上看到一句: devise-secret-key
原因应该是,在创建 devise model 之前,而在
config/routes.rb
中使用了devise_for :users
将它注释掉,再重新生成就可以了。
经过一番折腾后,终于可以 看到页面了,只是有两个问题:一个是图片找不到,二是 CSS 没有加载
查 Chrome Network 发现:Status Code:404 Not Found
搜索了一下,才知道,在 development 下没有关系的,而到 production 之前要先将 assets 中的资源 precompile,它会保存到 public/assets 下,可供 rails 读取。 因为 在 production 下,是不会自动处理静态资源的。
执行 docker exec -it appname_app_1 /bin/bash
后 进入 app 的容器中
再执行 rake assets:precompile
没有错误报出,查看 public 中 assets 也看到有资料生成
但 还是老样子。
再找原因,后来想起,可能在生成 web 容器时就将 assets 执行 precompile 了,而这些生成的资料会被复制放到 web 容器中。 而我在 app 容器执行,但生成的资料是放在 app 容器里了,没有在 web 容器里,所以要重新生成,或拷到 web 容器里。
Precompiling Assets
$ RAILS_ENV=production bin/rails assets:precompile
http://guides.rubyonrails.org/asset_pipeline.html#in-production
Development workflow
http://blog.carbonfive.com/2015/03/17/docker-rails-docker-compose-together-in-your-development-workflow/ When you want to run: With Docker Compose, you would run: bundle install docker-compose run web bundle install rails s docker-compose run web rails s rspec spec/path/to/spec.rb docker-compose run web rspec spec/path/to/spec.rb RAILS_ENV=test rake db:create docker-compose run -e RAILS_ENV=test web rake db:create tail -f log/development.log docker-compose run web tail -f log/development.log
FROM ruby:2.2.0
RUN apt-get update -qq && apt-get install -y build-essential nodejs npm nodejs-legacy mysql-client vim
RUN npm install -g phantomjs
RUN mkdir /myapp
WORKDIR /tmp
COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock
RUN bundle install
ADD . /myapp
WORKDIR /myapp
RUN RAILS_ENV=production bundle exec rake assets:precompile --trace
CMD ["rails","server","-b",”0.0.0.0"]
As the Ruby image itself is based on a
Ruby image 是基于 Debian 镜像的,所以我们使用 apt-get
来安装软件
而更新源,则可以修改 相关的源
FROM dockerfile/ubuntu
查了一下,发现并不是 Debian,而实际情况用下面的方法也是有效的
# 更新源
RUN echo "deb http://mirrors.163.com/debian/ jessie main non-free contrib" > /etc/apt/sources.list
#更新apt-get源 使用163的源
RUN mv /etc/apt/sources.list /etc/apt/sources.list.bak && \
echo "deb http://mirrors.163.com/debian/ jessie main non-free contrib" >/etc/apt/sources.list && \
echo "deb http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib" >>/etc/apt/sources.list && \
echo "deb-src http://mirrors.163.com/debian/ jessie main non-free contrib" >>/etc/apt/sources.list && \
echo "deb-src http://mirrors.163.com/debian/ jessie-proposed-updates main non-free contrib" >>/etc/apt/sources.list
http://mirrors.163.com/.help/debian.html
而 web 容器呢,又不一样了
查看一下 nginx Dockerfile
可以看到 FROM dockerfile/ubuntu
所以:
http://www.cnblogs.com/52fhy/p/5836429.html
在 docker-compose.yml
中添加 volumes 代码如下:
app:
build: .
volumes:
- .:$RAILS_ROOT
就报出:ERROR: for app Invalid volume spec ".": Invalid volume destination path: '.' mount path must be absolute.
同时还报出:
WARNING: The RAILS_ROOT variable is not set. Defaulting to a blank string.
后来 将代码 改成:
app:
build: .
volumes:
- .:/var/www/app_name
就不再报错。 docker-compose build
执行也无错。
就是 docker-compose up
时报错,提示:
app_1 | bundler: failed to load command: unicorn (/usr/local/bundle/bin/unicorn)
app_1 | ArgumentError: directory for pid=/var/www/app_name/tmp/pids/unicorn.pid not writable
这又 是因为 在 Rails 的 Dockerfile 有这样一句:
RUN mkdir -p $RAILS_ROOT/tmp/pids
所以 这样是不可行的。
后来,又 仔细 看了一下文章 的最后 有个 docker-compose.override.yml
app:
# map our application source code, in full, to the application root of our container
volumes:
- .:/var/www/docker_example
web:
# use whatever volumes are configured for the app container
volumes_from:
- app
http://stackoverflow.com/a/14854266/4455426 能否用此方法,先给 nginx 容器添加一个 volume,而后再把指定 Just solved the same problem. In my case Ryan's answer was not helpful. Bratsche pointed to the Rails Guides, unfortunately this didn't work for me too. However the resource was helpful. So I took Nginx configuration from there and added the root directive, pointing to the public directory. Without this it doesn't work.
# serve static assets
location ~ ^/assets/ {
expires 1y;
root /path/to/my/cool_project/public;
add_header Cache-Control public;
add_header ETag "";
break;
}
Restart nginx, and that's it.
复制文件从容器到主机
In order to copy a file from a container to the host, you can use the command
docker cp :/file/path/within/container /host/path/target
Here's a handy way to get at your latest container if you're simply using docker for a temp Linux environment:
docker ps -alq.
location ~ ^/(assets)/ { http://pothibo.com/2015/10/rails-in-production-with-coreos
查看容器内的环境变量
docker-compose run web env
Update for stack overflow:
39 #RUN RAILS_ENV=production bundle exec rake assets:precompile --trace
40 RUN bundle exec rake assets:precompile --trace
41
42 # Define the script we want run once the container boots
43 # Use the "exec" form of CMD so our script shuts down gracefully on SIGTERM (i.e. docker stop
)
44 CMD [ "config/containers/app_cmd.sh” ]
在
$ docker-compose build ERROR: yaml.parser.ParserError: while parsing a block mapping in "./docker-compose.yml", line 1, column 1 expected , but found '' in "./docker-compose.yml", line 26, column 2
这个 问题主要 是缩进的不一致导致的,将缩进严格为 2 个空格,注意层级
$ docker-compose build ERROR: Validation failed in file './docker-compose.yml', reason(s): Unsupported config option for services.web: 'dockerfile'
查看版本: docker-compose --version
docker-compose version 1.7.0rc2, build ea2d526
升级 docker-compose https://docs.docker.com/compose/install/
访问 github 速度太慢了,用了替代的方法
$ pip install docker-compose
装完,别忘记改权限:
$ sudo chmod +x /usr/local/bin/docker-compose
否则 会报错:
$ docker-compose build
Cannot open self /usr/local/bin/docker-compose or archive /usr/local/bin/docker-compose.pkg
改了权限还是,报同样错误
测试这一步:https://github.com/docker/compose/issues/1135
same problem but I could not find a certain useful answer to solve it
#docker-compose Cannot open self /usr/local/bin/docker-compose or archive /usr/local/bin/docker-compose.pkg
yeah, i have solved this problem now! you can do like this.
do not use the command line curl -L https://github.com/docker/compose/releases/download/1.9.0/docker-compose-uname -s-uname -m > /usr/local/bin/docker-compose to download, maybe this makes it too slow to download.
choose the way of downloading the file , visit this https://github.com/docker/compose/releases website and choose file to download docker-compose-Linux-x86_64 7.67 MB docker-compose-Windows-x86_64.exe 5.97 MB then rename as docker-compose and copy into /usr/local/bin/
that's OK.
now you can use docker-compose --version to test whether your docker-compose is installed
Try this: If you have problems installing with curl, you can use pip instead: pip install -U docker-compose Then you need apply executable permissions to the binary:
chmod +x /usr/local/bin/docker-compose Let me know if the problem is fixed or not.
$ curl -L https://github.com/docker/compose/releases/download/1.7.0/docker-compose-`uname -s`-`uname -m` > ./docker-compose
$ sudo mv ./docker-compose /usr/bin/docker-compose
$ sudo chmod +x /usr/bin/docker-compose
最后,
部署 Capistrano 3 实现 Rails 自动化部署
https://ruby-china.org/topics/18616
Deploy a Rails app to Docker with Capistrano https://libertyseeds.ca/2015/09/09/Deploy-a-Rails-app-to-Docker-with-Capistrano/
HINT: You might need to specify "USING is_slide::boolean". : ALTER TABLE "banners" ALTER COLUMN "is_slide" TYPE boolean
现在的问题是:
rake assets:precompile
生成的 assets 是在 app 容器当中,并不能被 nginx 容器查找到
所以,考虑将内容用 volumes, 和 volumes_from 来指向
而用法可以参考:https://github.com/ogihara-ryo/froide-task-management-tool/blob/1688e37758c3ab1ad8e770c1ed55347a18236cbb/docker-compose.yml
经过 上述操作之后,nginx 容器中是有那些已经生成的文件 了,但网页访问 还是没有 找到 assets
到此时,才意识到:
这根本 就是 nginx 对 assets 文件的访问控制上出了问题 这也可以 通过 Chrome 的开发者工具了解到一些信息,
搜索 关键词 nginx assets 404
http://stackoverflow.com/questions/11404502/rails-3-2-2-getting-a-404-on-stylesheets-and-js-assets-after-deployment-with-cap
config.server_static_assets = true
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
`gzip_static
检测: http://www.whatsmyip.org/http-compression-test/
可复制 js 等地址(可从 chrome-dev 中查看)进去检测
直接在 app 容器中安装 nginx
sudo apt-get install nginx
nginx -h
/etc/init.d/nginx -h
sudo service nginx start
Dockerizing an Existing Rails Application
流程
docker-compose.yml
Dockerfile
config/database.yml
config/secrets.yml
.env
docker-compose up -d db cache
docker-compose build app jobs
docker-compose run —rm app rake db:create db:migrate
Nginx and Docker
演示了一个简单的示例,创建 nginx 容器、docker-compose
一些命令,
以及更重要的演示了如何通过添加或减小容器数量来做负载平衡,简单容易操作(docker-compose scale
)
d-c ps
d-c exec service_name bash
nslookup app
ping app
mount
/etc/resolv.conf
more /etc/resolv.conf
nameserver 127.0.0.11
(这个在后面会用到)
*more /etc/resolv.conf
d-c scale
d-c scale app=4
docker ps
scale
将 容器数量从高降低时,则会有错误出现,此时即需要修改 proxy.conf
在 docker-compose 的 version 2 中 并不需要 使用 links 来关联,因为 已经有 services 存疑
upstream unicorn { server unix:/tmp/unicorn.phindee.sock fail_timeout=0;}server { server_name www.phindee.com; return 301 $scheme://phindee.com$request_uri;}server { listen 80 default deferred; server_name phindee.com; root /var/www/phindee/current/public; location ^~ /assets/ { gzip_static on; expires max; add_header Cache-Control public; } try_files $uri/index.html $uri @unicorn; location @unicorn { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass http://unicorn; } error_page 500 502 503 504 /500.html; keepalive_timeout 10;}
Nginx 是不会处理由 Rails 产生的动态请求,我们要把这些动态的请求交给 Unicorn。
Uncaught TypeError: Cannot read property 'offsetWidth' of undefined
添加 seeds.rb
是将所需图片存到本地 host 的 public/images
下面,提示 no such file
Errno::ENOENT: No such file or directory @ rb_sysopen - /var/www/myapp/public/images/banners/slide1.jpg
查看容器的 mount
信息
docker inspect container_name
发现有一个 mount 是 命名的 volume
ActiveRecord::RecordInvalid: Validation failed: Cover translation missing: en.errors.messages.mini_magick_processing_error
注意最后的 mini_magick_processing_error
,应该是没有安装 mini_magick
的原因。
修改 Dockerfile
添加一句:RUN apt-get install -y imagemagick
应用 docker-compose exec scale web=4 app=4
,提示此错误
表象为:
运行 docker-compose up
,app
先启动,马上就退出,并提示 eshopdd_app_1 exited with code 1
vi log/nginx.error.log
17 2017/03/06 03:05:09 [error] 5#5: *2 connect() failed (113: No route to host) while connecting to upstream, client: 192.168.94.193, server: we.nb2j.com, request: "GET / HTTP/1.1", upstream: "http://172.22.0.4:3000/", host: "we.nb2j.com"
vi log/unicorn.stderr.log
ArgumentError: Already running on PID:1 (or pid=/var/www/eshop/tmp/pids/unicorn.pid is stale)
ps aux | grep 'unicorn'
root 19108 0.3 2.4 267468 94140 ? Ssl 11:22 0:03 unicorn master -c config/containers/unicorn.rb -E production root 19353 0.0 2.2 267468 88728 ? Sl 11:36 0:00 unicorn worker[0] -c config/containers/unicorn.rb -E production
kill -9 19108 19353
docker-compose up
ERROR: for app Cannot start service app: rpc error: code = 2 desc = "oci runtime error: container with id exists: c53ad59009ded923a82eba0957b4247f17845e06a6470e44df7b946119e30229" ERROR: Encountered errors while bringing up the project.
最后 重新执行:
dc scale app=1
把已经生成的相关的容器全部 删除,而后再重新 启动,就 OK 了