Docker Containers and Applied Necromancy

You're probably sick of stories about Docker and containerization.
Yes, and I have already written a training course on Docker and an article about all sorts of self hosted, but today I will tell you about a funny example of using containers – to launch and update ancient web services.

There will be two live examples:

  1. Mediawiki, PHP wiki engine, ancient installation – we are updating from version 1.24 from September 2014.

  2. A fun xkcd-style comic generation tool written in Node.JS and last updated in March 2013. Pick it up and explore. There will be twists and turns, and a tragic ending.

I wonder how to resurrect these ancient artifacts? Then let's go!

Story one. Mediawiki

Ten years ago I participated in filling a certain wiki, and out of nostalgia I agreed to help my friends with an update. It was impossible to simply rewrite the materials into a new installation – gigabytes of data and a bunch of users had accumulated. So it was necessary to update. And this is always an interesting challenge – will I be able to do it?

At first glance it seemed easy, once in my childhood I had fun with PHP development, and even wrote modules for MediaWiki. Well, what can I say – take the code and the base, and shove it into a new container.
However, the further into the forest, the angrier the woodpeckers. At first, I was pleased by the disclaimer on the mediawiki page:

Since Version 1.36, MediaWiki only commits to supporting upgrades from two LTS releases ago (see phab:T259771). Upgrades from older versions of MediaWiki will have to be performed in multiple steps. This means that if you want to upgrade to 1.41 from 1.34 or earlier, you'll first have to upgrade your 1.34 wiki to 1.35 (or 1.39), and, from 1.35 (or 1.39), you'll be able to upgrade to 1.41 .

I mean

As of version 1.36, MediaWiki only supports upgrades from the previous two LTS releases. Upgrades from older versions of MediaWiki must be done in stages. That is, if you want to upgrade to 1.41 from version 1.34 or earlier, you will first need to upgrade from 1.34 to 1.35 (or 1.39), and then from 1.35 (or 1.39) you can upgrade to 1.41.

Then I saw something else compatibility chart for PHP:

And for MySQL:

Yes, it won't work right away. Having estimated the position of the stars, I decided that MySQL 5.7 should be enough for all versions (as it turned out, I was not mistaken), but PHP is better updated in several stages.
As a result, I got three stages of the update:

  1. Current version of Mediawiki is 1.24 and PHP 5.6

  2. Interim version 1.35 and PHP 7.4.3

  3. The target, latest at the time of writing, version is 1.41 and PHP 8.1

You might ask, why is my own version the first step?
The answer is this – at the time this entertainment began, the project was deployed on some godforsaken server of an incomprehensible and ancient configuration, and first it was necessary to quickly take it away and make sure that nothing had fallen and that it worked exactly the same.

You might also ask why docker is needed here. The answer is simple – PHP 5 has not been in the official repositories for a long time, and I didn't want to install something from left PPA and pollute the server with it. In addition, I wanted well-reproducible behavior. And I wasn't sure that I would be able to update to the latest version, so I wanted to isolate the application from the rest of the server. Therefore – containerization.

Underwater rocks

Well, then everything seems simple – we take the prepared PHP containers, copy the code, run the update, rotate the containers.

But… Not so fast. After all, mediawiki, in addition to PHP itself, requires a number of different PHP extensions and system libraries. And I couldn't find an image that would already have all of this.

Why I didn't use ready-made containerswhich are provided by MediaWiki? There should have been an answer at this point that there are only images from version 1.39:

But… At the time of writing this article I noticed that in mediawiki readme not all the tags that actually exist are specified. And if you fall into them on DockerHub, there are versions from 1.29.0… Therefore, the correct answer to the question “why I didn't use ready-made images from MediaWiki” is because I don't know how to use DockerHub 🙁 I hope you won't repeat my mistake, but I'll continue the story. Not because you have to do it this way, but because this is rather a general story that will be applicable to any project, including one where no one has prepared containers for you. And it's not a fact that these images are working and extensible, I haven't tried them.

So, then I decided to build a container on Debian out of habit. And then I was in for a bummer – the new versions of Debian no longer have the packages I need, and the repositories of the old versions are already dead…

I tried to solve this problem for a long time, looked for ready-made containers, and nothing suited me. But suddenly it turned out that Alpine Linux supports all the old stuff I needed! It would seem – here it is – just change the version of the PHP package and build containers…

However, there were some pitfalls here too, because for different versions of PHP, extensions are installed slightly differently.

Happy ending?

In general, having spent some time on selecting packages and the method of their installation, I was able to assemble the necessary versions. Moreover, everything took off immediately and almost without errors! And even database updates of several gigabytes were successful. Here my respect to the developers of MediaWiki – it is not so easy to maintain compatibility for decades. Although in all other respects I rather had the feeling that I returned 10 years ago – the methods of working with extensions, skins, and interaction with developers are simply terrible.

The only thing that didn't take off was custom extensions, which required remembering childhood and updating the code manually. But that's not a very interesting story.

As a result, we have an application updated to the latest version, a good container, and the ability to update it further, or freeze it in the same form for another 10 years, calmly moving the container from server to server. A happy ending, however!

I will not provide a link to the wiki itself, since it is private and generally of no interest to people outside the circle of its users. However, I published The resulting docker files and images are on GitHub, so if you have an old MediaWiki or some other project with similar dependencies, you can use it. But first try the official images I wrote about above – maybe it will be easier with them.

Story two. cmx.js

Once upon a time there was a web application cmx.ioand there you could use a mouse, HTML and some motherfucker to draw a comic in the xkcd style. There's even a thread about it article on wired.

For example, my hobby colleague @leotsarev once had this is the markup The comic was rendered like this:

But nothing lasts forever under the moon, the site has safely died, sources are not going to, and Leonid asked who could raise this. Apparently, he wants to write another article on Habr – a sacred matter, how can you not help. Especially since the application is on Node.JS – there it probably takes five minutes, pick the right version of node – and off we go. But…

Underwater rocks

In the times of myths and legends, when the ancient gods were vengeful and cruel, the toolkit of a front-end and back-end JS developer was completely different. When I tried to assemble the code, I felt like I had opened a time capsule, because there were:

  • Dependencies that did not build under Node > 8

  • Code generated by yeoman, an ancient boilerplate generator for web applications

  • Grunt as a task runner

  • CoffeeScript! Mother of God!

  • Bootstrap 2.2.2

  • Bower, which installs requirejs, modernizr, and jquery version 1.91

  • Some ruby ​​scripts and dependencies on its gems

Wow! Sounds like a flight attendant that doesn't need digging up. However, why not do it for a comic book drawing? Again…

So I decided – why not.

Success?

Surprisingly, the bower repositories are still working, and I was able to build a working container that installed both bower dependencies and ruby ​​and the required gem.
Code written 11 years ago works again!

Success!

While I was writing the article, I became terribly curious – what are those ruby ​​gems, and what are those dependencies that are not supported on the current node?.. The answer, as they say, killed me.

  • It turned out that the ruby ​​gem is needed to compile Sass… Everything would be fine, but in this project Sass is not used anywhere. Threw it out.

  • It turned out that the non-working dependency is needed for compressing JPEGs… Which is also not used. Threw it out.

  • And there are dependencies for tests, including non-working, but very thick PhantomJS. But there are no tests in the project. Threw it out.

  • And the dependencies with bower… Copied to the repository itself. And also not used. Threw them out.

In general, after cutting out all the unnecessary things, it turned out that the latest version of Node 22 is enough to launch the application. And the docker image accordingly became twice as thin.

Right now I can feel the satisfied rumbling of the left-fall witness sect. They say they will create dependencies for themselves and then collect them into fat images.

In fact, the problem is not node, npm or small dependencies. Quite the opposite. But to notice this, you need to look at the number of co-authors of the project and the number of its users. The number of co-authors, in addition to the author… One… We can only calculate the number of users approximately, based on the fact that about 290 hist exported from this project are published on GitHub.
Let's pretend that:

  1. About every tenth user using GitHub decided to save the result

  2. Only every tenth user has a GitHub

In total, according to the scientific method of three P's (floor, finger, ceiling), it turns out that the project had about 29,000 users. And let me remind you – one co-author… If there were at least 2-3 more developers, they would have certainly noticed the jambs and cut off everything unnecessary. And with his comic-example, the author showed that he is waiting for co-authors:

But… The expectations were in vain, the man-hours he expected were not spent, and 792 stars and 89 forks resulted in only one developer…
Here it is important to ask the question – why? And the answer to it is quite simple. The size and complexity of the project is inversely proportional to the developer's desire to understand and bring benefit.
Because the more context there is, the more time it will take him to understand it.

That is why small projects and small packages are important – where you can come and bring benefit in an hour, and not in a week of continuous work. And also important is respect and a culture of donations. Which also work almost in no way – both in my personal experience and, for example, on sad example my highly respected @rock. So, at the current stage of development of open source culture, small bricks are the best way to make the work of developers easier, and give them at least some co-authors.

So the problem of unnecessary dependencies and unused boilerplate is not a problem of a specific author, node, NPM or any other technology. This problem is us, developers who use open source solutions and treat them in an extremely consumerist way.

So why is the docker here?

A natural question may arise – what are we even talking about Docker if it turns out that you can simply cut off everything unnecessary and leave only the node?

The question is fair, but there is an answer to it. And even several.

  1. Tearing off the excess is an iterative process. I would hardly have been able to tear off everything at once and immediately assemble a working application. But this way, I was able to raise the same environment, make sure that it works identically, and gradually bite off the excess.

  2. Now I can share this service with you. Even if you have another OS and don't have Node.JS

  3. In this form, the service will be able to survive for a long time – until the browser compatibility drops.

Bonus

To avoid ending on a sad note, I’ll share a funny find.

If you search for a piece of code specific to this project, can be found the resulting comics are on github. There's probably a lot of good stuff there, so feel free to deploy my fork according to simple instructions and explore.
For example, there is such a comic:

And some very strange thingssimilar to the beginning of DnD history – there is a prison, two chairs and a zombie attack. I did not raise the service on the web, because there are probably ancient vulnerabilities there. And locally you can play around with it. But be careful and review the code before rendering – there may easily be some evil JS, the author did not make protection against it during rendering.

Instead of a conclusion

It's common to make generalizations, to say that I'm great (or not great, since it could have been done faster, or not done at all), but I just hope that you found this story interesting, and that it will help you in your necromantic research. And tell me if you've ever done something similar – there are probably other funny stories!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *