mmornati / docker-ghostblog

Ghost Blog Docker Container
MIT License
10 stars 6 forks source link

Permission issue since we switched to user node #37

Closed pascalandy closed 5 years ago

pascalandy commented 6 years ago

Hello guys,

I know it's best practice to use a user like 'node'. But now I have permission issues all over the place :-/

By looking at the official Ghost Dockerfile we can see they don't use USER like we do. I feel this might can the issue. I'll test without it.

The official image also uses su-exec and we don't.

docker service logs

root@CODA03:~# docker service logs 10000013-infinitio-ghost
10000013-infinitio-ghost.1.qpy1an4a5xgd@CODA03    | Ghost override provided. Override the internal configuration
10000013-infinitio-ghost.1.5a5mo6y6pg5y@CODA03    | Ghost override provided. Override the internal configuration
10000013-infinitio-ghost.1.qpy1an4a5xgd@CODA03    | => Change config based on ENV parameters:
10000013-infinitio-ghost.1.5a5mo6y6pg5y@CODA03    | => Change config based on ENV parameters:
10000013-infinitio-ghost.1.5a5mo6y6pg5y@CODA03    | ========================================================================
10000013-infinitio-ghost.1.qpy1an4a5xgd@CODA03    | ========================================================================
10000013-infinitio-ghost.1.5a5mo6y6pg5y@CODA03    |       WEB_URL:        http://infinitio.tk/blog
10000013-infinitio-ghost.1.qpy1an4a5xgd@CODA03    |       WEB_URL:        http://infinitio.tk/blog
10000013-infinitio-ghost.1.qpy1an4a5xgd@CODA03    | ========================================================================
10000013-infinitio-ghost.1.5a5mo6y6pg5y@CODA03    | ========================================================================
10000013-infinitio-ghost.1.5a5mo6y6pg5y@CODA03    | cp: can't create directory '/var/lib/ghost/content/apps': Permission denied
10000013-infinitio-ghost.1.qpy1an4a5xgd@CODA03    | Missing content folder. Copying the default one...
10000013-infinitio-ghost.1.5a5mo6y6pg5y@CODA03    | cp: can't create directory '/var/lib/ghost/content/data': Permission denied
10000013-infinitio-ghost.1.qpy1an4a5xgd@CODA03    | cp: can't create directory '/var/lib/ghost/content/apps': Permission denied
10000013-infinitio-ghost.1.qpy1an4a5xgd@CODA03    | cp: can't create directory '/var/lib/ghost/content/data': Permission denied
10000013-infinitio-ghost.1.5a5mo6y6pg5y@CODA03    | cp: can't create directory '/var/lib/ghost/content/images': Permission denied
10000013-infinitio-ghost.1.qpy1an4a5xgd@CODA03    | cp: can't create directory '/var/lib/ghost/content/images': Permission denied
10000013-infinitio-ghost.1.5a5mo6y6pg5y@CODA03    | cp: can't create directory '/var/lib/ghost/content/logs': Permission denied
10000013-infinitio-ghost.1.5a5mo6y6pg5y@CODA03    | cp: can't create directory '/var/lib/ghost/content/themes': Permission denied
10000013-infinitio-ghost.1.qpy1an4a5xgd@CODA03    | cp: can't create directory '/var/lib/ghost/content/logs': Permission denied
10000013-infinitio-ghost.1.qpy1an4a5xgd@CODA03    | cp: can't create directory '/var/lib/ghost/content/themes': Permission denied
10000013-infinitio-ghost.1.5a5mo6y6pg5y@CODA03    | Missing content folder. Copying the default one...
sr229 commented 6 years ago

This is quite easy to fix, we just need to chmod and chown the directories they're installed.

mmornati commented 6 years ago

Hey. Yeah it seems that the switch to user node for the build process is braking the access to the default content folder.

mmornati commented 6 years ago

No problem on my side creating the folder for a new blog... as I said, I think even before the user was node.

capture d ecran 2018-02-23 a 22 50 12
sr229 commented 6 years ago

@mmornati seesms to cause OCI Runtime issues on K8s on my end

mmornati commented 6 years ago

Can you post some logs about the issue?

Le dim. 8 avr. 2018 à 12:50, Capuccino notifications@github.com a écrit :

@mmornati https://github.com/mmornati seesms to cause OCI Runtime issues on K8s on my end

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mmornati/docker-ghostblog/issues/37#issuecomment-379540601, or mute the thread https://github.com/notifications/unsubscribe-auth/AAIgOy1bigJIX5lycNfRP6QAOUwUfJzZks5tmet0gaJpZM4SOojT .

pascalandy commented 6 years ago

At the moment, I stopped to use this image because of this problem.

From the official image

I would propose we follow the docker hub official image https://github.com/docker-library/ghost/tree/47f1ab8767c6547455dbddc0508c1856ddefde77/1/alpine and add the final multi-stage build in the Dockerfile. We could propose our PR to the docker team later (when it will be supported by Docker EE).

I tried to do a multi-stage version out of the official Dockerfile but I could not figure it out. At this point, my custom image size (uncompressed) is not too bad at 394 MB but I would like to include the multi-build. Here is my Dockerfile.

user/ghostimage       edge_2018-03-29_23H25   26e35c219cc5        9 days ago          394MB

Cheers!

mmornati commented 6 years ago

I think it is only a problème related to the files and folder which was created previously using the root user. The problem can be quickly fixed without changing anything in the container. You can find lot of documentation about it on the net (https://blog.joeyandres.com/2017/07/16/solving-permission-denied-when-writing-to-docker-volume/).

Can you post an ls - l of your content folder outside and inside the container?

mmornati commented 6 years ago

Here you are what I have on my side. Locally on the linux server schermata 2018-04-09 alle 08 18 16 schermata 2018-04-09 alle 08 18 25

Inside the Ghost Container schermata 2018-04-09 alle 08 19 15

In Linux mmornati is the user I'm using to run Docker and inside the container, as you know, the user is node. All the magic is done by Docker. That the reason you don't need to do anything, except if you run Docker with a non-root user and the files are owned by root.

Running a container with a root user inside allow anyone to do anything on the server even without root access. You can run the container, mount the volume you want (which is protected as root on the server) and enter in your container to have access to the files you can't read directly on the server. An article explaining the problem: https://medium.com/@mccode/processes-in-containers-should-not-run-as-root-2feae3f0df3b

pascalandy commented 6 years ago

It seems you spot the issue:

echo; pwd; echo; ls -AlhF; echo; du -sh *; echo; du -sh;

drwxr-xr-x  2 1000 1000 4.0K Oct  9 22:50 apps/
drwxr-xr-x  2 1000 1000 4.0K Apr  1 10:23 data/
drwxr-xr-x  4 1000 1000 4.0K Mar 31 19:53 images/
drwxr-xr-x  2 1000 1000 4.0K Apr  8 20:00 logs/
drwxr-xr-x 12 1000 1000 4.0K Mar 31 19:08 themes/

4.0K    apps
1.1M    data
27M images
18M logs
10M themes

Let me test this carefully :)

pascalandy commented 6 years ago

I added the attribute user --user=1000:1000 and run the official ghost image. Works good as usual.

docker service create \
   --user=1000:1000 \
   --name=$CTN_ghost_app --hostname=$CTN_ghost_app \
   --env url="http://$ENV_URL_BLOG"
   [...]
   "$IMG_ghost"

Then I run my service using this image and it still doesn't start. I don't see any obvious issues errors now. Man .. I'm confused :-p

docker service logs 33013-example-ghost

33013-example-ghost.1.i66uu9lvv6qg@CODA03    | ========================================================================
33013-example-ghost.1.zqjbcdbn0gtz@CODA03    | [2018-04-09 11:38:11] INFO Ghost is running in production...
33013-example-ghost.1.x36bfk6mxur5@CODA03    | [2018-04-09 11:43:19] INFO Your blog is now available on http://example.io/blog/
33013-example-ghost.1.l85ks8fbof2y@CODA03    | [2018-04-09 11:39:53] INFO Ghost is running in production...
33013-example-ghost.1.xk9h8daqrgso@CODA03    | [2018-04-09 11:45:02] INFO Your blog is now available on http://example.io/blog/
33013-example-ghost.1.wd3nsofk91gw@CODA03    | [2018-04-09 11:46:45] INFO Ghost boot 5.228s
33013-example-ghost.1.i66uu9lvv6qg@CODA03    |       WEB_URL:        http://example.io/blog
33013-example-ghost.1.x36bfk6mxur5@CODA03    | [2018-04-09 11:43:19] INFO Ctrl+C to shut down
33013-example-ghost.1.zqjbcdbn0gtz@CODA03    | [2018-04-09 11:38:11] INFO Your blog is now available on http://example.io/blog/
33013-example-ghost.1.l85ks8fbof2y@CODA03    | [2018-04-09 11:39:53] INFO Your blog is now available on http://example.io/blog/
33013-example-ghost.1.l85ks8fbof2y@CODA03    | [2018-04-09 11:39:53] INFO Ctrl+C to shut down
33013-example-ghost.1.xk9h8daqrgso@CODA03    | [2018-04-09 11:45:02] INFO Ctrl+C to shut down
33013-example-ghost.1.i66uu9lvv6qg@CODA03    | ========================================================================
33013-example-ghost.1.x36bfk6mxur5@CODA03    | [2018-04-09 11:43:19] INFO Ghost boot 5.158s
33013-example-ghost.1.zqjbcdbn0gtz@CODA03    | [2018-04-09 11:38:11] INFO Ctrl+C to shut down
33013-example-ghost.1.zqjbcdbn0gtz@CODA03    | [2018-04-09 11:38:11] INFO Ghost boot 5.132s
33013-example-ghost.1.l85ks8fbof2y@CODA03    | [2018-04-09 11:39:53] INFO Ghost boot 5.159s
33013-example-ghost.1.xk9h8daqrgso@CODA03    | [2018-04-09 11:45:02] INFO Ghost boot 5.435s
33013-example-ghost.1.i66uu9lvv6qg@CODA03    | Database already exists. Executing migration (if needed)
33013-example-ghost.1.x36bfk6mxur5@CODA03    | [2018-04-09 11:44:44] WARN Ghost has shut down
33013-example-ghost.1.x36bfk6mxur5@CODA03    | [2018-04-09 11:44:44] WARN Your blog is now offline
33013-example-ghost.1.zqjbcdbn0gtz@CODA03    | [2018-04-09 11:39:35] WARN Ghost has shut down
33013-example-ghost.1.l85ks8fbof2y@CODA03    | INFO [2018-04-09 11:40:08] "GET /blog/" 200 388ms
33013-example-ghost.1.xk9h8daqrgso@CODA03    | INFO [2018-04-09 11:45:23] "HEAD /blog/" 200 353ms
33013-example-ghost.1.i66uu9lvv6qg@CODA03    | [2018-04-09 11:41:31] INFO Finished database migration!
33013-example-ghost.1.i66uu9lvv6qg@CODA03    | [2018-04-09 11:41:36] WARN Theme's file locales/en.json not found.
33013-example-ghost.1.zqjbcdbn0gtz@CODA03    | [2018-04-09 11:39:35] WARN Your blog is now offline
33013-example-ghost.1.l85ks8fbof2y@CODA03    | [2018-04-09 11:41:18] WARN Ghost has shut down
33013-example-ghost.1.xk9h8daqrgso@CODA03    | [2018-04-09 11:46:27] WARN Ghost has shut down
33013-example-ghost.1.l85ks8fbof2y@CODA03    | [2018-04-09 11:41:18] WARN Your blog is now offline
33013-example-ghost.1.i66uu9lvv6qg@CODA03    | [2018-04-09 11:41:36] INFO Ghost is running in production...
33013-example-ghost.1.i66uu9lvv6qg@CODA03    | [2018-04-09 11:41:36] INFO Your blog is now available on http://example.io/blog/
33013-example-ghost.1.xk9h8daqrgso@CODA03    | [2018-04-09 11:46:27] WARN Your blog is now offline
33013-example-ghost.1.i66uu9lvv6qg@CODA03    | [2018-04-09 11:41:36] INFO Ctrl+C to shut down
33013-example-ghost.1.i66uu9lvv6qg@CODA03    | [2018-04-09 11:41:36] INFO Ghost boot 5.015s
33013-example-ghost.1.i66uu9lvv6qg@CODA03    | [2018-04-09 11:43:01] WARN Ghost has shut down
33013-example-ghost.1.i66uu9lvv6qg@CODA03    | [2018-04-09 11:43:01] WARN Your blog is now offline
mmornati commented 6 years ago

You don't need the attribute I think. But we need to check what is the ID of the node user inside the container. If it is 1000 it should work as the user owns the files and folder if it is different than 1000 that is the problem. What about if you start the blog with an empty content folder? Are you able to start it up?

pascalandy commented 6 years ago

When I start from scratch I can run the container. User ID in the container is 1000. As you say this should work.

/var/lib/ghost $ id -u node
1000

/var/lib/ghost $ echo; pwd; echo; ls -AlhF; echo; du -sh *; echo; du -sh;

/var/lib/ghost

total 24
-rw-r--r--    1 node     node          59 Apr  4 19:36 .ghost-cli
drwxr-xr-x    2 root     root        4.0K Apr 10 00:16 config.override.json/
-rw-r--r--    1 node     node         429 Apr 10 00:16 config.production.json
drwxr-xr-x    7 node     node         238 Apr 10 00:13 content/
drwxr-xr-x    7 node     node        4.0K Apr  4 19:36 content.bck/
lrwxrwxrwx    1 node     node          30 Apr  4 19:36 current -> /var/lib/ghost/versions/1.22.1/
-rwxrwxr-x    1 node     node        1.5K Apr  4 19:35 run-ghost.sh*
drwxr-xr-x    3 node     node        4.0K Apr  4 19:36 versions/

4.0K    config.override.json
4.0K    config.production.json
496.0K  content
24.0K   content.bck
0   current
4.0K    run-ghost.sh

141.5M  versions

142.0M  .
pascalandy commented 6 years ago

Guys!

In the docker-entrypoint.sh they specify the node user.

But in the run-ghost.sh we do not! It's probably related to this.

I won't try to fix it as my bash knowledge is limited. Hope this is the issue :-p

mmornati commented 6 years ago

Thanks Pascal. I will check it. Normally the entry point should run as node user as we specified in the docker file that is the one to use for everything.

I will take a look.

Marco

Le sam. 14 avr. 2018 à 03:59, Pascal Andy notifications@github.com a écrit :

Guy!

In the docker-entrypoint.sh https://github.com/docker-library/ghost/blob/8e29a02e28c641e39a509588fc06c63d5cc281ea/1/alpine/docker-entrypoint.sh#L6 they specify the node user.

But in the run-ghost.sh https://github.com/mmornati/docker-ghostblog/blob/master/run-ghost.sh#L8 we do not! It's probably related to this.

I won't try to fix it has my bash knowledge is limited. Hope this is the issue :-p

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mmornati/docker-ghostblog/issues/37#issuecomment-381295933, or mute the thread https://github.com/notifications/unsubscribe-auth/AAIgO0C1CwukAh7u6mGXUolJys9-o2jvks5toVgGgaJpZM4SOojT .

sr229 commented 6 years ago

Let's try something like the theia-openshift Usermode hack from Theia.

pascalandy commented 6 years ago

You mean this I guess? https://github.com/theia-ide/theia-apps/blob/master/theia-openshift-docker/Dockerfile#L3

sr229 commented 6 years ago

@pascalandy yep, since that line alone seems to change permissions for the user.

pascalandy commented 5 years ago

Hey guys, long time no see! I can't explain why, but my image reach more than 5M download. If you would like to give me a hand to make it multi-stage, it would be even more awesome!

It's aligned with the official docker image. Here are the tweaks:

Here is the project https://github.com/firepress-org/ghostfire

Cheers! P

mmornati commented 5 years ago

Hey @pascalandy how long 😄 Thanks for your comment. In the end, I'm just still using this docker for my blog... but it was only a great exercise to really learn Docker. I just take a look to your Dockerfile and I think you can improve it a lot (even without multistage). For example, the comment with the lines to edit can be moved to ARG. The advantages: modify only 1 line and you can run a docker build passing the argument value directly at the command line. I added it to the latest version of this repository Docker (just because I didn't want to lost time every time I had to update the blog :P)

pascalandy commented 5 years ago

Hey @mmornati, It's been a while!

I update the Dockerfile using ARG. I think it's more elegant as well :)

When you say:

I think you can improve it a lot

I'm curious to know what you have in mind. As previously stated, I want to follow the same pattern as the official docker image. What do you have in mind? Cheers!

mmornati commented 5 years ago

In the end it is getting lot of stuffs inside the Dockerfile and, as you are saying, you want to keep aligned with the official one. So: why you don't simply use the official one? If you need to change it you can simply reference the official docker in the FROM of your Dockerfile. In any other case, you can generate the Docker as you want without keeping it aligned to the official... because is your docker :) As we did at the beginning with this one. Personally, I will keep the one from this repository because is doing the job for what I need and it is a really small docker image (60mb vs 187, if the data on hub.docker.com are true 😄), and it is the only thing I'm looking for as my VPS is a really small disk.