Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting CPU and Memory usage of a docker container from within the dockerized application

I'm running a node.js application from within a docker container. I'm trying to retrieve system usage metrics of the container the node.js application is running inside of. Right now I'm using https://www.npmjs.com/package/dockerstats but it consistently shows no cpu or memory usage, running docker stats shows usage in each.

My code resembles the following:

let dockerId = setUp.getDockerId();
dockerId.then(dockerId => {
    if (dockerId !== null) {
            console.log(`dockerId: ${dockerId}`);
            dockerstats.dockerContainerStats(dockerId, data => {
                console.log(`cpu_percent: ${data.cpu_percent}`);
                console.log(`memPercent: ${data.memPercent}`);
                console.log(`memUsage: ${data.memUsage}`);
            });
        }
    });

The setUp class resembles the following and uses https://www.npmjs.com/package/docker-container-id:

const getId = require('docker-container-id');
module.exports = class setUp {

    getDockerId () {
        return getId().then(id => {
            if (!id) {
                return null;
            }
            return id;
        });
    }
}
like image 703
user5186815 Avatar asked Jul 09 '18 14:07

user5186815


2 Answers

As you said, you are using the docker-container-id package to obtain the container ID. This package works by inspecting the /proc/self/cgroup file, thus it should work only from inside the container (i.e. only when getContainerId() is executed from the containerized process). That said, further I will assume that you are trying to obtain the metrics from inside the container where your application runs (you did not mentioned this fact explicitly).

The problem here is that, as stated in the dockerstats package description, this package uses Docker API and, as per package source, the client connects to the docker socket (/var/run/docker.sock), which is is not available inside the container by default. The easy (but dangerous) way to workaround this is to mount host's /var/run/docker.sock into the container by using the following option when starting the container:

-v /var/run/docker.sock:/var/run/docker.sock

E.g.

docker run -v /var/run/docker.sock:/var/run/docker.sock $MY_IMAGE_NAME

However, this is STRONGLY DISCOURAGED, as it creates a serious security risk. Never do this in production. By doing so, you are allowing your container to control Docker, which is essentially the same as giving the container root access to the host system.

But you actually don't need to use the Docker API to access resource consumption metrics. The point is that you may directly read the information about process' cpuacct and memory control groups (which are responsible for tracking and limiting the CPU and the memory consumption respectively) from /sys/fs/cgroup. For example, reading the /sys/fs/cgroup/memory/memory.usage_in_bytes file will give you the amount of memory used by your container (in bytes):

# cat /sys/fs/cgroup/memory/memory.usage_in_bytes 
164823040

And reading the /sys/fs/cgroup/cpuacct/cpuacct.usage file will give you a total CPU usage of your container (in nanoseconds):

# cat /sys/fs/cgroup/cpuacct/cpuacct.usage
2166331144

So, you can read these metrics from your application and process them. Also you may use statistics from procfs, refer to this discussion for details.

like image 74
Danila Kiver Avatar answered Oct 27 '22 03:10

Danila Kiver


As I do not have enough reputation to comment, I would like to complement the answer from @danila-kiver with a quick way to check the memory usage in Megabytes:

cat /sys/fs/cgroup/memory/memory.usage_in_bytes | awk '{ byte =$1 /1024/1024; print byte " MB" }'

Or in Gigabytes:

cat /sys/fs/cgroup/memory/memory.usage_in_bytes | awk '{ byte =$1 /1024/1024/1024; print byte " GB" }'

For anyone in need.

like image 25
Douglas Quintanilha Avatar answered Oct 27 '22 04:10

Douglas Quintanilha