I try to use gcsfuse in order to store application source code on a GCP bucket, here's my Dockerfile:

ARG VERSION

FROM golang:1.12.5-alpine3.9 as gcsfuse-builder

ENV GOPATH /go

RUN apk --update add git=2.20.1-r0 fuse=2.9.8-r2 fuse-dev=2.9.8-r2 \
    && go get -u github.com/googlecloudplatform/gcsfuse

FROM php:$VERSION as base

ARG REVISION

ENV APP_DIR=/srv/app \
    APP_ENV=prod \
    APP_FRONT_CONTROLLER=index.php \
    APP_LOCALE=fr \
    APP_USER=test-user \
    APP_USER_GROUP=test \
    APP_PORT=8080 \
    COMPOSER_ALLOW_SUPERUSER=1 \
    NGINX_DIR=/etc/nginx \
    NGINX_VERSION=1.14.2-r1 \
    PHP_FPM_CONF_DIR=/usr/local/etc/php-fpm.d/ \
    SUPERVISORD_CONF_DIR=/etc/supervisor \
    SUPERVISOR_VERSION=3.3.4-r1 \
    BUILD_SCRIPTS_DIR=/build-scripts \
    GOOGLE_APPLICATION_CREDENTIALS=/srv/app/bucket.json

# Supervisord conf to be copied at the end.
COPY docker/prod/php/scripts/*.sh $BUILD_SCRIPTS_DIR/

# Core dependencies installation (installed as a virtual package in order to remove it later)
RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS \
    && apk add --no-cache --virtual .fuse-deps curl sshfs fuse \
    && apk add --no-cache --virtual .bash bash=4.4.19-r1 \
    && apk add --no-cache --virtual .core-php-deps icu-dev=62.1-r0 \
    && rm -rf /var/cache/apk/* \
    && docker-php-ext-install \
        intl \
        opcache \
    && docker-php-ext-configure intl \
    && docker-php-ext-enable opcache \
    && apk del .build-deps .phpize-deps-configure

# User creation
RUN apk add --no-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ --allow-untrusted --virtual .user-deps gosu=1.10-r0 \
    && rm -rf /var/cache/apk/* \
    && addgroup $APP_USER_GROUP \
    && adduser -D -h /home/portfolio -s /bin/bash -G $APP_USER_GROUP $APP_USER \
    && chown -R $APP_USER $BUILD_SCRIPTS_DIR \
    && apk del .user-deps

# Nginx & Supervisor installation
RUN apk add --no-cache --virtual .http-deps nginx=$NGINX_VERSION supervisor=$SUPERVISOR_VERSION \
    && rm -rf /var/cache/apk/* \
    && ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log

# Filesystem (gcsfuse)
COPY --from=gcsfuse-builder /go/bin/gcsfuse /usr/local/bin
COPY bucket.json $APP_DIR/bucket.json

# Filesystem (gcsfuse binding)
RUN apk add --no-cache --virtual .filesystem-deps curl fuse fuse-dev rsync \
    && mkdir -p $APP_DIR $BUILD_SCRIPTS_DIR \
    && chown -R $APP_USER $APP_DIR \
    && chmod -R 755 $APP_DIR \
    && gcsfuse mybucketname $APP_DIR

COPY docker/prod/php/conf/php.ini $PHP_INI_DIR/php.ini
COPY docker/prod/php/conf/fpm.conf $PHP_FPM_CONF_DIR/fpm.conf
COPY docker/prod/nginx/conf/nginx.conf $NGINX_DIR/nginx.conf
COPY docker/prod/supervisord/supervisord.conf $SUPERVISORD_CONF_DIR/supervisord.conf

# Used to check that PHP-FPM works
HEALTHCHECK --interval=5s --timeout=3s \
  CMD curl -f http://localhost/ping || exit 1

# Production build
FROM base as production

COPY docker/prod/nginx/conf/test.conf $NGINX_DIR/conf.d/test.conf

WORKDIR $APP_DIR

COPY . .

# The vendors are installed after the whole project is copied, this way, we can dump the autoload properly.
# The unrequired directories are also removed.
RUN /bin/bash "$BUILD_SCRIPTS_DIR/install_composer.sh" \
    && /bin/bash "$BUILD_SCRIPTS_DIR/composer_dependencies.sh" \
    && rm -rf $BUILD_SCRIPTS_DIR \
        /usr/bin/git* \
        /lib/apk/db/installed \
        /usr/local/bin/composer \
        node_modules/

EXPOSE $APP_PORT 443

CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/supervisord.conf"]

The image can be built without gcsfuse but when the build use:

gcsfuse mybucketname $APP_DIR

Here's the error that I encounter:

fusermount: fuse device not found, try 'modprobe fuse' first

Is there any workaround to get it working during docker build?

Thanks for the support


Install gcsfuse only in build phase. Put the gcsfuse mount part in script and use the script in CMD.

Then run your container with --privileged


You must expose /dev/fuse from the command line or from docker-compose.yml and set privileged:

myproject:
  privileged: true
  devices:
    - "/dev/fuse:/dev/fuse"

My Dockerfile adapted from Ernest's docker-gcsfuse:

FROM golang:alpine AS builder
ARG GCSFUSE_VERSION=0.27.0
RUN apk --update --no-cache add git fuse fuse-dev;
RUN go get -d github.com/googlecloudplatform/gcsfuse
RUN go install github.com/googlecloudplatform/gcsfuse/tools/build_gcsfuse
RUN build_gcsfuse ${GOPATH}/src/github.com/googlecloudplatform/gcsfuse /tmp ${GCSFUSE_VERSION}

COPY --from=builder /tmp/bin/gcsfuse /usr/bin
COPY --from=builder /tmp/sbin/mount.gcsfuse /usr/sbin
RUN ln -s /usr/sbin/mount.gcsfuse /usr/sbin/mount.fuse.gcsfuse
WORKDIR /

Mount through fstab (key_file is optional):

echo "$BUCKET $MOUNTPOINT gcsfuse rw,user,noauto,key_file=$KEYFILE_PATH" >> /etc/fstab
mount.gcsfuse $BUCKET $MOUNTPOINT

When using last versions of go, you need to use GO111MODULE=off to avoid errors.

FROM golang:alpine AS builder
ARG GCSFUSE_VERSION=0.27.0
ENV GO111MODULE=off
RUN apk --update --no-cache add git fuse fuse-dev;
RUN go get -d github.com/googlecloudplatform/gcsfuse
RUN go install github.com/googlecloudplatform/gcsfuse/tools/build_gcsfuse
RUN build_gcsfuse ${GOPATH}/src/github.com/googlecloudplatform/gcsfuse /tmp ${GCSFUSE_VERSION}

FROM alpine
COPY --from=builder /tmp/bin/gcsfuse /usr/bin
COPY --from=builder /tmp/sbin/mount.gcsfuse /usr/sbin
RUN ln -s /usr/sbin/mount.gcsfuse /usr/sbin/mount.fuse.gcsfuse