4

First things first:

  1. Alpine Version 3.9.0
  2. perf[from:http://dl-cdn.alpinelinux.org/alpine/edge/testing] 4.18.13
  3. Docker 18.09.3 build 774a1f4

My Dockerfile

FROM alpine:latest

# Set the working directory to /app
WORKDIR /app/

# Install any needed packages specified in requirements.txt
RUN yes | apk add vim
RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a  /etc/apk/repositories
RUN apk add --update perf

The problem, these are commands ran inside the container:

/ # cat /proc/sys/kernel/perf_event_paranoid 
-1
/ # perf stat -d sleep 1
Error:
No permission to enable task-clock event.

You may not have permission to collect stats.

Consider tweaking /proc/sys/kernel/perf_event_paranoid,
which controls use of the performance events system by 
unprivileged users (without CAP_SYS_ADMIN).

The current value is -1:

   -1: Allow use of (almost) all events by all users
       Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK
 >= 0: Disallow ftrace function tracepoint by users without CAP_SYS_ADMIN
       Disallow raw tracepoint access by users without CAP_SYS_ADMIN
 >= 1: Disallow CPU event access by users without CAP_SYS_ADMIN
 >= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN

 To make this setting permanent, edit /etc/sysctl.conf too, e.g.:

      kernel.perf_event_paranoid = -1

 / # 

The command for launching the image:

docker run -it --mount type=tmpfs,tmpfs-size=512M,destination=/app/ alpy

I've worked with perf for a long time. But, this is a first. Does anyone know why perf knows I have permission to profile, but won't let me do so?

Thank you.

2 Answers2

13

The problem is that Docker by default blocks a list of system calls, including perf_event_open, which perf relies heavily on.

Official docker reference: https://docs.docker.com/engine/security/seccomp/

Solution:

  • Download the standard seccomp(secure compute) file for docker. It's a json file.
  • Find "perf_event_open", it only appears once, and delete it.
  • Add a new entry in syscalls section:

    { "names": [ "perf_event_open" ], "action": "SCMP_ACT_ALLOW" },

  • Add the following to your command to run the container: --security-opt seccomp=path/to/default.json

That did it for me.

  • This worked ! But the latest json now has 2 mentions of perf_event_open, i deleted both – Kira Mar 10 '23 at 08:47
1

Just F.Y.I for those who want to run perf on Alpine via docker-compose.

tl; dr

  • Add the below 2 entries into the services you wan to use perf.
    cap_add:
      - SYS_PTRACE
    security_opt:
      - seccomp:unconfined
  • Note that the security option was set to unconfined, so you must know what you are running.

ts; dr

  • Dockerfile
FROM ${BASEIMAGE}

RUN \
    apk add --no-cache perf && \
    # Smoke-test
    perf --version
  • docker-compose.yml
version: "3.9"
services:
  go:
    build:
      context: .
      dockerfile: ./Dockerfile
      args:
        BASEIMAGE: golang:alpine
    volumes:
      - .:/tmp/bench
    working_dir: /tmp/bench
    cap_add:
      - SYS_PTRACE
    security_opt:
      - seccomp:unconfined
    entrypoint: [ "perf", "stat", "-r5", "go", "run", "./fibonacci.go" ]
  python:
    build:
      context: .
      dockerfile: ./Dockerfile
      args:
        BASEIMAGE: python:3-alpine
    volumes:
      - .:/tmp/bench
    working_dir: /tmp/bench
    cap_add:
      - SYS_PTRACE
    security_opt:
      - seccomp:unconfined
    entrypoint: [ "perf", "stat", "-r5", "python", "./fibonacci.py" ]

  • Shell session
$ docker-compose build
** snip **

$ docker-compose run go
9227465
9227465
9227465
9227465
9227465

 Performance counter stats for 'go run ./fibonacci.go' (5 runs):

            566.09 msec task-clock:u              #    1.336 CPUs utilized            ( +-  3.43% )
                 0      context-switches:u        #    0.000 /sec                   
                 0      cpu-migrations:u          #    0.000 /sec                   
             10864      page-faults:u             #   20.656 K/sec                    ( +-  3.77% )
   <not supported>      cycles:u                                                    
   <not supported>      instructions:u                                              
   <not supported>      branches:u                                                  
   <not supported>      branch-misses:u                                             

            0.4236 +- 0.0186 seconds time elapsed  ( +-  4.40% )

$ docker-compose run python
9227465
9227465
9227465
9227465
9227465

 Performance counter stats for 'python ./fibonacci.py' (5 runs):

           4487.88 msec task-clock:u              #    0.987 CPUs utilized            ( +-  0.40% )
                 0      context-switches:u        #    0.000 /sec                   
                 0      cpu-migrations:u          #    0.000 /sec                   
               949      page-faults:u             #  209.758 /sec                     ( +- 88.64% )
   <not supported>      cycles:u                                                    
   <not supported>      instructions:u                                              
   <not supported>      branches:u                                                  
   <not supported>      branch-misses:u                                             

            4.5453 +- 0.0175 seconds time elapsed  ( +-  0.39% )

$ # Env info
$ docker --version
Docker version 20.10.11, build dea9396
$ docker-compose --version
Docker Compose version v2.2.1
$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.7
BuildVersion:   19H1615
KEINOS
  • 1,050
  • 2
  • 13
  • 32