diff --git a/.dockerignore b/.dockerignore index 6b8710a..82933d8 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,16 @@ .git +.stuff +.bundle +tmp/* +log/* +target +uploads/* +coverage +Dockerfile +a2png/main.js +a2png/page/page.js +a2png/target +a2png/node_modules +a2png/target +config/asciinema.yml +config/database.yml diff --git a/Dockerfile b/Dockerfile index 485317f..92805ce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,105 +1,132 @@ -FROM ubuntu:14.04 +FROM ubuntu:16.04 MAINTAINER Bartosz Ptaszynski +MAINTAINER Marcin Kulik # A quickstart: # # docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=mypass --name=postgres postgres # docker run -d -p 6379:6379 --name=redis redis -# docker run --rm -e DATABASE_URL="postgresql://postgres:mypass@172.17.42.1/asciinema" foobarto/asciinema.org bundle exec rake db:setup +# docker run --rm -e DATABASE_URL="postgresql://postgres:mypass@postgres/asciinema" asciinema/asciinema.org bundle exec rake db:setup # # starting sidekiq using the provided start_sidekiq.rb file will also start sendmail service if you don't want to use SMTP # # otherwise start sidekiq by starting: bundle exec sidekiq -# docker run -d -e DATABASE_URL="postgresql://postgres:mypass@172.17.42.1/asciinema" foobarto/asciinema.org ruby start_sidekiq.rb -# docker run -d -e DATABASE_URL="postgresql://postgres:mypass@172.17.42.1/asciinema" -p 3000:3000 foobarto/asciinema.org +# docker run -d -e DATABASE_URL="postgresql://postgres:mypass@postgres/asciinema" asciinema/asciinema.org ruby start_sidekiq.rb +# docker run -d -e DATABASE_URL="postgresql://postgres:mypass@postgres/asciinema" -p 3000:80 asciinema/asciinema.org # # You can override the address/port that is sent in email with login token by passing HOST="host:port" environment variable when starting the web server. -# -# Assuming you are running Docker Toolbox and VirtualBox: go to http://192.168.99.100:3000/ and enjoy. -ENV RUBY_VERSION 2.1.7 -EXPOSE 3000 +ARG DEBIAN_FRONTEND=noninteractive +ARG NODE_VERSION=node_6.x +ARG DISTRO=xenial -# get ruby in the house -RUN mkdir /app && \ +RUN apt-get update && \ + apt-get install -y wget software-properties-common apt-transport-https && \ + add-apt-repository ppa:brightbox/ruby-ng && \ + echo "deb https://deb.nodesource.com/$NODE_VERSION $DISTRO main" >/etc/apt/sources.list.d/nodesource.list && \ + wget --quiet -O - https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \ apt-get update && \ apt-get install -y \ autoconf \ build-essential \ - curl \ git-core \ - libcurl4-openssl-dev \ - libffi-dev \ + imagemagick \ + libfontconfig1 \ libpq-dev \ - libreadline-dev \ - libsqlite3-dev \ - libssl-dev \ libtool \ libxml2-dev \ libxslt1-dev \ - libyaml-dev \ + nginx \ + nodejs \ pkg-config \ - postgresql \ - python-software-properties \ + ruby2.1 \ + ruby2.1-dev \ sendmail \ - software-properties-common \ - sqlite3 \ - zlib1g-dev - -ENV PATH /usr/local/rbenv/bin:/usr/local/rbenv/plugins/ruby-build/bin:$PATH - -# install ruby -RUN mkdir /usr/local/rbenv && \ - git clone git://github.com/sstephenson/rbenv.git /usr/local/rbenv && \ - git clone git://github.com/sstephenson/ruby-build.git /usr/local/rbenv/plugins/ruby-build && \ - git clone https://github.com/sstephenson/rbenv-gem-rehash.git /usr/local/rbenv/plugins/rbenv-gem-rehash && \ - rbenv install $RUBY_VERSION && \ - rbenv global $RUBY_VERSION && \ - rbenv rehash - -# get asciinema dependencies -RUN curl --silent --location https://deb.nodesource.com/setup_4.x | sudo bash - && \ - add-apt-repository ppa:tanguy-patte/phantomjs && \ - apt-get update && \ - apt-get install -y phantomjs nodejs && \ - rbenv exec gem install bundler + supervisor \ + ttf-bitstream-vera + +# Packages required for: +# autoconf, libtool and pkg-config for libtsm +# libfontconfig1 for PhantomJS +# ttf-bitstream-vera for a2png +# imagemagick (identify) for PNG generator (Ruby) + +# install Bundler + +RUN gem install bundler + +# install PhantomJS + +ARG PHANTOMJS_VERSION=2.1.1 + +RUN wget --quiet -O /opt/phantomjs.tar.bz2 https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 && \ + tar xjf /opt/phantomjs.tar.bz2 -C /opt && \ + rm /opt/phantomjs.tar.bz2 && \ + ln -sf /opt/phantomjs-$PHANTOMJS_VERSION-linux-x86_64/bin/phantomjs /usr/local/bin -# get libtsm -RUN git clone git://people.freedesktop.org/~dvdhrm/libtsm /tmp/libtsm && \ +# install libtsm + +RUN git clone https://github.com/asciinema/libtsm.git /tmp/libtsm && \ cd /tmp/libtsm && \ - git checkout libtsm-3 && \ + git checkout asciinema && \ test -f ./configure || NOCONFIGURE=1 ./autogen.sh && \ ./configure --prefix=/usr/local && \ make && \ - sudo make install && \ - sudo ldconfig + make install && \ + ldconfig && \ + rm -rf /tmp/libtsm + +# install JDK + +RUN wget --quiet -O /opt/jdk-8u111-linux-x64.tar.gz --no-check-certificate --no-cookies --header 'Cookie: oraclelicense=accept-securebackup-cookie' http://download.oracle.com/otn-pub/java/jdk/8u111-b14/jdk-8u111-linux-x64.tar.gz && \ + tar xzf /opt/jdk-8u111-linux-x64.tar.gz -C /opt && \ + rm /opt/jdk-8u111-linux-x64.tar.gz && \ + update-alternatives --install /usr/bin/java java /opt/jdk1.8.0_111/bin/java 1000 + +# install leiningen + +RUN wget --quiet -O /usr/local/bin/lein https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein && \ + chmod a+x /usr/local/bin/lein + +ARG LEIN_ROOT=yes # install asciinema -ADD . /app + +ENV RAILS_ENV "production" + +RUN mkdir -p /app/tmp /app/log WORKDIR /app -RUN rbenv local $RUBY_VERSION && \ - cd /app/src && \ - eval "$(rbenv init -)" && \ - make && \ - cd /app && \ - rm -f log/* && \ - bundle install && \ - mkdir -p tmp && \ - ln -s /app/vendor/assets/javascripts/asciinema-player.js /app/a2png/ && \ - ln -s /app/vendor/assets/stylesheets/asciinema-player.css /app/a2png/ && \ - touch tmp/restart.txt - -VOLUME ["/app/config", "/app/log", "/app/uploads"] - -# 172.17.42.1 is the docker0 address -ENV DATABASE_URL "postgresql://postgres:mypass@172.17.42.1/asciinema" -ENV REDIS_URL "redis://172.17.42.1:6379" -ENV RAILS_ENV "development" -# when using Docker Toolbox/Virtualbox this is going to be your address -# set to whatever FQDN/address you want asciinema to advertise itself as -# for ex. asciinema.example.com +COPY Gemfile* /app/ +RUN bundle install --deployment --without development test + +COPY a2png/project.clj /app/a2png/ +RUN cd a2png && lein deps + +COPY a2png /app/a2png +RUN cd a2png && lein cljsbuild once main && lein cljsbuild once page + +COPY . /app + +ENV DATABASE_URL "postgresql://postgres:mypass@postgres/asciinema" +ENV REDIS_URL "redis://redis:6379" + +RUN cd src && make +RUN bundle exec rake assets:precompile + +# configure Nginx + +COPY docker/nginx/asciinema.conf /etc/nginx/sites-available/default + +# configure Supervisor + +RUN mkdir -p /var/log/supervisor +COPY docker/supervisor/asciinema.conf /etc/supervisor/conf.d/asciinema.conf + +VOLUME ["/app/log", "/app/uploads"] + ENV HOST "localhost:3000" -ENTRYPOINT ["rbenv", "exec"] -CMD ["bundle", "exec", "rails", "server"] +CMD ["/usr/bin/supervisord"] # bundle exec rake db:setup # bundle exec sidekiq OR ruby start_sidekiq.rb (to start sidekiq with sendmail) + +EXPOSE 80 diff --git a/README.md b/README.md index 548b7fa..4b6e029 100644 --- a/README.md +++ b/README.md @@ -24,18 +24,20 @@ your organization. ### Quickstart Using Docker Compose Required: - - [Docker](https://docs.docker.com/engine/getstarted/step_one/#step-1-get-docker) - - [docker-compose 1.5+](https://docs.docker.com/compose/install/) + +- [Docker](https://docs.docker.com/engine/getstarted/step_one/#step-1-get-docker) +- [docker-compose 1.5+](https://docs.docker.com/compose/install/) + ```bash $ wget https://raw.githubusercontent.com/asciinema/asciinema.org/master/docker-compose.yml -$ docker-compose up -d asciinema $ docker-compose run --rm db_init +$ docker-compose up -d web ``` You can override the address/port that is sent in email with login token by passing HOST="host:port" environment variable when starting the web server. -Assuming you are running Docker Toolbox and VirtualBox: go to http://192.168.99.100:3000/ and enjoy. +Assuming you are running Docker Toolbox and VirtualBox: go to http://your-docker-host:3000/ and enjoy. ### Manual setup diff --git a/config/unicorn.rb b/config/unicorn.rb new file mode 100644 index 0000000..5810026 --- /dev/null +++ b/config/unicorn.rb @@ -0,0 +1,55 @@ +ASCIINEMA_HOME = ENV["ASCIINEMA_HOME"] || Dir.pwd +UNICORN_WORKERS = (ENV["UNICORN_WORKERS"] || "4").to_i + +# Use at least one worker per core if you're on a dedicated server, +# more will usually help for _short_ waits on databases/caches. +worker_processes UNICORN_WORKERS + +# Help ensure your application will always spawn in the symlinked +# "current" directory that Capistrano sets up. +working_directory ASCIINEMA_HOME + +listen 3000, :tcp_nopush => true + +# nuke workers after 60 seconds +timeout 60 + +# feel free to point this anywhere accessible on the filesystem +pid "#{ASCIINEMA_HOME}/tmp/unicorn.pid" + +preload_app true + +# Enable this flag to have unicorn test client connections by writing the +# beginning of the HTTP headers before calling the application. This +# prevents calling the application for connections that have disconnected +# while queued. This is only guaranteed to detect clients on the same +# host unicorn runs on, and unlikely to detect disconnects even on a +# fast LAN. +check_client_connection false + +before_exec do |server| + ENV["BUNDLE_GEMFILE"] = "#{ASCIINEMA_HOME}/Gemfile" +end + +before_fork do |server, worker| + if defined?(ActiveRecord::Base) + ActiveRecord::Base.connection.disconnect! + Rails.logger.info('Disconnected from ActiveRecord') + end + + 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| + if defined?(ActiveRecord::Base) + ActiveRecord::Base.establish_connection + Rails.logger.info('Connected to ActiveRecord') + end +end diff --git a/docker-compose.yml b/docker-compose.yml index 398537a..093d34c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,21 +1,24 @@ version: '2' # Quickstart: -# docker-compose up -d asciinema -# docker-compose run --rm db_init +# docker-compose run --rm -b_init +# docker-compose up -d web # To cleanup: -# docker-compose stop && docker-compose rm +# docker-compose stop && docker-compose rm services: postgres: image: postgres - container_name: postgres + container_name: asciinema_postgres + redis: image: redis - container_name: redis + container_name: asciinema_redis + sidekiq: image: asciinema/asciinema.org + container_name: asciinema_worker links: - redis - postgres @@ -27,9 +30,9 @@ services: volumes: - /tmp/asciinema/uploads:/app/uploads - asciinema: + web: image: asciinema/asciinema.org - container_name: asciinema + container_name: asciinema_web links: - redis - postgres @@ -40,16 +43,14 @@ services: REDIS_URL: "redis://redis:6379" HOST: "localhost:3000" # replace with actual hostname/ip.... ${HOSTNAME} doesn't seem to work.. ports: - - "3000:3000" + - "3000:80" volumes: - /tmp/asciinema/uploads:/app/uploads db_init: image: asciinema/asciinema.org links: - - redis - postgres environment: DATABASE_URL: "postgresql://postgres:mypass@postgres/asciinema" - REDIS_URL: "redis://redis:6379" command: "bundle exec rake db:setup" diff --git a/docker/nginx/asciinema.conf b/docker/nginx/asciinema.conf new file mode 100644 index 0000000..6e92331 --- /dev/null +++ b/docker/nginx/asciinema.conf @@ -0,0 +1,36 @@ +upstream rails-server { + server 127.0.0.1:3000 fail_timeout=0; +} + +server { + listen 80 default_server; + listen [::]:80 default_server; + + server_name _; + + root /app/public; + + client_max_body_size 16m; + + location / { + try_files $uri $uri/index.html $uri.html @rails; + } + + location ~ ^/assets/ { + expires 1y; + add_header Cache-Control public; + + add_header ETag ""; + break; + } + + location @rails { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $http_host; + proxy_pass http://rails-server; + proxy_redirect off; + error_page 500 502 504 /500.html; # Rails error pages + } +} diff --git a/docker/supervisor/asciinema.conf b/docker/supervisor/asciinema.conf new file mode 100644 index 0000000..0857a41 --- /dev/null +++ b/docker/supervisor/asciinema.conf @@ -0,0 +1,17 @@ +[supervisord] +nodaemon=true + +[program:nginx] +command=/usr/sbin/nginx -g "daemon off;" +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:rails] +command=bundle exec unicorn -c config/unicorn.rb +directory=/app +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 \ No newline at end of file