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:
Internals
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
STATUS: DEPLOYED
RESOURCES:
==> 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 \
http://screenshot.screenshot/screenshot/?width=1180&height=768&url=https://amplifr.com/en
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
STATUS: DEPLOYED
RESOURCES:
==> 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
NOTES:
1. Get the application URL by running these commands:
http://screenshot.local/screenshot
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.
Usage
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("&")
).get
File.open('screenshot.png', "wb") { |f| f.write(response.body) }
Conclusion
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.
Top comments (0)