Cover image for Setup web-page screenshots within a minute

Setup web-page screenshots within a minute

dsalahutdinov profile image Salahutdinov Dmitry ・3 min read

For many years PhantomJS is used to generate a web-page screenshot. As we have a Ruby web-application on Kubebernetes, it brought some inconveniences: we had to install NodeJs and PhantomJS rights into the main Ruby Docker image:

# Phantomjs is installed via npm to avoid HUGE dependencies such as QT and others.
RUN npm install phantomjs-prebuilt \
  && ln -s /node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs /usr/local/bin/phantomjs \
  && rm -rf /tmp/phantomjs

COPY ./fonts/Helvetica.ttf /usr/share/fonts/truetype/Helvetica.ttf

It causes all the application instances, like web, sidekiq, and others, had these low-level dependencies installed even if they did not need to generate screenshots.

For some time PhantomJS are not supported anymore. The new alternative is to use Google Chrome within the "headless" mode, a great example of doing it from the command line:

google-chrome --headless --window-size=1180,768 --screenshot=/tmp/screenshot.png https://amplifr.com/en

We need to get google-chrome installed to a machine, so using this command rights from the ruby code doesn't change anything fundamentally.

That is why I decided to extract it into separated HTTP based micro-service for capturing web-page and returning an image.

Here it is https://github.com/dsalahutdinov/screenshot
It could be touched with curl:

curl --output screenshot.png http://screenshot.local/screenshot\?width\=1180\&height\=768\&url\=https://amplifr.com/en

Or with browser as well:

Generated screenshot


Internally it is simple HTTP-wrapper for running Chrome and return resulting image file. Nothing more on it. Screenshot tool is Kubernetes-ready, and you can get it up in a minute by running kubectl or using predefined helm-chart.

Use Helm Chart

The predefined helm-chart is located here. This repo also works as a helm-repository on top of Github pages. Add the repository to your helm settings:

$ helm repo add screenshot-helm https://dsalahutdinov.github.io/screenshot-helm/
"screenshot-helm" has been added to your repositories

And deploy the chart into current Kubernetes cluster:

$ helm install screenshot-helm/screenshot --name screenshot --namespace screenshot

NAME:   screenshot
LAST DEPLOYED: Sat Apr  4 16:59:02 2020
NAMESPACE: screenshot

==> v1/Deployment
NAME         AGE
screenshot  1s

==> v1/Pod(related)
NAME                      AGE
screenshot-76948b-rrq77  1s

==> v1/Service
NAME         AGE
screenshot  1s

Since then, service will run as "internal" without any ingress resources. You can access it within the cluster by its internal DNS name, [release].[namespace].kubernetes.local, or with just short name [release].[namespace]:

curl --output screenshot.png \

Run on Minikube

Here is the manual for running screenshot service into Minikube local cluster with using "external" domain name screenshot.local:

# starts minikube
minikube start

# gets minikube ip address and adds it as screenshot.local domain address
echo "$(minikube ip) screenshot.local" | sudo tee -a /etc/hosts

# adds helm repository
$ helm repo add screenshot-helm 

# installs screenshot service with the enabled ingress
$ helm install screenshot-helm/screenshot \
  --name screenshot \
  --namespace screenshot \
  --set ingress.enabled=True \
  --set ingress.hosts\[0\].host=screenshot.local \
  --set ingress.hosts\[0\].paths\[0\]=/screenshot

NAME:   screenshot
LAST DEPLOYED: Mon Apr  6 10:51:54 2020
NAMESPACE: screenshot

==> v1/Deployment
NAME        AGE
screenshot  0s

==> v1/Pod(related)
NAME                         AGE
screenshot-58dd688598-ml9nw  0s

==> v1/Service
NAME        AGE
screenshot  0s

==> v1/ServiceAccount
NAME        AGE
screenshot  0s

==> v1beta1/Ingress
NAME        AGE
screenshot  0s

1. Get the application URL by running these commands:

After the start, service will be available to access with amplifr.local domain. Other supported options of helm-chart, like resources, tls, affinity you can find here.


Using ruby is very straightforward:

options = {
  height: 1024, width: 768, url: 'https://amplifr.com/en'
response = Faraday.new(
  'http://screenshot.screenshot/screenshot?' + options.map { |k, v| "#{k}=#{v}" }.join("&")

File.open('screenshot.png', "wb") {  |f| f.write(response.body) }


The screenshot tool is straightforward and solves the simple, practical task - web-page screenshot generation. You can run into a Kubernetes cluster in a minute if you would need a web-page screenshot generation one day.


Editor guide