3
\$\begingroup\$

I had to do a CLI script that does something, I also had to add a validation that checks if it runs inside the Docker. After some research I found a solution that people check some processes via cat /proc/self/cgroup and then grep to search for a docker phrase within.

So I ended-up with this method. It works pretty well. Inside docker it returns true, while on my local mac it returns false.

It's not rocket science however I would like people to take a look and tell me if this is a sufficient method or a completely different approach is better.

private function isDocker(): bool
{
    $processStack = explode(PHP_EOL, shell_exec('cat /proc/self/cgroup'));
    $processStack = array_filter($processStack); // remove empty item made by EOL

    foreach ($processStack as $process) {
        if (strpos($process, 'docker') === false) {
            return false;
        }
    }

    return true;
}

Later call to this script looks like:

if ($this->isDocker() === false) {
    throw new \Exception('This helper script can be called only inside Docker container.' . "\n");
}
\$\endgroup\$
0

3 Answers 3

2
\$\begingroup\$

For this simple method, I have a couple thoughts below. Your method seems sufficient; I don't think a completely different approach is necessary, although I question how often this method is called. If it is called more than once per page load/script run, it may be worth memoizing the value once obtained for better performance.


Good job utilizing the PHP 7 return type declaration.


Because the method utilizes no instance properties or methods, it could be declared as static, and possibly public so other code could use it, though maybe it is best to leave it as private until there is a legitimate need to make it otherwise.


While the logic would need to be reversed, substr_count() could be used instead of strpos(). The difference is likely negligible but you need to ask yourself in which case would you rather have the method return as soon as the string is or isn't found...

    foreach ($processStack as $process) {
        if (substr_count($process, 'docker')) {
            return true;
        }
    }
    return false;
\$\endgroup\$
2
\$\begingroup\$

in my humble opinion, maybe a ...

    $processStack = explode(PHP_EOL, shell_exec('cat /proc/self/cgroup | grep docker'));
    $processStack = array_filter($processStack); 
    return count($processStack) > 0;

... would be slightly more straightforward, as this follows the same logic but spares an unnecessary foreach loop and is less verbose; since the OP was checking if the term docker was present in the cgroup to determine if the script was running in a Docker env.

Using | grep docker allows us to have an already filtered process stack; that way we only need to check if the array has a length superior to 0 to achieve the same result: knowing if we are on Docker, hence the return count($processStack) > 0

\$\endgroup\$
3
  • \$\begingroup\$ Please argue: how is using three "external processes" instead of two (or even none…) more straightforward? \$\endgroup\$
    – greybeard
    Commented Jan 2, 2022 at 5:09
  • \$\begingroup\$ hey @greybeard, I edited my answser, hope it's clearer; I did not change the OP logic to verify if in Docker, I just tried to reduce the amount of code, hence the more straightforward \$\endgroup\$
    – yactouat
    Commented Jan 2, 2022 at 13:36
  • \$\begingroup\$ (Well, now it mentions what you consider more straightforward. But having a shell pipe the output of a cat single_file to another command uses an extra process if cat is not built-in to that shell, given a shell's input redirection mechanism. Then, many commands take file-name parameters - including grep. The shell could filter the words in /proc/self/cgroup all by itself. So could PHP, using class Directory or open/read/closedir().) \$\endgroup\$
    – greybeard
    Commented Jan 2, 2022 at 14:22
2
\$\begingroup\$

I'd use this simpler way to detect docker:

private function isDocker(): bool
{
    return is_file("/.dockerenv");
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.