Php7 Redis Client on Alpine OS - docker

I crafted a docker image using alpine 3.5 as base Image. I want my php apllication running inside container to communicate with a redis server.But I don't find any php7-redis client in Alpine.
Is there a workway around it ?I tried to use pecl to install redis but there is no pecl package in alpine.I tried with pear but pear doesn't have redis package. Any thoughts on this issue ?

For versions of Alpine prior to 3.6, such as the current official PHP Alpine image (Alpine 3.4), you need to build the extension from source. There are a few dependencies you also need to do that: autoconf, git, gcc/g++, and make. As an example, this is a complete Dockerfile for the latest stable release of PHP built on Alpine with the redis extension for php7 installed and enabled:
FROM php:alpine
RUN apk add --no-cache autoconf git g++ make
RUN \
git clone https://github.com/phpredis/phpredis.git && \
cd phpredis && \
git checkout php7 && \
phpize && \
./configure && \
make && make install && \
docker-php-ext-enable redis
If you want a smaller image you can remove the phpredis directory and the deps that were needed to clone and build it afterward. If you're not using an official PHP image then you will need to replace docker-php-ext-enable redis with a couple of commands to move the redis.so where you need it and add the extension=redis.so line to your PHP config.

You can find your solution here https://pkgs.alpinelinux.org/package/edge/community/x86_64/php7-redis

php7-redis is in v3.6 (released yesterday) and edge (rolling/unstable), as you can easily find yourself on pkgs.alpinelinux.org.
pecl is currently provided by package php7-pear.

Related

Cannot explain why Alpine apk upgrade command does not update ncurses package although a newer version exists

I have a Dockerfile as:
FROM nginx:1.21.3-alpine
RUN apk update && apk add bash \
&& apk upgrade
I can see that package ncurses is installed and the version is 6.2_p20210612-r0.
Now, There is a newer package available in the main repository edge branch with version 6.2_p20211002-r0 here.
As far as I understand after building an image from the above mentioned Dockerfile the version of ncurses should be updated to 6.2_p20211002-r0 BUT instead it stays as 6.2_p20210612-r0. I cannot understand why?
I confirmed this by running a container after build and running:
apk info -a ncurses
The output was:
ncurses-6.2_p20210612-r0 installed size:
284 KiB
The nginx:1.21.3-alpine image is based on Alpine 3.14 (see cat /etc/os-release), and therefore ncurses is updated with the version of the Alpine 3.14 repository, which is currently 6.2_p20210612-r0.
For installing ncurses from edge (currently version 6.2_p20211002-r0), you could specify the edge repository explicitly in the apk command:
apk add ncurses --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main
Mixing and matching packages from different repositories this way might be OK in some cases, but has to be tested carefully. For ncurses, some functionality might be broken, since the matching ncurses-libs package should be installed as well, but some of the package images depend on ncurses-libs, so re-installing it triggers update of these packages. Moreover, the nginx-module-njs dependent package must be removed. If this is acceptable, you could modify the Dockerfile as follows:
FROM nginx:1.21.3-alpine
RUN apk update && \
apk del ncurses ncurses-libs nginx-module-njs && \
apk add ncurses ncurses-libs --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main && \
apk add bash && \
apk upgrade

How to correctly install programs in docker?

I know that every line of RUN ... will add a layer to the docker image and that it is recommended to make RUN commands connected with &&. But my question is:
Is better this:
RUN apk update && apk upgrade \
&& apk add openssh \
&& apk add --update nodejs nodejs-npm \
&& npm install -g #angular/cli \
&& apk add openjdk11 \
&& apk add maven \
&& apk add git
Or this:
RUN apk update && apk upgrade
RUN apk add openssh
RUN apk add --update nodejs nodejs-npm
RUN npm install -g #angular/cli
RUN apk add openjdk11
RUN apk add maven
RUN apk add git
The first one creates just one layer but when a version of anything changes the image would have to start from the beginning, not from cash. The second approach will create more layers but when just the version of git changes only the git layer needs to be build again and all previous layers can be used from cash.
I'd recommend:
Install all the OS packages in a single apk invocation: there is some overhead in starting the package manager (more noticeable with dpkg/apt) and it is faster if you start it once and install several packages
If you need to run an update command, always run it in the same RUN command as your other package-manager steps. This avoids some trouble with Docker layer caching (again, very noticeable with apt) where docker build doesn't re-run update, but then it does try to run a changed install step; when it tries to install a package using yesterday's package index, the upload of that package that happened today deleted yesterday's file and the download will fail.
Don't npm install single packages. That means your package.json file is incomplete. Add it there.
I've seen recommendations both ways as to whether or not to run a full upgrade. Keeping up-to-date on security fixes is important; the underlying base images on Docker Hub also update pretty regularly. So if your image is FROM alpine:latest, doing a docker build --pull will get you much of the effect of an explicit apk upgrade.
Stylistically, if I need any substantial number of packages, I find the list a little more maintainable if I sort it alphabetically and put one package on a line, but this is purely personal preference.
Putting this all together would transform your example into:
RUN apk update \
&& apk upgrade \
&& apk add \
git \
maven \
nodejs \
nodejs-npm \
openjdk11 \
openssh
COPY package.json package-lock.json . # includes #angular/cli
RUN npm ci
Don't be afraid to use multiple containers, if that makes sense. (What's your application that uses both Java and Node together; can it be split into two single-language parts?) Don't install unnecessary developer-oriented tools in your image. (Does your application invoke git while it's running; do you install a dependency directly from GitHub; or can you remove git?) Don't try to run an ssh daemon in your container. (It breaks the "one process per container" rule which instantly makes things harder to manage; 90% of the SO examples have a hard-coded user password plus sudo rights, which is not really a security best practice; managing the credentials is essentially impossible.)
Both approaches are on the extreem, you need to try to minimize the layers for "reusability" at the same time to optimize for lower number of layers.
Based on your example, the build can be organized as follows:
RUN apk update && apk upgrade \
&& apk add openssh \
&& apk add --update nodejs nodejs-npm \
&& apk add openjdk11 \
&& apk add maven \
&& apk add git
RUN npm install -g #angular/cli \
Now I have only 2 layers, first one is bringing the OS packages and the second one dealing with the node.js packages. Now this can better be reused in other builds.
Once you have done this modification, you can move to multistage build where you will be able to better control and reuse the intermediate containers like in this example

How can I build a similar docker image based on alpine that works on ubuntu?

I am trying to rewrite a Dockerfile (https://github.com/orangefoil/rcssserver-docker/blob/master/Dockerfile) so that it uses alpine instead of ubuntu. Goal is to reduce the file size.
In the original image the robocup soccer server is built from scratch using g++, flex, bison, etc.
FROM ubuntu:18.04 AS build
ARG VERSION=16.0.0
WORKDIR /root
RUN apt update && \
apt -y install autoconf bison clang flex libboost-dev libboost-all-dev libc6-dev make wget
RUN wget https://github.com/rcsoccersim/rcssserver/archive/rcssserver-$VERSION.tar.gz && \
tar xfz rcssserver-$VERSION.tar.gz && \
cd rcssserver-rcssserver-$VERSION && \
./bootstrap && \
./configure && \
make && \
make install && \
ldconfig
I tried to do the same on alpine and had to exchange some packages:
FROM alpine:latest
ARG VERSION=16.0.0
WORKDIR /root
# Add basics first
RUN apk — no-cache update \
&& apk upgrade \
&& apk add autoconf bison clang-dev flex-dev boost-dev make wget automake libtool-dev g++ build-base
RUN wget https://github.com/rcsoccersim/rcssserver/archive/rcssserver-$VERSION.tar.gz
RUN tar xfz rcssserver-$VERSION.tar.gz
RUN cd rcssserver-rcssserver-$VERSION && \
./bootstrap && \
./configure && \
make && \
make install && \
ldconfig
Unfortunately, my version doesn't work yet. It fails with
/usr/lib/gcc/x86_64-alpine-linux-musl/9.3.0/../../../../x86_64-alpine-linux-musl/bin/ld: cannot find -lrcssclangparser
From what I found so far, this can happen, if dev packages are not installed (see ld cannot find an existing library), but I changed to dev packages where I could find them and still no luck.
So, my current assumption is that ubuntu has some package installed, that I need to add in my alpine image. I would exclude a code problem, since the ubuntu version works.
Any ideas, what could be missing? I would also be happy to understand how to compare the packages myself, but the package namings are not the same in ubuntu and alpine, so I find it pretty hard to figure this out.
You should break this up using a multi-stage build. In the image you're building now, the final image contains the C toolchain and all of the development libraries and headers that those -dev packages install; you don't need any of those to actually run the built application. The basic idea is to build the application exactly as you have it now, but then COPY only the built application into a new image with fewer dependencies.
This would look something like this (untested):
FROM ubuntu:18.04 AS build
# ... exactly what's in the original question ...
FROM ubuntu:18.04
# Install the shared libraries you need to run the application,
# but not -dev headers or the full C toolchain. You may need to
# run `ldd` on the built binary to see what exactly it needs.
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install --assume-yes --no-install-recommends \
libboost-atomic1.65.1 \
libboost-chrono1.65.1 \
# ... more libboost-* libraries as required ...
# Get the built application out of the original image.
# Autoconf's default is to install into /usr/local, and in a
# typical Docker base image nothing else will be installed there.
COPY --from=build /usr/local /usr/local
RUN ldconfig
# Describe how to run a container.
EXPOSE 12345
CMD ["/usr/local/bin/rcssserver"]
Compared to the size of the C toolchain, header files, and build-time libraries, the difference between an Alpine and Ubuntu image is pretty small, and Alpine has well-documented library compatibility issues with its minimal libc implementation.

How can we install google-chrome-stable on alpine image in dockerfile using dpkg?

I am trying to install google-chrome-stable on alpine image using dpkg. However, the dpkg is installed but it does not install google-chrome-stable and return this error instead? Is there a way to install google-chrome-stable in alpine image either using dpkg or other way?
dpkg: regarding google-chrome-stable_current_amd64.deb containing
google-chrome-stable:amd64, pre-dependency problem:
google-chrome-stable:amd64 pre-depends on dpkg (>= 1.14.0)
dpkg: error processing archive google-chrome-stable_current_amd64.deb (--install):
pre-dependency problem - not installing google-chrome-stable:amd64
Errors were encountered while processing:
Dockerfile:
# Base image
FROM ruby:2.6.3-alpine3.10
# Use node version 10.16.3, yarn version 1.16.0
RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.10/main/ nodejs=10.16.3-r0
RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.10/community/ yarn=1.16.0-r0
# Install dependencies
RUN apk upgrade
RUN apk --update \
add build-base \
git \
tzdata \
nodejs \
nodejs-npm \
bash \
curl \
yarn \
gzip \
postgresql-client \
postgresql-dev \
imagemagick \
imagemagick-dev \
imagemagick-libs \
chromium \
chromium-chromedriver \
ncurses \
less \
dpkg=1.19.7-r0 \
chromium \
chromium-chromedriver
RUN dpkg --add-architecture amd64
RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
RUN dpkg -i google-chrome-stable_current_amd64.deb
# This is the base directory used in any
# further COPY, RUN and ENTRYPOINT commands
WORKDIR /webapp
# Copy Gemfile and Gemfile.lock and run bundle install
COPY Gemfile* /webapp/
RUN gem install bundler -v '1.17.3' && \
bundle _1.17.3_ install
# Copy everything to /webapp for docker image
COPY . ./
EXPOSE 3000
# Run the application
CMD ["rails", "server", "-b", "0.0.0.0"]
Installing the Chrome .deb file this way won't work on Alpine.
While the dpkg package is available in the Alpine repository, and is useful for installing lightweight Debian packages, you won't be able to use it for installing complex Debian packages, since it'll be impossible to satisfy many Debian dependencies. Alpine is generally not Debian compatible (relying on musl libc), so installing native Alpine packages using apk is the right way to go.
AFAIK, there's currently no Google Chrome Alpine Linux compatible, musl-libc build.
You could, however, install the Chromium browser, which is available using an apk package:
apk add chromium
Another option is enabling glibc on a vanilla Alpine image, making it compatible with Debian binaries. This is a fairly simple procedure, see: Dockerfile. However, it may not be suitable for images with existing applications such as ruby:2.6.3-alpine3.10. Moreover, even with a glibc setup on Alpine, Chrome is not likely to run without issues. I have made a quick attempt (Dockerfile) but couldn't get past the first segfault.
Edit 9/5/21: Running the debian compatible Chrome stable on Alpine is going to be a very difficult task to say the least. This is in part due to the very large number of dependencies and libraries. Trying to run it results with segfaults during dynamic linking and finally assertions from the dynamic linker. Even if we manage to get passed these issues and start Chrome it will probably be very unstable.
Since chromium-chromedriver is presented in your package list, I suppose that you want to do browser automation.As to browser automation, I used java and selenium, and download chromium binary and chromium driver binary manually.
What the most I want to tell you is that the chromium binary and chromium driver binary bundle might not work as expected, and you need to downgrade the version of either chrome driver or chrome and make several trial to find a matched versions that really work, no matter whether you use node.js or java selenium.
With Selenium, you have another option that you can deploy the chrome and chromedriver bundle as a http service in a different server, and make selenium invoke the remote chrome service.
ChromeDriver for version 93.0.4577.15

How do I install a specific version of Chrome in a Dockerfile?

Have a Dockerfile that installs from a python image and then I need it to install a specific (not latest) version of Google Chrome.
Here's what I have:
FROM python:3.6
# Tools
RUN apt-get update \
&& apt-get install -y vim less \
&& apt-get clean
# https://github.com/SeleniumHQ/docker-selenium/blob/master/NodeChrome/Dockerfile.txt
#============================================
# Google Chrome
#============================================
# can specify versions by CHROME_VERSION;
# e.g. google-chrome-stable=53.0.2785.101-1
# google-chrome-beta=53.0.2785.92-1
# google-chrome-unstable=54.0.2840.14-1
# latest (equivalent to google-chrome-stable)
# google-chrome-beta (pull latest beta)
#============================================
ARG CHROME_VERSION="google-chrome-stable"
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list \
&& apt-get update -qqy \
&& apt-get -qqy install \
${CHROME_VERSION:-google-chrome-stable} \
&& rm /etc/apt/sources.list.d/google-chrome.list \
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/*
The Chrome installation steps were taken from here (as seen in the comments) and even using the version in the example I get the error
E: Version '53.0.2785.101-1' for 'google-chrome-stable' was not found
Tried other versions from https://chromereleases.googleblog.com/ and nothing works.
Do you know of a different way to install a specific version or if I'm doing something wrong with these steps?
This took me a while to find, but you're installing from Google's repository and they only keep the latest versions of Google Chrome in their repositories. You could probably search for 3rd party repositories that have older versions of Chrome, but I personally wouldn't recommend that.
The current version is 75.0.3770.100-1 for google-chrome-stable at the time of this post. Will that not work for you?
Lastly, I directly copied your dockerfile and it worked for me with the latest build of google-chrome-stable installed on the image. How were you running docker?
Here was my process:
Copied your docker file directly into ./Dockerfile
docker build ./
docker image ls
Copied my image id (90206843f24e in my case)
docker run --entrypoint "/bin/bash" -it 90206843f24e
You'll be dropped in a root shell on the docker image to "poke" around
run google-chrome -version to verify the above version is installed
I hope this works for you. Good luck and keep us posted!

Resources