New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Working on a build for Ghost 1.0 #65

Closed
pascalandy opened this Issue May 27, 2017 · 48 comments

Comments

Projects
None yet
@pascalandy
Copy link
Contributor

pascalandy commented May 27, 2017

Hello Folks!

I love the work Docker is doing for Ghost. It's super easy run and update from version to version. The official image is great!

I tried to build Ghost 1.0.0-alpha.21 and I could not run Ghost successfully :-\

Wondering if someone have found a way to run the alpha version in Docker.

Cheers!

@pascalandy pascalandy changed the title Testing Ghost 1.0 Alpha (and Future beta) Testing Ghost 1.0 Alpha (and future beta) May 27, 2017

@tianon

This comment has been minimized.

Copy link
Member

tianon commented May 30, 2017

Great idea -- took the first step over in #66.

@tianon

This comment has been minimized.

Copy link
Member

tianon commented May 31, 2017

Looks like https://github.com/TryGhost/Ghost-CLI is going to be the "canonical" installation method for 1.0 (see http://support.ghost.org/v1-0-alpha/, especially "when we ship Ghost 1.0 this will be the way to install and update Ghost"), and it wants to manage installations in a bit of an interesting way (so it can handle upgrades, etc). Not 100% sure how to handle this best via Docker yet.

Might be that the Docker images for 1.0+ only include ghost-cli? Maybe some scripts to handle the common cases? Not sure yet.

@tianon

This comment has been minimized.

Copy link
Member

tianon commented May 31, 2017

ghost-cli appears to be intended to manage the full lifecycle of the Ghost instance (ghost start, ghost stop, ghost restart, ghost update, etc), which is kind of a problem for Docker usage. Perhaps we should file an issue over there to see if they're willing to advise on what we should do WRT Docker for 1.0+. 😇 😅

@tianon

This comment has been minimized.

Copy link
Member

tianon commented May 31, 2017

For reference, here's the very basic Dockerfile I've been testing with so far:

FROM node:6-alpine

# grab su-exec for easy step-down from root
RUN apk add --no-cache 'su-exec>=0.2'

ENV GHOST_CLI_VERSION 1.0.0-alpha.17

RUN set -ex; \
	yarn global add "ghost-cli@${GHOST_CLI_VERSION}"

ENV GHOST_SOURCE /usr/src/ghost
WORKDIR $GHOST_SOURCE
@pascalandy

This comment has been minimized.

Copy link
Contributor

pascalandy commented May 31, 2017

@pascalandy

This comment has been minimized.

Copy link
Contributor

pascalandy commented Jun 1, 2017

Hi @tianon. I found fixer on slack and he managed to make Ghost Alpha work on his setup. It’s not perfect but it can guide us.

Well my setup has multiple weak points. A) downloads lateat alpha from an url generated by my api (wrapper for github api)

So as ive said earlier its a quick & dirty kind of thing

Also the way im using env vars is a little messed up because of my current setup (using the image on heroku,openshift & local dev cluster

Its still good enough for testing  but i dont tudod nk its good enough for the official image

Dockerfile

https://hub.docker.com/r/fixer/ghostfixer/builds/bsuiay8cvngcmmklj4qzko5/

all the magic is here:

wget -O ghost-latest.zip https://api.hgrg.info/github/repos/TryGhost/Ghost/prereleases/latest/zip && \
  unzip ghost-latest.zip -d /ghost && \
  rm -f ghost-latest.zip && \
  cd /ghost && \
  npm i -g knex-migrator && \
  yarn run init && \
  knex-migrator init && \ 
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false -o APT::AutoRemove::SuggestsImportant=false zip unzip git && \ yarn cache clean && \ sed -i 's/"type": "ghost"/"type": "password"/' /ghost/core/server/config/env/config.development.json && \

and start.bash file

Easy try out!

docker run -d --name=ghostalpha -e PORT=2368 -p:2368:2368 fixer/ghostfixer:alpha

@pascalandy pascalandy changed the title Testing Ghost 1.0 Alpha (and future beta) Working on a build for Ghost 1.0 Beta Jul 2, 2017

@pascalandy

This comment has been minimized.

Copy link
Contributor

pascalandy commented Jul 2, 2017

Here is a plain installation (not a Dockerfile) for Alpine when I follow the docs from the Ghost team.

When I execute the following, Ghost runs but I can't connect when I go to localhost:2368

The installation is probably is too simplitic for a full Dockerfile, but if it can help other folks to start here it is :)

EDIT: THIS IS NOT RELEVENT ANYMORE

# Run Node container
docker run -dit --name GhostAlpineWIP \
-p 2368:2368 \
node:6-alpine sh && \

# Connect into Node container
docker exec -it GhostAlpineWIP sh;

# Basic updates and installs
apk update && \
apk upgrade && \
apk add curl && \

npm install -g ghost-cli && \
mkdir ghostapp && \
cd ghostapp && \
ghost install local && \

# Check the installation
ghost --version && \
ghost ls && \
ghost log ghost-local && \
curl localhost:2368

# Remove Container
# exit then...
docker rm -f GhostAlpineWIP

P.S. At this moment Ghost 1 Beta can only run in development mode. Let's care about production later :)

@noahwhite

This comment has been minimized.

Copy link

noahwhite commented Jul 9, 2017

I am trying to Dockerize 1.0 beta-2 on Alpine and seeing the same behavior when running a local ghost install. I get an empty response from outside the container even thought I get index.html when I curl from within the container.

I am guessing that when you run Ghost in local mode it only binds to localhost and thus you can't expose it outside the container which would explain the behavior I am seeing above.

@noahwhite

This comment has been minimized.

Copy link

noahwhite commented Jul 9, 2017

That was the issue for me and I got it to work by adding --ip 0.0.0.0 too ghost install local

@pascalandy

This comment has been minimized.

Copy link
Contributor

pascalandy commented Jul 9, 2017

Cool!! I'll try this :)

I got it to work by adding --ip 0.0.0.0 too ghost install local

@magnonellie

This comment has been minimized.

Copy link

magnonellie commented Jul 10, 2017

I probably shouldn't come in here and pretend like I know anything, but whatever.

I asked in the help chat on the ghost slack (message link) and it seems like you can just install ghost the "normal" way (downloading the zip, npm i, npm start, etc) without any trouble if you're just aware about everything else that needs to go in there. I guess that would probably also end up being the easiest way for this project to pick up since it's essentially just what's here now, right? What probably needs to be done however is to add instructions on how to use this image in conjunction with the mysql one since ghost is gonna use that by default in production.

@Windfarer

This comment has been minimized.

Copy link

Windfarer commented Jul 24, 2017

Now ghost 1.0.0 has been released, any update for this docker image? @tianon

@tianon

This comment has been minimized.

Copy link
Member

tianon commented Jul 24, 2017

We definitely need to figure out how to handle Ghost 1.0, but I don't think we have a good answer for that ATM, and really need to talk to upstream to see whether they'd like us to do something based around the new ghost tool or whether they'd rather we continue to build this image the same way we have been (downloading the release and extracting it directly, which is the more "Docker-native" solution).

@tianon

This comment has been minimized.

Copy link
Member

tianon commented Jul 24, 2017

Alternatively we could swap this image to simply be ghost:cli-X.Y.Z, but I'm not sure whether that really adds much value -- we really need upstream's input to do this properly.

@SISheogorath

This comment has been minimized.

Copy link

SISheogorath commented Jul 24, 2017

@alexellis

This comment has been minimized.

Copy link

alexellis commented Jul 27, 2017

The "let's make a CLI to rule them all" approach is going to make running this in Docker hard. Here's how I did it - https://blog.alexellis.io/try-ghost-1-0-in-docker/

@alexellis

This comment has been minimized.

Copy link

alexellis commented Jul 27, 2017

There is also a kind of anti-container sentiment (maybe it complicates support?) It's a bit odd as I think the hosted product version runs on LXC. TryGhost/Ghost-CLI#384 (comment)

@acburdine

This comment has been minimized.

Copy link
Collaborator

acburdine commented Jul 27, 2017

@tianon FWIW I can create a recommended Docker setup based on what's here currently that also uses ghost-cli. (I built most of it so have a good idea of how to make it work well in Docker 😉)

@alexellis it's not so much anti-container sentiment as it is trying to reduce Ghost's support overhead - if a docker install of Ghost has issues people come to Ghost support and previously, we tried to help which reduced the amount of time that we had to work on new features. With the new CLI - the intent was to support fully a recommended stack and then make the community provide support for other, non recommended stacks. This allows us to spend more time working on new features 😉

@alexellis

This comment has been minimized.

Copy link

alexellis commented Jul 27, 2017

I guess you are aware that this approach makes Docker + Ghost even harder. (Being stateful vs effectively immutable, trying to manage the process itself, including systemd, including nginx, expecting Ubuntu 16.04). I can see how a known configuration would reduce support time and issues - but running applications in containers seems like a core use-case.

Hopefully there will still be a sensible way to run with containers moving forward while taking advantage of the easier install afforded by the CLI. I'm happy to test it out, I've written about this several times and Ghost 0.x has served me well. https://blog.alexellis.io/tag/blog/

@tianon

This comment has been minimized.

Copy link
Member

tianon commented Jul 27, 2017

@acburdine any help you're willing to offer would be amazing, and really appreciated!! ❤️

@acburdine

This comment has been minimized.

Copy link
Collaborator

acburdine commented Jul 27, 2017

@alexellis Like I said - I have a pretty good way of making it run right with docker, just need to fix a bug and I'll have a working setup 😄

@tianon reading your comment above would definitely be willing to have a chat sometime about how best to move forward with Docker & Ghost-CLI - feel free to email me and we can figure something out.

@seeruk

This comment has been minimized.

Copy link

seeruk commented Jul 27, 2017

I like the idea of Ghost CLI, and it does seem to be a nice tool, but I must admit that as others have said above, I'm surprised at the lack of a truly container-friendly approach to running Ghost in this age of containers.

Personally, I'd like to just see some recommended installation instructions that don't use Ghost CLI. It's a nice tool, but to get Ghost successfully running in Docker myself in production mode / development mode as I want I've basically had to disable every feature Ghost CLI gives you, and just focus on having it download and extract Ghost, and create a configuration file. If there were just some instructions about how to initialise Ghost on it's own without Ghost CLI, that'd be a good starting point for easier containerisation. Maybe even some Ghost-in-container recommendations specifically, given that a LOT of people are running things in containers these days. I've still got an older instance of Ghost running in Docker elsewhere, and it's working great still - without the CLI.

Just to be clear, I don't want to make it sound like the CLI tool is pointless or a bad tool, because it isn't, and I am certain it'll be a huge boon to people who aren't Docker savvy, or simply don't want to run things in containers, etc. but right now, as the only recommended way to install Ghost, it is really not Docker-friendly - and it feels like a huge oversight. Perhaps this situation will improve with more documentation about the CLI tool too.

Some ways this could be made more Docker friendly:

  • Allow basic "download, extract, and set up to run without anything else at all happening, no user config, no DB config, no systemd, no checks, nothing" to be a bit simpler ($ ghost install docker or $ ghost install bare, etc.?) I know you can just disable all the things like I have for now - this one isn't actually a big deal, it'd just be nice to have this functionality abstracted behind a command.
  • Allow configuration via environment variables when you run Ghost (e.g. via $ ghost run), e.g. switching environment, configuring your database, and configuring directories. This would be HUGELY beneficial compared to the current approach with the CLI, because as it's been explained above the current approach sort of makes you build configuration into your image... Allowing Ghost to be configured with environment variables would probably be the biggest step to make Ghost more Docker-friendly IMO.
  • Also, whilst talking about $ ghost run, it'd be nice to have something to get rid of the warning that's shown when you use it. It probably is the way you'd want to run it in Docker. Or just in the foreground in general with $ ghost start instead?
  • Another thing that would be nice to think about, I've not thought about it enough to give any suggestions yet, is how you'd update Ghost when it's running in a Docker container. Generally you'd update the image being used (i.e. again, not necessarily using Ghost CLI to run the update specifically - not without complicating things like automation at least), meaning things like your content and database would have to be migrated when the container starts (honestly, I'm not sure if this is already the case or not).

The aim would be to be able to make a container image that's immutable, and doesn't need to change in any way at build-time, but would respond to different configurations at run-time.

@jtcressy

This comment has been minimized.

Copy link

jtcressy commented Jul 27, 2017

I'd like to point out that Ghost 1.0 currently supports overriding configuration with environment variables: https://docs.ghost.org/docs/config#section-running-ghost-with-config-env-variables

However I think that documentation should be expanded upon. I also noticed that Ghost won't take the env vars unless they are lowercase such as database__connection__host instead of DATABASE__CONNECTION__HOST

@acburdine

This comment has been minimized.

Copy link
Collaborator

acburdine commented Jul 28, 2017

PR is now open with configs for Ghost 1.0 😄 Turns out the bugfix wasn't needed after all! #67

@pascalandy

This comment has been minimized.

Copy link
Contributor

pascalandy commented Jul 28, 2017

Hi @acburdine !
Thanks for pushing this. It's very interesting to read your Dockerfile. I just build it, then ran:

docker run -dit --name ghost \
-p 2368:2368 devmtl/dockerghost:latest

but got this error on my server and on my mac:

docker: Error response from daemon: oci runtime error: container_linux.go:262: starting container process caused "exec: \"docker-entrypoint.sh\": executable file not found in $PATH".

Something else we should know about running Ghost in a container?
Many cheers!

@acburdine

This comment has been minimized.

Copy link
Collaborator

acburdine commented Jul 28, 2017

Ah! Looks like I need to add execute permissions to a couple of the files. Will fix tomorrow morning :)

@pascalandy pascalandy changed the title Working on a build for Ghost 1.0 Beta Working on a build for Ghost 1.0 Jul 29, 2017

@tomkersten

This comment has been minimized.

Copy link

tomkersten commented Jul 30, 2017

FWIW: I have taken a slightly different approach which uses the recommended stack (aside from systemd & nginx) and breaks MySQL and the Ghost app into separate containers. My setup/approach likely isn't for everyone, as it assumes you have set up nginx (+ SSL, etc) elsewhere...but it feels like it may end up working well for me so I thought I'd share for those interested...

https://github.com/tomkersten/ghost-docker

[Lots of room for improvement I'm sure...PRs welcome]

@alexellis

This comment has been minimized.

Copy link

alexellis commented Jul 31, 2017

I think you'll end up with a smaller image on Alpine Linux. Have you thought of using a stack instead of old compose v2? https://blog.alexellis.io/docker-stacks-attachable-networks/

@tomkersten

This comment has been minimized.

Copy link

tomkersten commented Jul 31, 2017

@alexellis I assume you were talking to me...if not, ignore what follows....

I don't necessarily want to hijack this thread with ways of changing what I've done, unless others are interested (as my solution/approach is not a fork of this codebase at this point).

However, my response to your point & question are:

I think you'll end up with a smaller image on Alpine Linux.

Although I appreciate the sentiment, this was not really my concern, to be honest. I was primarily interested in getting as close to the "recommended stack" as possible without violating the fundamental "single process" approach to a container. I started with an Alpine Linux install and had it ~80% there, but switched to Ubuntu to be in line with the recommended stack (to simplify updates, etc). PRs or forks are welcome, of course...

Have you thought of using a stack instead of old compose v2? https://blog.alexellis.io/docker-stacks-attachable-networks/

I had not. To be honest, I've never done anything with stack and didn't realize v2 of compose files was that old (I'm definitely not a Docker expert). I was anxious to get a deployment that was functional, compatible, and easy to maintain with the nginx-proxy I have set up. Again, totally open to PRs...

@pmig

This comment has been minimized.

Copy link

pmig commented Jul 31, 2017

@tomkersten Your stack would be ideal for me too, but I would also love to have to have to commitment for stability and up to date images of an official repository. Maybe we get the splitted images into the official repos with a different version tag and ensure that the image is concurrently build with the other one!

@alexellis

This comment has been minimized.

Copy link

alexellis commented Jul 31, 2017

Often the official images provide 2-3 alternatives - Ubuntu/fully bloated / Debian slim and Alpine. The example I shared above shows how to add Node.js to Alpine Linux. As for compose - stacks are in compose format 3.0 and the latest format is 3.1 which also supports secure secrets. Secrets could be useful for a MySQL container for instance.

I have been maintaining Ghost images for some time for x86_64 / ARM but would be more interested in seeing "official" Dockerfiles to point people at going forward.

@seeruk

This comment has been minimized.

Copy link

seeruk commented Jul 31, 2017

If anyone is curious to see a (mostly complete) slightly different approach, using Alpine, avoiding the bulk of the system setup stuff, then I've made this image: https://github.com/SeerUK/docker-ghost I'd like to hear any criticisms anyone has regarding the image too.

I've just not quite got permissions there just yet. It's fine in a production environment - if you create the Ghost volume and assign the permissions manually on the host, and probably on Docker for Mac too, but will likely fail for development when using Docker Machine, or Docker on Linux, etc.

I'll be getting that sorted out soon though, because I'll be developing on Linux / macOS.

@jwarkentin

This comment has been minimized.

Copy link

jwarkentin commented Jul 31, 2017

I generally like the approach @tomkersten has taken since I already have MySQL and nginx with SSL running separately. I suspect anyone using Docker will have a similar setup since that's kind of just the way things are done with Docker. An Alpine base would certainly be preferable though. Can this just be based on the Node.js Alpine image on Docker Hub?

Also, it would be really nice if it could run a script to check if it needs to run the ghost update command prior to starting Ghost as part of the run command. Then updating would be as simple as updating the Docker image and starting it. Not sure how to check if it needs to update though. Is the version stored in the DB or anything? Alternatively, is it bad to run the update command every time the container is started? Not sure what all it does.

@seeruk

This comment has been minimized.

Copy link

seeruk commented Jul 31, 2017

@jwarkentin My image does indeed do a ghost update if the version you request is different to the detected installed version (it also detects if a new installation is needed if the installed version detected is empty).

This way you don't update the Docker image, but instead update an environment variable.

I agree wholeheartedly though. I'll have MySQL running in another image. I'll probably use jwilder's Nginx proxy for Nginx, and don't need to be tied to systemd for process monitoring, etc.

Still just the permissions issues to sort out though, with the Ghost volume. If you use a Docker volume it would also work, but again that's not a good plan for a development environment. I do want to get that sorted today though if possible.

@jwarkentin

This comment has been minimized.

Copy link

jwarkentin commented Jul 31, 2017

@seeruk Nice! I like that approach for managing installation and updates. I haven't ever used Docker for development personally so that won't affect me much. I generally use a scripted Vagrant environment for development. I'll have to look closer at your setup when I have some time but I like where it's going.

@pascalandy

This comment has been minimized.

Copy link
Contributor

pascalandy commented Jul 31, 2017

@jwarkentin I don't think this is good practice.

Then updating would be as simple as updating the Docker image and starting it.

You don't want to be surprised that Ghost have updated and that broken your theme or your DB.

@jwarkentin

This comment has been minimized.

Copy link

jwarkentin commented Aug 1, 2017

It's not really a surprise if you update the image tag you're pulling. But the environment variable update approach used by @seeruk works too and may be better because it doesn't require a new image to update to the latest version. The only potential downside I see is if a new version of ghost changes how things work and actually requires an updated image to work.

Generally with Docker if I want to update something like Node.js, Elasticsearch, MySQL, etc... I change the tag to the version I want to run. And it's completely in my control so it's not a surprise either. And like with Elasticsearch, once you run it with the newer version it performs some updates on the underlying files and you can't go back so it's not like it's an unprecedented practice or anything. Regardless, I think both ways are fine. In either case you're just updating the version in your docker-compose file.

@pascalandy

This comment has been minimized.

Copy link
Contributor

pascalandy commented Aug 1, 2017

My bad. I should have quote:

would be really nice if it could run a script to check if it needs to run the ghost update command prior to starting Ghost as part of the run command.

When the container restart it could update Ghost. We probably don't want this behaviour. Make sense?

@jwarkentin

This comment has been minimized.

Copy link

jwarkentin commented Aug 1, 2017

Right. I see what you're saying. Yeah, that would be bad if it just updated it to whatever the latest version is when the container started. Ideally, it'd be able to update to a specific version that the container was built for. I know the install command allows specifying a version but I didn't see anything in the docs that allows updating to a specified version so that might not be possible.

@pascalandy

This comment has been minimized.

Copy link
Contributor

pascalandy commented Aug 2, 2017

Just took a look at the code and Ghost 1.0 is Dockerized! Can't wait to try it :-p

@alexellis

This comment has been minimized.

Copy link

alexellis commented Aug 2, 2017

"Upgrading" code inside a container makes it stateful, that's not a good way to manage your data. Using a Docker volume might be better. https://blog.alexellis.io/keeping-shipping-your-blog/

@seeruk

This comment has been minimized.

Copy link

seeruk commented Aug 2, 2017

@alexellis Correct, that's why my image doesn't do that. You specify a version as an environment variable, you would keep this as a static value (like you might some database credentials, etc.) and only change it if you want there to be a change.

My image stores the entirety of Ghost in a volume. There are no specific Ghost instance files kept in the image. Only Ghost CLI, and some scripts to automate the steps you might want to handle easily (like installing, updating, and starting Ghost).

This way, the image is immutable, and it would pretty much just change if you wanted to upgrade Ghost CLI. I was tempted to call the image seeruk/ghost-cli, but decided against it because the idea of the image is to run a Ghost instance, i.e. with the scripts included in the image too.

@pascalandy

This comment has been minimized.

Copy link
Contributor

pascalandy commented Aug 2, 2017

I confirm ghost 1.0 runs perfectly locally and on a server. See how here.

Cheers!

@ColtonProvias

This comment has been minimized.

Copy link

ColtonProvias commented Aug 2, 2017

Also confirming. Docs on hub.docker.com need to be updated to the new volume, though.

Now to start work on Dockerizing Ghost 1.4.0!

@pascalandy

This comment has been minimized.

Copy link
Contributor

pascalandy commented Aug 2, 2017

Will do a PR :)

Docs on hub.docker.com need to be updated to the new volume, though.

Also, I'll leave the issue open for couple of days but so far I think we are good to go :)

@pascalandy

This comment has been minimized.

Copy link
Contributor

pascalandy commented Aug 3, 2017

My PR is out here. Looking for your feedback folks. I know I sound funny in english sometimes :-p

@pascalandy

This comment has been minimized.

Copy link
Contributor

pascalandy commented Aug 4, 2017

I confirm the images are running smoothly (since 2 days running 1.0.2).
This morning, just restarted the container using 1.5.0. Cheers!

@tianon

This comment has been minimized.

Copy link
Member

tianon commented Aug 4, 2017

Rock on! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment