Cannot change file owner in docker container

Hi,

I have a docker-compose that works fine on local and wanted to run it on github actions so I can run my unit tests everytime I push my repo.

So basically I have a dockerfile that uses an Alpine image to build php on it. This dockerfile creates the www user, and then uses COPY --chown www:www to copy my project inside the container with the right file ownerships.

The thing is, when using actions/checkout on github actions, building the container, and then list the owners of the container files, they all belong to the runner user of the github host. I have tried using RUN chown -R www:www on the dockerfile too, but it didn’t work either. I also tried to run the chown command directly on the github actions file but got a permission denied from the alpine-php container.

Do you guys understand what’s going on ?

Here’s my Alpine-php dockerfile :

 FROM alpine:3.12

# Set working directory
WORKDIR /var/www

# Need the root user for apt
USER root
# Install dependencies
RUN apk --update add \
        build-base \
        php7 \
        php7-bcmath \
        php7-dom \
        php7-ctype \
        php7-curl \
        php7-fpm \
        php7-gd \
        php7-iconv \
        php7-intl \
        php7-json \
        php7-mbstring \
        php7-mcrypt \
        php7-mysqlnd \
        php7-opcache \
        php7-openssl \
        php7-pdo \
        php7-pdo_mysql \
        php7-pdo_pgsql \
        php7-pdo_sqlite \
        php7-phar \
        php7-posix \
        php7-session \
        php7-soap \
        php-xml \
        php7-xml \
        php7-zip \
        php7-xml \
        curl \
        php7-pear \
        php7-dev \
        php7-gettext \
        libzip-dev \
    && rm -rf /var/cache/apk/*

# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# MongoDB extension
RUN pecl channel-update pecl.php.net
RUN pecl install mongodb \
    && pecl clear-cache
RUN echo "extension=mongodb.so" > /etc/php7/conf.d/mongodb.ini

# Add user
RUN addgroup -S www && adduser -S www -G www

# Copy existing application directory permissions
COPY --chown=www:www . /var/www/
# Remove default nobody user and group so that www is the default one
RUN sed -i "s|user = nobody||g" /etc/php7/php-fpm.d/www.conf
RUN sed -i "s|group = nobody||g" /etc/php7/php-fpm.d/www.conf
# Allow php to access env variables
RUN sed -i "s|;clear_env = no|clear_env = no|g" /etc/php7/php-fpm.d/www.conf
# Allow remote connections
RUN sed -i "s|listen = 127.0.0.1:9000|listen = 9000|g" /etc/php7/php-fpm.d/www.conf
# Allow to write on logs
RUN chown -R www:www /var/log/php7
# Change current user to www
USER www

# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm7", "-F"]

the docker-compose file :

 version: '3.5'
services:

  #PHP Service
  app:
    image: docker.pkg.github.com/smsfactor/plateforme/plateforme-app:0.6
    container_name: plateforme-app
    restart: unless-stopped
    tty: true
    environment:
      SERVICE_NAME: plateforme-app
      SERVICE_TAGS: dev
    working_dir: /var/www
    networks:
      - plateforme-network
    volumes:
      - .:/var/www
      - ./docker/php/local.ini:/usr/local/etc/php7/conf.d/

  #Nginx Service
  webserver:
    image: nginx:alpine
    container_name: plateforme-webserver
    restart: unless-stopped
    tty: true
    ports:
      - "8087:80"
      - "44307:443"
      - "8088:8088"
      - "44308:44308"
    networks:
      - plateforme-network
    volumes:
      - .:/var/www
      - ./docker/nginx/conf.d/:/etc/nginx/conf.d/
      - ./docker/nginx/plateforme.crt:/etc/nginx/plateforme.crt
      - ./docker/nginx/plateforme.key:/etc/nginx/plateforme.key

#Docker Networks
networks:
  plateforme-network:
    driver: bridge

the github actions file :

name: Continuous Integration
# This workflow is triggered on pushes to the repository.
on: [push]

jobs:
  build:
    name: Unit Tests
    runs-on: ubuntu-16.04
    services:
      mysql:
        image: mysql:5.7
        env:
          MYSQL_ROOT_PASSWORD: root
        ports:
        - 3306:3306
        options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5 --name mysql

      # Label used to access the service container
      redis:
        # Docker Hub image
        image: redis
        # Set health checks to wait until redis has started
        options: >-
          --health-cmd "redis-cli ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
          --name redis
        ports:
          # Maps port 6379 on service container to the host
          - 6379:6379

    steps:

    - name: Checkout
      uses: actions/checkout@v2

    - name: Log in to registry
      run : docker login docker.pkg.github.com --username smsfactor --password ${{ secrets.GITHUB_TOKEN }}

    - name: Setup Nginx + PHP with docker-compose
      run: docker-compose up --build -d

    - name: Docker-compose logs
      if: ${{ always() }}
      run: |
        cat /etc/passwd
        docker-compose exec -T app ls -la

Actions output :

cat /etc/passwd

runner:x:1001:118:,,,:/home/runner:/bin/bash

docker-compose exec -T app ls -la


total 288
drwxr-xr-x   17 1001     118           4096 Jul  8 08:05 .
drwxr-xr-x    1 root     root          4096 Jun 23 15:02 ..
drwxr-xr-x    8 1001     118           4096 Jul  8 08:05 .git
drwxr-xr-x    3 1001     118           4096 Jul  8 08:05 .github
-rwxr-xr-x    1 1001     118            557 Jul  8 08:05 .gitignore
drwxr-xr-x    3 1001     118           4096 Jul  8 08:05 .idea
-rwxr-xr-x    1 1001     118             13 Jul  8 08:05 README.md
drwxr-xr-x    7 1001     118           4096 Jul  8 08:05 api
-rw-r--r--    1 1001     118            245 Jul  8 08:05 codeception.yml

Sorry for the delay response. It spent me quite a time to reproduce and troubleshoot this issue.
I tried in my local machine, using docker-compose also has the same issue. The owner of files are root, not www.

version: '3.5'
services:

  #PHP Service
  app:
   ......
    volumes:
      - .:/var/www
      - ./docker/php/local.ini:/usr/local/etc/php7/conf.d/

Finally, I found that In your docker-compose file you added a volume from current working folder (on the hosted runner machine $GITHUB_WORKSPACE ) to /var/www (inside container).
This will cover all the existing files under /var/www inside container. And the owner of files on hosted runner is runner.
I would recommend you modify the volume setting of docker-compose file .

@yanjingzhu Thank you very much for your reply, you’re absolutely right about the volume being the cause of my issue. Removing the bind solves my issue on Github Actions, which is great, but now, when I’m in the dev environment, my changes on files aren’t taken into account dynamically by the container, which is annoying. What would be the best approach here to you ?

Is your repo a public one? If possible, please share the repo links here.

According to your docker-compose file , the plateforme-app container image is docker.pkg.github.com/smsfactor/plateforme/plateforme-app:0.6. If your changes are not included by the volumes, the container will not be impacted.

It’s a private repo and I used to be able to change my local files so it was dynamically changed also inside the container, which is quite convenient when coding. I found a way to deal with that by using the -f option when launching my container so it can take a second config file. In this second file I mount the desired volume so that I can use it only in dev environment. The only issue now is that I’m having issue with permissions as the container user doesn’t have the permission to write on host files (which makes sense security wise), but I’ll figure it out sooner or later and my initial question has already been answered thanks to you.

1 Like