30

I just started working with Docker and Kubernetes and I've been watching a lot of stacks, in which some people build nginx+php in a single image and some build an image with nginx and another one with php (mounting the same path and enclosing both containers in the same deployment in Kubernetes).

What would be the advantages of building two docker images instead of installing both nginx+php in the same one?

CarlosAS
  • 435
  • 1
  • 5
  • 9

4 Answers4

22

PHP with nginx is usually done using php-fpm which is a separate processus.

Keeping the core idea of docker of one process (see end of answer for more details on this point) per container this makes sense to have the nginx process and php-fpm process in separate containers.

As the communication between nginx and php-fpm arise through fastcgi the php-fpm container can also be on a separated host and this allows using a cluster of php-fpm containers behind nginx.

After the wall of comment here's a little more background, docker documentation have paragraph about the idea that a container should have only one concern.

The main idea of a linux container (lxc) is to run a process in an isolated namespace at the cpu and memory level, docker add on top of this an isolation at the filesystem level.
The advantage is that the compromission of a process within this namespace won't allow to read memory of other processes and as such should prevent other compromission on the host.

While talking about nginx and php-fpm, they work in pair but each has it's own concern, nginx will do the HTTP part, routing, headers validation, etc. and php-fpm will do the code interpretation and return the html part to nginx. While it's usual to have both together serving a single application that's not mandatory.

Depending on context it may be easier to have a container including the whole stack for an application, on a developer workstation for exemple. But ideally for production use, try to keep the fewer interaction inside the container, having separated processes in the same container with supervisord brings its share of problem in term of zombie process and log handling (exemple story here for illustration purpose only).

So finally I'll quote the docker page with some emphasis:

While “one process per container” is frequently a good rule of thumb, it is not a hard and fast rule. Use your best judgment to keep containers as clean and modular as possible.

There's no "silver bullet rule" which apply to everything, it's always a balance between the complexity within the container and the complexity orchestrating the containers themselves.

Tensibai
  • 11,366
  • 2
  • 35
  • 62
  • 4
    The core idea is actually "Each container should have only one concern", and "it is not necessarily true that there should be only one operating system process per container". https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#avoid-installing-unnecessary-packages – user2640621 Sep 20 '17 at 10:41
  • I admit it's a shortcut to strike the idea, nginx is not a single monolithic process nor is php-fpm, but replace process by concern in my answer and it is still OK nginx does the routing, php-fpm does the interpretation – Tensibai Sep 20 '17 at 10:54
  • 3
    The answer is usually one service one port per container, not really one process. On the other hand, if you have multiple running processes in a container, you need to consider some init process, service management, restarts, independent logging, independent package dependencies, it gets a bit more complicated. And sometimes 1:1 mapping turns into 1:n mapping when scaling. – Jiri Klouda Sep 20 '17 at 16:26
  • @Jiri playing devil's advocate: so a apache in front of a rails app using a postgres DB should go within the same container? That's just one service in an external point of view after all. – Tensibai Sep 20 '17 at 18:27
  • It is context dependent, but it might be the case. It all depends on the architecture. But one could argue that in cases where that would be the case, some more lightweight technology choices could have been made. – Jiri Klouda Sep 20 '17 at 18:32
  • @Jiri this also mean you're defeating the purpose of namespacing the processes as a breach in one can allow access to the memory of all others, and so using a container doesn't make more sense than using a host. (the opposite argument, which I tend to follow for production use to avoid a web server flaw allowing to read the DB memory) – Tensibai Sep 20 '17 at 18:45
  • @jiri I mean the only valid context I can think of for this is a container running on a dev workstation for tests purposes before a push, not something to advertise too much as an entry point. And this question is an entry point – Tensibai Sep 20 '17 at 18:51
  • It is all about deployment. If there is a complex service that requires 7-8 processes to run and orchestrate, you are pulling all the orchestration outside the container. So some form of deployment instructions need to travel with the containers to orchestrate them properly, the other containers are potentially exposed to unless you have security profile accompany it, its a mess. – Jiri Klouda Sep 22 '17 at 01:55
  • 1
    @JiriKlouda answer amended, I hope it's detailed enough to convey all the points raised in comments. – Tensibai Sep 22 '17 at 08:34
  • @user2640621 I've amended my answer, I'm taker of your feedback on this version – Tensibai Sep 22 '17 at 08:34
5

There is no meaningful benefit that outweighs having to manage two containers. As long as you have a 1:1 relationship between the processes and they serve a single purpose, put them in the same container.

user2640621
  • 1,395
  • 8
  • 20
  • Do you mean different images on the same container? – CarlosAS Sep 20 '17 at 13:06
  • How will you start nginx and php-fpm in the same container? Please add an example. – 030 Sep 20 '17 at 14:49
  • 1
    @030 here an example – CarlosAS Sep 20 '17 at 15:24
  • 2
    @carlos Very valid exemple for dev purposes, I'd block this kind of things for production use (running supervisord within a container can turn in a footgun quite easily) – Tensibai Sep 20 '17 at 17:41
  • I disagree with that answer, with this reasoning a apache server with mod security talking to a tomcat talking to a postgresql server hosting only one app should fit within a single container. – Tensibai Sep 20 '17 at 18:30
  • @Tensibi your example doesn't apply to my answer, because a database doesn't have a 1:1 relationship to a web/app service. You normally have many applications talking to few database servers. If it was a distributed database and you never needed any other service to speak to it, then it might be worth considering. A modsec layer is usually shared across services, so I also do not think it applies here. – user2640621 Sep 20 '17 at 22:19
  • @CarlosAS Thank you for adding a link to an example. The dockerfile is quite large and that makes it more difficult to troubleshoot possible issues. I prefer that every container has its own responsibility. – 030 Sep 20 '17 at 22:27
  • @user one DB per app to avoid DB impact from one app to another. I agree the comment was a tad caricatural including mod security, but there's nothing preventing it. Returning your comment, there's no reason to dedicate one php-fpm daemon to a single app either, as there's none to dedicate one nginx server per app. Otoh there's reasons to have a cluster of php-fpm daemons behind a single nginx for performance purposes, weighting toward the separation of concerns. At this point I think I'll extend my answer when I can – Tensibai Sep 20 '17 at 22:35
4

Actually, one missing point here is the horizontal scalability. There's an article from Jamie Alquiza long time ago addressed this:

http://archive.is/pDzz0

In short, you scale your php-fpm horizontally for reaching higher performance. Scaling Nginx+php-fpm together does not bring you any benefit. I encourage you do some stress testing (e.g. Tsung, Gatling, etc.; please don't do Apache ab, that is a very old toy) yourself to verify what the article stated. I personally have several real world experiences proved the article is true in general.

But there're two drawback (maybe not for Kubernetes) for bare metal machines / VMs:

  1. How to configure Nginx dynamically discover php-fpm container changes? This is the easy part.
  2. How do we share the same volume / file systems after scaling? Nginx and php-fpm containers should read exactly the same content to reach consistency. This leaves you the least complicated puzzle piece (and the most fun part) to work on.

EDITED: Now it's almost halfway into the of year 2019. Old model, php-fpm+nginx in the same pod, has different usage. If you're familiar with service mesh, then nginx (or what so call Nginmesh) serves as a sidecar to handle east-west bound traffic. East-west bound traffic mostly used to authenticate among services, or other fancy functionalities, whereas pure "php-fpm only" containers could not do that alone.

K8sN0v1c3
  • 195
  • 1
  • 9
Ming Hsieh
  • 141
  • 4
-1

The advantage is : you can run multiple php-fpm containers in back-end, we call it PHP cluster, via number of ports. Example port 9000, 9001, 9002 .. and so on

Dylan B
  • 99