2012-03-31 6 views
17

Sto usando nebbia con carrierwave nel mio sito web. Ma le immagini si caricano molto molto lentamente.Usa CDN con carrierwave + fog in s3 + cloudfront con rail 3.1

Quindi voglio accelerare il caricamento di immagini con un CDN.

Ho seguito questo tutorial per creare il CDN per le immagini:

http://maketecheasier.com/configure-amazon-s3-as-a-content-delivery-network/2011/06/25

ora ho la mia distribuzione schierato per le immagini, ma non so come funziona bene il CDN. Ho in inizializzatori/fog.rb la configurazione successiva:

CarrierWave.configure do |config| 
    config.fog_credentials = { 
    :provider    => 'AWS', 
    :aws_access_key_id  => 'key', 
    :aws_secret_access_key => 'key', 
    :region     => 'eu-west-1' 
    } 
    config.fog_host = "http://da33ii2cvf53u.cloudfront.net" #config.asset_host instead of config.fog_host for new fog gem versions 
    config.fog_directory = 'pin-pro' 
    config.fog_public  = false 
    #config.fog_attributes = {'Cache-Control' => 'max-age=315576000'} 
end 

Non so se questo è corretto, ma nella mia macchina locale che non funziona bene per me. Vedo la posizione dell'immagine, è lo stesso percorso di prima:

https://s3-eu-west-1.amazonaws.com/pin-pro/uploads/pins/medium_610cafbe-5d43-4223-ab0e-daa4990863c4.jpg?AWSAccessKeyId=AKIAIDX34WHYKB3ZKFVA&Signature=RwQriNpiRXaTxyfYVvYjsvclUa8%3D&Expires=1333203059 

Come posso aggiungere una CDN di nebbia file in carrierwave con S3 e CloudFront?

+0

Se uso che l'impostazione: 'fog_host', allora ottengo questo errore: metodo non definito' fog_host =' per CarrierWave :: Uploader :: Base: Classe Quale versione di carrierwave sono persone che utilizzano? –

+0

Dovresti usare 'config.asset_host' invece di' config.fog_host'. Ho aggiunto questo problema alla domanda. In bocca al lupo! – hyperrjas

+0

Sì, l'ho notato, dopo alcuni scavi :) Grazie. –

risposta

7

Sembra che tu non abbia aggiunto la riga sotto alla tua configurazione. Dovrai sostituire l'indirizzo di esempio qui sotto con il tuo indirizzo cloudfront da Amazon.

Dal README github: https://github.com/jnicklas/carrierwave

"Opzionalmente si può includere il vostro nome host CDN nella configurazione Questo è altamente raccomandato, come senza di essa ogni richiesta richiede una ricerca di queste informazioni."

config.asset_host = "http://c000000.cdn.rackspacecloud.com"

+0

Questo non funziona con il contenuto privato CloudFront. – Allen

6

sembra che Amazon CDN non funziona con config.fog_public = false, quindi i file privati ​​sono accessibili solo da S3, non dalla CDN

10

CarrierWave non wor k quando si imposta config.fog_public = falsee punto config.asset_host in una distribuzione CloudFront. Questo è stato documentato più volte:

https://github.com/carrierwaveuploader/carrierwave/issues/1158 https://github.com/carrierwaveuploader/carrierwave/issues/1215

In un recente progetto ero felice con CarrierWave per gestire il caricamento a S3, ma ha voluto che per restituire un URL CloudFront firmato quando si utilizza Model.attribute_url. Ho trovato la seguente soluzione (certamente brutta) che spero che altri possano beneficiare o migliorare:

Aggiungi il gioiello 'cloudfront-signer' al tuo progetto e configuralo seguendo le istruzioni. Quindi aggiungere il seguente override /lib/carrierwave/uploader/url.rb in un nuovo file in config/initializers (notare le molteplici inserimenti di AWS :: :: CF Signer.sign_url):

module CarrierWave 
     module Uploader 
     module Url 
      extend ActiveSupport::Concern 
      include CarrierWave::Uploader::Configuration 
      include CarrierWave::Utilities::Uri 

      ## 
      # === Parameters 
      # 
      # [Hash] optional, the query params (only AWS) 
      # 
      # === Returns 
      # 
      # [String] the location where this file is accessible via a url 
      # 
      def url(options = {}) 
      if file.respond_to?(:url) and not file.url.blank? 
       file.method(:url).arity == 0 ? AWS::CF::Signer.sign_url(file.url) : AWS::CF::Signer.sign_url(file.url(options)) 
      elsif file.respond_to?(:path) 
       path = encode_path(file.path.gsub(File.expand_path(root), '')) 

       if host = asset_host 
       if host.respond_to? :call 
        AWS::CF::Signer.sign_url("#{host.call(file)}#{path}") 
       else 
        AWS::CF::Signer.sign_url("#{host}#{path}") 
       end 
       else 
       AWS::CF::Signer.sign_url((base_path || "") + path) 
       end 
      end 
      end 

     end # Url 
    end # Uploader 
end # CarrierWave 

Quindi sovrascrivere /lib/carrierwave/storage/fog.rb aggiungendo quanto segue alla parte inferiore dello stesso file:

require "fog" 

module CarrierWave 
    module Storage 
    class Fog < Abstract 
     class File 
      include CarrierWave::Utilities::Uri 
      def url 
      # Delete 'if statement' related to fog_public 
      public_url 
      end 
     end 
    end 
    end 
end 

Infine, in config/inizializzatori/carrierwave.rb:

config.asset_host = " http://d12345678.cloudfront.net "

config.fog_public = false

Questo è tutto. Ora puoi utilizzare Model.attribute_url e restituirà un URL CloudFront firmato a un file privato caricato da CarrierWave sul tuo bucket S3.

1

Dopo aver cercato e faticato con questo a lungo, ho trovato una pagina che dice che CarrierWave non supporta gli URL firmati CloudFront. Gli URL firmati CloudFront sono diversi dagli URL firmati S3, il che mi ha causato confusione. Una volta capito, era molto più facile sapere cosa fare.

Se si configura CarrierWave con config.fog_public = false allora inizierà automaticamente la firma degli URL S3, ma non può essere configurato per lavorare con Fog e CloudFront contenuti privati ​​nella versione di CarrierWave sto usando (1.0.0). Ho anche provato a usare la gemma carrierwave-aws e non è stato di alcun aiuto.

Quindi, che cosa accadrebbe è che CarrierWave avrebbe firmato l'URL e l'host sarebbe simile a questa:

https://my_bucket_name.s3-us-west-2.amazonaws.com/uploads/...?signature... 

che punta direttamente al secchio S3, ma ne avevo bisogno per puntare a CloudFront. Avevo bisogno l'host per assomigliare a questo:

https://s3.cloudfront_domain_name.com/uploads/... 

E cosa sarebbe successo se ho impostato config.asset_host uguale alla mia posizione CloudFront è che avrei avuto questo, (con le doppie barre prima di "arrivi"):

https://s3.cloudfront_domain_name.com//uploads/... 

Anche questo ha chiarito che CarrierWave non era ancora progettato per essere utilizzato con CloudFront. Spero che lo miglioreranno. Questo è stato il mio work-around. È brutto, ma ha funzionato per ottenere ciò di cui avevo bisogno senza dover modificare CarrierWave stesso, poiché spero che CarrierWave aggiungerà a un certo punto il supporto per CloudFront.

  1. Prima ho fatto una regex trova/sostituisci sul mio URL e rimosso la parte host S3 e messo sulla mia parte dell'host CloudFront. cf_url = s3_url.gsub("my_bucket_name.s3-us-west-2.amazonaws.com", "s3.cloudfront_domain_name.com")
  2. Poi ho fatto un altro regex trova/sostituisci per rimuovere la S3 firmato url alla fine della stringa: non_signed_cf_url = cf_url.gsub(/\?.+/, '') Questo perché la firma non sarà corretto perché è stato utilizzando l'API per S3 e non per CloudFront per firma l'URL.
  3. Ora mi ri-firmare l'URL me stesso, utilizzando il cloudfront-signer gemma: signed_cf_url = Aws::CF::Signer.sign_url(non_signed_cf_url, :expires => 1.day.from_now)

Ci sono alcune altre cose che dovete essere a conoscenza di quando servono contenuti privati ​​su CloudFront:

  • In Impostazioni comportamento cache per il modello del percorso (non necessariamente quello predefinito), impostare: "Limita accesso visualizzatore (Usa URL firmati o cookie firmati)" a "Sì"
  • Impostare "Trusted Signers "to" self "
  • Impostare" Inoltra stringa e cache di query "a" Inoltra tutto, cache in base a tutti "se si desidera utilizzare altre stringhe di query più della firma CloudFront nell'URL, ad esempio response-content-disposition e response-content-type (Sono riuscito a far funzionare correttamente questi file, ma devono essere url_encoded correttamente.)
  • Nelle impostazioni di origine di CloudFront, impostare l'identità di accesso e impostare "Consenti autorizzazioni di lettura in bucket" a "Sì, politica di aggiornamento dei bucket"
  • Nelle impostazioni di distribuzione generali, assicurati che "Stato di distribuzione" sia "Abilitato" e che hai aggiunto un CNAME a "Nomi di dominio alternativi (CNAME)" se ne stai utilizzando uno.
  • Se si utilizza un CNAME, assicurarsi che il proprio DNS sia configurato correttamente per puntarlo al nome della propria distribuzione CloudFront.
  • Infine, una volta impostate le configurazioni, c'è una lunga attesa mentre AWS aggiorna la distribuzione, quindi non vedrete le modifiche subito. Potrebbe sembrare che la tua app/il tuo sito Web sia ancora guasto fino a quando le modifiche non si propagheranno attraverso CloudFront. Questo può rendere difficile la configurazione perché se ti sbagli devi aspettare molto tempo prima di poter vedere le tue modifiche diventare effettive e potresti non essere sicuro di cosa sia successo. Ma con queste impostazioni sono riuscito a farlo funzionare per me.
  • È inoltre possibile creare più di un modello di percorso di memorizzazione nella cache in modo che alcuni contenuti siano privati ​​e che richieda un url firmato CloudFront e che il contenuto non lo sia. Ad esempio, ho impostato un pattern di percorso di *.mp4 che richiede una firma per tutti i file mp4 e posizionato sopra il comportamento predefinito. E poi ho il comportamento predefinito della cache impostato per NON richiedere gli URL firmati, il che consente a tutti gli altri file, come le immagini, di essere accessibili pubblicamente attraverso la distribuzione CloudFront.