【问题标题】:docker-compose error connecting to redis + sidekiqdocker-compose 连接到 redis + sidekiq 时出错
【发布时间】:2019-03-03 19:30:29
【问题描述】:

我正在尝试使用 docker 构建一个容器,但我无法连接 sidekiq + redis,错误为 sidekiq_1 | Error connecting to Redis on 127.0.0.1:6379 (Errno::ECONNREFUSED),似乎 sidekiq 正在尝试连接到 localhost 但因为我正在构建“理论上”redis + sidekiq + rails + postgres 容器不在本地主机中,它应该在 redis 映像中。

我的 docker-compose.yml 文件是这样的:

version: '3'

services:
  postgres:
    image: postgres:10.5
    volumes:
      - my_app-postgres:/var/lib/postgresql/data

  redis:
    image: redis:4.0.11
    volumes:
      - my_app-redis:/var/lib/redis/data

  web:
    build: .
    command: bundle exec rails server -p 3000 -b '0.0.0.0'
    ports:
      - '3000:3000'
    depends_on:
      - postgres
      - redis
    volumes:
      - .:/my_app
    env_file:
      - .env

  sidekiq:
    build: .
    command: bundle exec sidekiq -C config/sidekiq.yml
    volumes:
      - .:/my_app
    depends_on:
      - postgres
      - redis
    env_file:
      - .env

volumes:
  my_app-postgres:
  my_app-redis:

我在日志中看到的另一个有趣的“信息”是Booting Sidekiq 4.2.10 with redis options {:url=>nil} 这个网址可能是问题的原因吗?

在我的开发环境中,该应用程序运行良好,我尝试“dockerize”我所拥有的。我怎样才能使这项工作?

【问题讨论】:

    标签: ruby-on-rails docker redis sidekiq


    【解决方案1】:

    默认情况下,sidekiq 会尝试连接到127.0.0.1:6379,但你的sidekiq 与redis 在不同的容器中,所以你需要配置sidekiq 使用redis:6379 作为redis 主机,例如通过使用初始化器

     Sidekiq.configure_server do |config|
      config.redis = { url: 'redis://redis:6379/12' }
     end
    

    查看文档了解更多详情:https://github.com/mperham/sidekiq/wiki/Using-Redis

    如果您打算稍后使用 Kubernetes 进行部署,您可以将所有容器放在一个 pod 中,然后它们将能够通过 localhost 连接,因为同一个 Kubernetes pod 中的容器共享网络空间。要直接在 Kubernetes 集群内的 pod 中编程,您可以使用我最近在 GitHub 上开源的一个名为 DevSpace: https://github.com/covexo/devspace

    的工具

    【讨论】:

    • 最好在 ENV 中设置 URL,这样就不需要初始化器:REDIS_URL=redis://redis:6379 bundle exec sidekiq ...
    【解决方案2】:

    创建两个初始化文件:

    i) redis.rb

    uri = "redis://#{ENV['REDIS_URL']}:#{ENV['REDIS_PORT']}/0/your-app-cache" || 'redis://localhost:6379/0/your-app-cache'
    
    Rails.application.config.cache_store = :redis_store, uri
    

    ii) sidekiq.rb

    Sidekiq.configure_server do |config|
      config.redis = { url:  "redis://#{ENV['REDIS_URL']}:#{ENV['REDIS_PORT']}/12" }
    end
    
    Sidekiq.configure_client do |config|
      config.redis = { url:  "redis://#{ENV['REDIS_URL']}:#{ENV['REDIS_PORT']}/12" }
    end
    

    【讨论】:

      【解决方案3】:

      完整样本

      ./Dockerfile

      FROM ruby:2.6.3-alpine
      
      ENV BUNDLER_VERSION=2.0.2
      
      RUN apk add --update --no-cache \
            binutils-gold \
            build-base \
            curl \
            file \
            g++ \
            gcc \
            git \
            less \
            libstdc++ \
            libffi-dev \
            libc-dev \ 
            linux-headers \
            libxml2-dev \
            libxslt-dev \
            libgcrypt-dev \
            make \
            netcat-openbsd \
            nodejs \
            openssl \
            pkgconfig \
            postgresql-dev \
            python \
            tzdata \
            yarn 
      
      ARG USER=root
      ARG WORK_DIR_PATH=/home
      RUN mkdir -p $WORK_DIR_PATH && chown -R $USER:$USER $WORK_DIR_PATH
      WORKDIR $WORK_DIR_PATH
      
      COPY Gemfile* ./
      RUN gem install bundler
      RUN bundle config build.nokogiri --use-system-libraries
      RUN bundle check || bundle install 
      
      COPY package.json yarn.lock ./
      RUN yarn install --check-files
      
      COPY . .
      

      ./.env

      APP_NAME=api
      APP_PORT=3100
      
      ENV=production
      
      DATABASE_NAME=rails_db
      DATABASE_USER=batman
      DATABASE_PASSWORD=super_pass_123
      DATABASE_PORT=5342
      DATABASE_HOST=api_db # must be equal to the name of the postgres service in docker-compose.yml
      
      SECRET_KEY_BASE=your_secret_string
      
      REDIS_HOST=redis # must be equal to the name of the redis service in docker-compose.yml
      REDIS_PORT=6379
      

      ./docker-compose.yml

      version: '3.7'
      services:
        api: 
          build:
            context: .
            dockerfile: Dockerfile
          container_name: ${APP_NAME}
          #restart: unless-stopped
          depends_on:     
            - api_db
            - redis
          ports: 
            - "${APP_PORT}:${APP_PORT}"
          volumes:
            - .:/app
            - gem_cache:/usr/local/bundle/gems
            - node_modules:/app/node_modules
          env_file: .env
          environment:
            RAILS_ENV: ${ENV}
          entrypoint: ./sh/entrypoints/api-entrypoint.sh
      
        api_db:
          image: postgres
          command: postgres -p ${DATABASE_PORT}
          ports:
            - "${DATABASE_PORT}:${DATABASE_PORT}"
          volumes:
            - db_data:/var/lib/postgresql/data
            - ./log/db:/logs
          environment:
            - POSTGRES_USER=${DATABASE_USER}
            - POSTGRES_PASSWORD=${DATABASE_PASSWORD}
            - POSTGRES_DB=${DATABASE_NAME}
      
        redis:
          image: redis
          ports:
            - "${REDIS_PORT}:${REDIS_PORT}"
          command: redis-server
          volumes:
            - redis:/data
      
        sidekiq:
          build:
            context: .
            dockerfile: Dockerfile
          depends_on:
            - api_db
            - redis
          volumes:
            - .:/app
            - gem_cache:/usr/local/bundle/gems
            - node_modules:/app/node_modules
          env_file: .env
          environment:
            RAILS_ENV: ${ENV}
            ENABLE_BOOTSNAP: 'false'
          entrypoint: ./sh/entrypoints/sidekiq-entrypoint.sh
      
      volumes:
        redis:
        gem_cache:
        db_data:
        node_modules:
      

      ./sh/entrypoints/api-entrypoint.sh

      https://*.com/a/59047028/4488252

      #!/bin/sh
      
      DB_INITED=0
      if db_version=$(bundle exec rake db:version 2>/dev/null)
      then
          if [ "$db_version" = "Current version: 0" ]
          then
              echo "DB is empty"
          else
              echo "DB exists"
              DB_INITED=1
          fi
          bundle exec rake db:migrate 
      else
          echo "DB does not exist"
          bundle exec rake db:setup
      fi
      
      if [ $DB_INITED == 0 ]
      then
          echo "Performing initial configuration"
          # init some plugins, updated db if need, add initial data
      fi
      
      bundle exec rails assets:precompile
      bundle exec rails s -b 0.0.0.0 -p $APP_PORT
      

      ./sh/entrypoints/sidekiq-entrypoint.sh

      #!/bin/sh
      
      set -e
      
      if [ -f tmp/pids/server.pid ]; then
        rm tmp/pids/server.pid
      fi
      
      bundle exec sidekiq
      

      ./config/database.yml

      default: &default
        adapter: postgresql
        encoding: unicode
        pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
        database: <%= ENV['DATABASE_NAME'] %>
        username: <%= ENV['DATABASE_USER'] %>
        password: <%= ENV['DATABASE_PASSWORD'] %>
        port: <%= ENV['DATABASE_PORT'] || '5432' %>
        host: <%= ENV['DATABASE_HOST'] %>
      
      development:
        <<: *default
      
      test:
        <<: *default
      
      production:
        <<: *default
        secret_key_base: <%= ENV['SECRET_KEY_BASE'] %>
      

      ./config/initializers/sidekiq.rb

      Sidekiq.configure_server do |config|
        config.redis = { :url => "redis://#{ENV['REDIS_HOST']}:#{ENV['REDIS_PORT']}/" }
      end
      
      Sidekiq.configure_client do |config|
        config.redis = { :url => "redis://#{ENV['REDIS_HOST']}:#{ENV['REDIS_PORT']}/" }
      end
      

      ./.dockerignore

      https://gist.github.com/neckhair/ace5d1679dd896b71403fda4bc217b9e

      .git
      .gitignore
      README.md
      
      #
      # OS X
      #
      .DS_Store
      .AppleDouble
      .LSOverride
      # Icon must end with two \r
      Icon
      # Thumbnails
      ._*
      # Files that might appear on external disk
      .Spotlight-V100
      .Trashes
      # Directories potentially created on remote AFP share
      .AppleDB
      .AppleDesktop
      Network Trash Folder
      Temporary Items
      .apdisk
      
      #
      # Rails
      #
      .env
      .env.sample
      *.rbc
      capybara-*.html
      log
      tmp
      db/*.sqlite3
      db/*.sqlite3-journal
      public/system
      coverage/
      spec/tmp
      **.orig
      
      .bundle
      
      .ruby-version
      .ruby-gemset
      
      .rvmrc
      
      # if using bower-rails ignore default bower_components path bower.json files
      vendor/assets/bower_components
      *.bowerrc
      bower.json
      
      # Logs
      logs
      *.log
      
      # Runtime data
      pids
      *.pid
      *.seed
      
      # Directory for instrumented libs generated by jscoverage/JSCover
      lib-cov
      
      # Coverage directory used by tools like istanbul
      coverage
      
      # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
      .grunt
      
      # node-waf configuration
      .lock-wscript
      
      # Compiled binary addons (http://nodejs.org/api/addons.html)
      build/Release
      
      # Dependency directory
      # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
      node_modules
      
      server/*.spec.js
      kubernetes
      

      用法

      https://docs.docker.com/compose/reference/down/

      构建并运行:docker-compose up --build -d

      https://docs.docker.com/compose/reference/down/

      停止:docker-compose down

      停止 + 删除图像和卷:docker-compose down --rmi all --volumes

      【讨论】: