ByteInternet / hypernode-docker

Fast and easy Docker for Magento development
https://community.hypernode.io/hypernode-docker
35 stars 8 forks source link

Install PHP 8.1 on an existing (older) Hypernode docker #71

Open Aquive opened 1 year ago

Aquive commented 1 year ago

I have an existing running docker box which goes up to PHP 8.0. Is it possible to manually install PHP8.1, so I don't need to recreate all a new docker?

vdloo commented 1 year ago

hey @Aquive, anything is possible but I really wouldn't recommend it as that sounds like quite a hassle. you could apt-get install these packages manually:

php8.1 php8.1-amqp php8.1-bcmath php8.1-bz2 php8.1-cli php8.1-common php8.1-curl php8.1-fpm php8.1-gd php8.1-igbinary php8.1-imagick php8.1-imap php8.1-intl php8.1-ldap php8.1-mbstring php8.1-mysql php8.1-odbc php8.1-opcache php8.1-pgsql php8.1-pspell php8.1-readline php8.1-redis php8.1-soap php8.1-tidy php8.1-xml php8.1-zip

but then you probably have some configuration mess to figure out in /etc/php/8.1

Aquive commented 1 year ago

Thanks for your fast answer @vdloo I am willing to try since setting up a new box is also a painful route ;)

For the configuration: can I peek into a newer box (with 8.1 installed) and take over configuration from there maybee? Which specific configuration are we talking about?

vdloo commented 1 year ago

Well, we Ansible a bunch of things into the image for different PHP versions so replicating that manually exactly is something you can't really do (that's not public code). But yeah you could look at a newer container and see if you can piece some things together. Anyway we do design Hypernode in a way where all the state is in /data, but in the docker you have root and can do whatever you want (so that abstraction kind of breaks). But in theory if you:

then you should have all your state running in the new container. but really it would be better to set up filesystem mounting in the future so your state doesn't live inside the container.

vdloo commented 1 year ago

oh by the way @Aquive I think this is only an issue if you don't have a version of the container yet which does have PHP 8.1 installed even though it's not active (see https://github.com/ByteInternet/hypernode-docker/blob/master/Documentation/switching-php-versions.md).

So what you could do (if you do have a container with all PHP versions installed):

# you can check like this
root@54084583ad3d ~ # ls /usr/bin/ | grep php
hypernode-switch-php3
php
php5.6
php7.0
php7.1
php7.2
php7.3
php7.4
php8.0
php8.1
php-config
php-config7.3
phpize
phpize7.3

to switch the PHP version you can edit:

vim /etc/hypernode/magweb.json

and change the php version there to whatever you want (php -> version in the json), and then restart the services like:

bash -x /etc/my_init.d/60_restart_services.sh

then if you run php -v you should see your different PHP version now being the system default one

Aquive commented 1 year ago

@vdloo Yeah, 8.0 was the newest version, unfortunately.

I must say this has always been an ongoing issue. Let me explain.

So thinking out of the for solutions:

I am looking forward to your reply.

vdloo commented 1 year ago

Yeah you can copy over /data/mysql entirely from one container to the next and restart mysql and be good to go. But I've never tested that with hypernode-docker but in theory that should work (and would be pretty safe to test if you're just copying it over to a new container). Upgrading package minor versions should work fine with apt-get update && apt-get upgrade -y, but if we're talking 'new PHP version' that requires a bunch of configuration management that we have all automated in Ansible but which 'outputs' these Docker images.

In Docker you're really not meant to use those containers as pets but only as cattle, so what you are doing is pretty unconventional. It of course is all perfectly possible, but by going this unconventional route you'll have to figure a lot of things out yourself that nobody else is probably doing. If you're doing this type of development where you expect a (docker) Hypernode to be updated over time you might be better of using a non-docker Hypernode development plan as a dev environment. Then you can just use hypernode-systemctl settings php_version 8.1 to let the Hypernode automation update your dev Hypernode with whatever setting changes you're performing.

Aquive commented 1 year ago

@vdloo thanks for the suggestions, I will try it out.

What do you mean I use it in an unconventional way? I know normally docker is used as services, and you have a docker for every service. But Hypernode uses a holistic approach where the docker is a replica of the hosting environment, right? I thought I was using it the way Hypernode want me to. If not, I am curious where the discrepancy is.

vdloo commented 1 year ago

Yes the hypernode-docker is not doing things 'the Docker way' too because of the fat-container aspect, but one of the things that Docker enables is that you can easily create/remove/recreate containerized environments which facilitates a 'throwaway' way of working. If you get used to being able to throw away / start from scratch with very low effort that can help experimenting in a different way than if you'd know you'd have to undo any changes you were trying out.

Like:

Option 2 is obviously way simpler because it enables you not to have to worry about side-effects of your experiments. Also going back to the previous state before your experiment is often not possible at all. So if you use Docker, generally you want to externalize all important 'state' from your container. So if you do have files that you want to keep between container processes, you normally would mount those in the container but those files would really live on your host. So if you'd mount your /data/web/magento2 for example on your host (ignoring the database for this example, but the same principle applies), then you could just start up a new container every day (instead of re-using the same container).

How you can mount data in your container depends on your platform (on Linux things are way easier / faster than on Windows / Mac, but here's some information https://docs.docker.com/storage/).

But of course you can use hypernode-docker however you want, if you used it in this way for years then apparently that's working as intended on some level. It just means that in your situation you'd have to spend some extra time figuring out how to update things inside the container (instead of just starting a new container based on the latest version).

Aquive commented 1 year ago

Ok, so you mention one aspect which is really the key point here I guess. If it is possible to also mount the DB data to my host just as I do with files, this will solve the whole issue at once.

If I understand correctly, this should be possible? This way I can just download a new image with the right version, mount it two times (once for file data, once for db data) and I am good to go? I never came across such a solution and never challenged myself to think about it this far.

One questions remains; which folder do I mount to my host for db data? Is that /data/mysql? And this will contain all databases, tables and data?

Mounting db data is like this?

docker run -d --name <name> -v ~/my-db-data:/data/mysql

Correct?

vdloo commented 1 year ago

Here's an example of how you can create persistent state between container instantiations by using bind mounts (docker run -v) on Linux:

Starting a new fresh container (with no mount):

# docker pull docker.hypernode.com/byteinternet/hypernode-buster-docker:latest
# docker run docker.hypernode.com/byteinternet/hypernode-buster-docker:latest

Logging into the container to create some state:

$ ssh root@172.17.0.2
# mysql -e 'create database mytestdatabase;'
# mysql mytestdatabase -e 'create table mytesttable(test INT) ENGINE=INNODB;'
# mysql mytestdatabase -e 'insert into mytesttable values (1);'
# ls /data/mysql/mytestdatabase/  # The DB now exists on disk
mytesttable.ibd

# echo "<? phpinfo();" > /data/web/public/index.php  # Simple 'website'

Now I have some state that exists inside the container that I'd like to get out and re-use in a different container. To do so I could sync the whole /data disk back to my host.

## On the host, not inside the container
# mkdir /root/mydatamount
# cd /root/mydatamount
# rsync -av root@172.17.0.2:/data . --progress
## Now on the host I have the contents of the /data dir
# ls /root/mydatamount/
data
# ls /root/mydatamount/data/
mysql  postprovisioning.d  var  web
# ls /root/mydatamount/data/mysql/ | grep mytest
mytestdatabase

So now I can start a new container with this data mounted from the host. For example I'm killing my original container, and now once again run docker run but this time with -v:

# docker run -v /root/mydatamount/data:/data docker.hypernode.com/byteinternet/hypernode-buster-docker:latest

In this new container when I login I'll see my data again:

# ls /data/web/public/
index.php
# mysql mytestdatabase -e 'select * from mytesttable;'
+------+
| test |
+------+
|    1 |
+------+

The nice thing about this is that if today I'm testing something with PHP 8.1 (like the hypernode-buster-docker:latest container currently is), but tomorrow I want to test something with PHP 8.0 for example then I can just start a different container image but with the same data directory mounted. Example:

docker pull docker.hypernode.com/byteinternet/hypernode-buster-docker-php80-mysql80:latest
docker run -v /root/mydatamount/data:/data docker.hypernode.com/byteinternet/hypernode-buster-docker-php80-mysql80:latest

And then if you log in to that container your mounted 'site' would be served by PHP with version 8.0 instead of 8.1:

# php /data/web/public/index.php  | grep 'PHP Version'
PHP Version => 8.0.16
Aquive commented 1 year ago

@vdloo that's awesome. I already had my files bound to my host, so I can use an IDE. I will try this also with DB data. Thanks for the explainating I will try it out and let you know!