Structure PHP application for easy upgrade and scaling? - php

I'm having a big problem trying to find a way to structure my application for scaling. Below is my current setup:
We have an application written in PHP and MySql. The app is written in such a way that it can, in theory, serves thousands of different websites using the same codebase (but each will have different database).
In our current setup, we have 1 nginx config file per 1 website, all of them pointing to the same location lets say /var/www/current-version. We have a way for us to know which website is supposed to be rendered.
Each time we upgrade, we update code to /var/www/new-version
Copy all code from /var/www/current-version/ to /var/www/old/
Point all current projects from current/ to old/ by search and replacing all nginx config files and the do a service reload
Copy code from new/ to current/
Loop through the websites to
edit the corresponding nginx config file to point to the current/ folder
sync the new updated config files across all instances
run update script (we have to do this because the upgrade process may involve migrating db and several other things)
This upgrade process involves quite a few steps and is subjected to certain issues such as when the sync does not happen fast enough.
I wonder if there is any better way to do this?
PS:
I'm not sure if this is the best place to ask this kind of question, stackexchange has too many sub-sites and I'm confused. Anyhow, please feel free to let me know if I post in the wrong place

Why not just to use symlinks? For example, all nginx configs are set up to /var/www/website, that is a symlink to /var/realdir/website_1_1_0. You deploy a new code to /var/realdir/website_1_2_0 and after it just change a symlink to point to this new directory.

Related

The point of Yii2 environments folder

I am trying to work what the point of the environments folder is.
Originally I had the idea that you could point the webserver to the different dev and prod folders in the environment folder but after reading up a bit I realise this is not the case.
In Yii 1 you would solve this by just having multiple index.php's i.e.:
index.php
index-local.php
So the question is what benefit does this new environment structure actually give me over the old way?
I've found environments very useful in allowing me to keep a common code base for multiple client projects (based on Yii App Advanced) and setting up a different environment for each specific client, keeping their custom code private and separate.
To do this I store the environments folder in a separate git repo from the rest of the code and pull down the relevant folder on a client/project basis.
This lets me use a base common code for all projects and add/override any file for a specific client or project whilst still allowing separate dev/prod config settings. If the client uses other developers too, they are also catered for. In this way, only common code I choose will be shared amongst clients and custom code will be kept private.
I've also moved the composer.json file into the environments folder so I can pull in different extensions per client/project keeping those private too.
That init command can be a very powerful tool and you don't have to limit yourself to the template provided by the core developers.
If you don't need environments, then don't use them, but I assure you some people will find it very useful.
Yii2 documentation in WIP, but you should read this :
https://github.com/yiisoft/yii2/blob/master/docs/guide/apps-advanced.md#configuration-and-environments
You need to use yii init command to switch between these environments.
EDIT :
This new environment feature is more than just use different config file. You can use different folder structure, different entry script...etc
Personnaly I won't use this feature, I don't need it (I will use a different entry script as with Yii 1), but I think this is not useless.
I think you didn't get the real purpose of environments introduced in Yii2.
I'll try to explain what was the main purpose of adding environments to yii from the developers point of view on an example and hope you will really appreciate its usefulness.
Let's suppose for a moment that you are a team of developers (e.g. 5-7 person) working on mid-to-large project implemented in Yii. To effectively work on that project your team decides to use some CVS or SVN (e.g. GIT) and keep all the files of the project in repository in cloud for the whole team. That's de facto standard while working on mid-to-large projects in teams and nobody will resist that it's the only comfortable and easy way.
Ok, now let's suppose you use Yii 1.x or Yii2 with the approach of different entry scripts to differentiate between local (development) and production environments to connect to db or set some other environment specific configs. Everything is ok and working. But suppose your team members implemented something new on the project and you check out repository to work on updated version and you suddenly find out that your local config file (in this case entry script with config) is overwritten with other team member's file who pulled the changes to repository (because each of you is using your local machine db with other database name or OS, or config, or simply because your team uses one local development server db, but you are on vacation and can't use anything except your local machine).
So generally Yii2 environment adds more flexibility for using different environments each with it's own specific configurations while using also general (common) configs when working in teams on mid-to-large projects hence why the example in guide is given on advanced app project.
Surely you can overcome everything stated above with some solutions or .gitignore which is used by default to overcome the problem stated in Yii2 with environments. But:
Why bother if everything is already done?
and
It was just one little example of usefulness of Yii2 environments. More depends on the project and your imagination.
Overall Yii2 is great product. Not only it adds many new features to already great framework, but it also is more robust and flexible than Yii 1.x (despite the fact that Yii 1.x was already very robust).
As for Laravel or any other PHP framework, it really depends... Everyone will find his/her own favorite.
For those who are tired of copying files around, I created a useful script that you can run in background to keep the files in sync on your dev environment:
File sync-env-files.sh
#!/bin/bash
ENVIRONMENT_DIR="/var/www/example.com/environments/dev/"
DIR="/var/www/example.com/"
while [ true ]; do
for envFile in `find $ENVIRONMENT_DIR -type f`
do
file=${envFile/$ENVIRONMENT_DIR/$DIR}
if [ `stat -c "%Y" $file` -gt `stat -c "%Y" $envFile` ]; then
#echo "copying modified file $file to $envFile"
/bin/cp -f $file $envFile
fi
done
sleep 2
done
Then run the script in background or add to cron with flock
nohup server/sync-env-files.sh >/dev/null 2>&1 &
I would like to mention in addition to #AngelCoding, since this question still gets seen, that I use the environments folder lots now and definitely see the point of it.
The very first things I do in any open source project is create one project for the code base on GitHub and then another, private, one on Bitbucket for the configuration, in other words the environments folder.
Having this folder has made it a lot easier for me to separate my configuration into a private repository.
So the environments folder has a lot of uses and really helps to separate configuration for easier usage even if it does not seem like it initially.

Wordpress site release management strategy

I'm updating an existing wordpress site making significant modifications the the theme and site structure, as well as making updates to plugins which in turn store their data into mysql database.
As far as I'm aware there are 2 (3?) possible strategies here:
'Dump-and-load' MySQL database from DEV to LIVE and replace wp-content folder with latest updates.
Import changes via WP-importer and replace wp-content folder with latest updates.
Make database changes manually via WP admin interface and replace wp-content folder with latest updates (this is useful only for minor changes).
While I am developing in my own separate environment this is for an existing website which is currently live and will continue to receive updates from the public such as comments and entries into contact forms, hence I expect the database to be different now from when I release my changes.
Given this the options above provide the following problems.
1. DUMP AND LOAD
The 'dump-and-load' strategy seems to be out of the question as my data is being updated behind the scenes (this would have been my preferred approach as this is easily rolled back).
Result: requires synchronising databases post release to get latest updates, TOO COMPLICATED.
2. USE THE IMPORTER
Using the WP-Importer plugin page and post IDs will get updated, screwing up styling that relies on the post IDs to get activated. This in turn creates a CSS nightmare that I wish to avoid, having to go though the CSS after release to update the new page/post IDs with the ones the database created.
Result: Too finicky, not very professional approach leading to long and complex release process.
3. UPDATE DATABASE MANUALLY
This option is great for small changes but when for more complex releases the list of steps to follow on the PROD interface becomes long and hard to follow, making it easy to make mistakes.
Result: Too easy to screw up, only a last resort.
IS THERE A STANDARD WORDPRESS RELEASE STRATEGY FOR EXISTING WEBSITES?
So basically, my question is: What release process do other wordpress developers follow when UPDATING an existing website? Is there an option that I have not listed below that minimizes hassle and reduces time and complexity during release?
I've set up source control for the site using GIT and I am used to automating things via ANT or similar release script, this may be overkill for the current project but would be ideal to at least know of a simple way to update a wordpress site and minimize the chances of screwing it up.
Thanks!
I don't think this is particular to WordPress, it's a similar situation to any custom site. I personally favor replaying the SQL changes on production that were made on dev. The tricky part is that you have to know what SQL changes were made. For example a certain plugin may make some schema changes when you install it - you need to know what they were. You can do that by creating an export of your DB as SQL before installing a plugin, then take another export after and do a diff on the files.
Since you say you're making the modifications then I might assume you know what SQL changes you are going to make? Just make sure all changes you make to the DB are in the form of SQL script files and not just editing using the GUI (you can use the GUI to help write the queries, but save the actual SQL). After all of your changes are done you should have a bunch of SQL scripts that you ran during your development process - you can re-run them in order without encountering errors.
Then when it's time to push to production, create a staging version of production (that is take a fairly current DB backup of production). Run your update scripts on that and test that everything is ok. If it is, then you can run on production.
definitely make a backup of production before running any changes on it!
The guy behind WordFence was working on a deployment plugin called
Deploymint.
There's a new one called WP Stack.
Metal Toad Media discussed using Capistrano, but that Capistrano isn't specific to WP.
CrowdFavorite launched a service called
RAMP.
Needless to say, you have some other options. If you're making db changes manually make sure you're working with the serialized data effectively. I recommend using Search and Replace DB. WordPress also had a great little trick for changing the site url entirely from the wp-config file.
I assume you have everything running in a test environment. I would then:
Create a new database in your live environment.
Preload it with all content and configurations for the new site.
In your test environment, configure your config.php to point to the new database.
Upload all files to the live server. Upload your config.php last.
This will minimize downtime.

Using multiple php frameworks on one website

Our main website uses symfony 1, and by the time I started working on the code it seems impossible to upgrade (too much custom code from previous developer). Now we are adding a large addition to what the company offers. Instead of using a really old framework I wanted to use CodeIgniter, also since I'm very familiar with it. My real question:
What is a proper way of setting up a website to use multiple frameworks. The new features will be separate from the original website, but it will still need a few tables of the database.
I was going to have apache handle where the root directory was depending on the url and just do everything normally. The main website is example.com and the new feature will be abc.example.com
I'm really looking for people who have done this and some tips and warning they had.
PHP will run the framework based on which directory is loaded on the server. For instance, on most apache servers the root directory for example.com would be /www. Which means all of the code for Symphony would be in /www/*.
When you setup the path of your subdomain, just put it outside of the /www folder. Then, when you go to abc.example.com apache won't try to load the original site along with the Symphony framework.
I think it will be fine for both frameworks to share the same database tables. I'm not entirely sure how you plan for these two applications to work, but as long as you don't change the column names and types you should be okay.
If you don't want the applications to share the data in the original table, then look into using mysqldump or something of the like to copy the data over to a new table.

Codeigniter Shared Resources - Opinions Wanted

I run multiple websites all running off of a single installation of CodeIgniter on my server (separate application directories and a single system directory). This has been working fabulously and I don't see any reason to change it at this point.
I find myself writing library classes to extend/override CI all of the time and many times if I find a bug or improve effeciency I have to go back to several websites to make the same adjustments at risk of a typo that breaks one of the websites. Because of this it requires that I change each file and then test that site for bugs.
I have been pondering a solution of using a single libraries directory in a central location and symlinking all of my websites to that central directory. Then when I make a file change it will immediately propagate to all of the downstream websites. It will still require that I test each one for errors, but I won't have to make the changes multiple times. Anything that is specific to a single website will either be a non-shared file (still in the linked directory just not used elsewhere) or can be put in a local helper.
Also, I keep separate 'system' directories by CI version so I can migrate my websites independently if necessary--this central libraries file would be attached to a specific version to reduce possible breaks.
Does anyone see potential issues or pitfalls from taking this approach? Has anyone accomplished this in another direction that I should consider?
Thanks in advance!
I think this actually makes sense :] Go for it. Even on official CodeIgniter page, they mention it's possible.
Also, I don't see one reason why there should be any problem.
Edit: they touch the problem of multiple sites here: http://codeigniter.com/user_guide/general/managing_apps.html
also:
http://codeigniter.com/wiki/Multiple_Applications/
http://www.exclusivetutorials.com/setting-multiple-websites-in-codeigniter-installation/
How to Handle Multiple Projects in CodeIgniter?
http://codeigniter.com/forums/viewthread/56436/
I have a single system directory and separate application directories for my CI apps. In order to share libraries and some view templates between my apps, I have created a "Common" directory, in the same folder as the CI system and with the same structure as a regular app folder and used symlinks, but you can modify the Loader class so that it looks in the Common folder too. My setup looks something like this:
/var/CodeIgniter/
/var/Common/
/var/Common/config/
/var/Common/controllers/
...
/var/Common/libraries/
...
/var/www/someapp/
/var/www/someotherapp/
...
I'm not sure how you handle publishing your sites (assuming you actually do any of that), but I'd look into version control. For example, in SVN you can make external to another svn directory (or file) and then just update the current svn directory which grabs the external file. This approach gains one benefit from the others, which is when you modify the common library, the others aren't immediately affected. This prevents unwanted breaks before you have time to go test all the sites using the common library. You can then just update each site's folder whenever you are ready to test the changes. This is "more work", but it prevents code duplication AND unwanted breaks.
I wrote a MY_Loader to do exactly that.
http://ellislab.com/forums/viewthread/136321/

How to efficiently manage multiple installations of a web application?

From my experience, one of the bigger problems we come across during our webdevelopment process is keeping different setups updated and secure across different servers.
My company has it's own CMS which is currently installed across 100+ servers. At the moment, we use a hack-ish FTP-based approach, combined with upgrade scripts at specific locations to upgrade all of our CMS setups. Efficiently managing these setups becomes increasingly difficult and risky when there are several custom modules involved.
What is the best way to keep multiple setups of a web application secure and up-to-date?
How do you do it?
Are there any specific tips regarding modularity in applications, in order to maintain flexibility towards our clients, but still being able to efficiently manage multiple "branches" of an application?
Some contextual information: we mainly develop on the LAMP-stack. One of the main factors that helps us sell our CMS is that we can plugin pretty much anything our client wants. This can very from 10 to to 10.000 lines of custom code.
A lot of custom work consists of very small pieces of code; managing all these small pieces of code in Subversion seems quite tedious and inefficient to me (since we deliver around 2 websites every week, this would result in a lot of branches).
If there is something I am overlooking, I'd love to hear it from you.
Thanks in advance.
Roundup: first of all, thanks for all of your answers. All of these are really helpful.
I will most likely use a SVN-based approach, which makes benlumley's solution closest to what I will use. Since the answer to this question might differ in other usecases, I will accept the answer with the most votes at the end of the run.
Please examine the answers and vote for the ones that you think have the most added value.
I think using a version control system and "branching" the part of the codes that you have to modify could turn out to be the best approach in terms of robustness and efficiency.
A distributed version system could be best suited to your needs, since it would allow you to update your "core" features seamlessly on different "branches" while keeping some changes local if need be.
Edit: I'm pretty sure that keeping all that up to date with a distributed version system would be far less tedious than what you seem to expect : you can keep the changes you are sure you're never going to need elsewhere local, and the distributed aspect means each of your deployed application is actually independent from the others and only the fix you mean to propagate will propagate.
If customizing your application involves changing many little pieces of code, this may be a sign that your application's design is flawed. Your application should have a set of stable core code, extensibility points for custom libraries to plug into, the ability to change appearance using templates, and the ability to change behavior and install plugins using configuration files. In this way, you don't need a separate SVN branch for every client. Rather, keep the core code and extension plugin libraries in source control as normal. In another repository, create a folder for each client and keep all their templates and configuration files there.
For now, creating SVN branches may be the only solution that helps you keep your sanity. In your current state, it's almost inevitable that you'll make a mistake and mess up a client's site. At least with branches you are guaranteed to have a stable code base for each client. The only gotcha with SVN branches is if you move or rename a file in a branch, it's impossible to merge that change back down to the trunk (you'd have to do it manually).
Good luck!
EDIT: For an example of a well-designed application using all the principles I outlined above, see Magento E-Commerce. Magento is the most powerful, extensible and easy to customize web application I've worked with so far.
I may be wrong, but it seems to me what Aron is after is not version control. Versioning is great, and I'm sure they're using it already, but for managing updates on hundreds of customized installations, you need something else.
I'm thinking something along the lines of a purpose-built package system. You'll want every version of a module to keep track of its individual dependencies and 'guaranteed compatibilities', and use this information to automatically update only the 'safe' modules.
E.g. let's say you've built a new version 3 of your 'Wiki' module. You want to propagate the new version to all the servers running your application, but you've made changes to one of the interfaces within the Wiki module since version 2. Now, for all default installations, that is no problem, but it would break installations with custom extensions on top of the old interface. A well-planned package system would take care of this.
To address the security question, you should look into using digital signatures on your patches. There are lots of good libraries available for public-key-based signatures, so just go with whatever seems to be the standard for your chosen platform.
Not sure whether someone's said this, there are a lot of long responses here, and I've not read them all.
I think a better approach to your version control would be to have your CMS sat on its own in its own repository and each project in its own. (or, all of these could be subfolders within one repo i guess)
You can then use its trunk (or a specific branch/tag if you prefer) as an svn:external in each project that requires it. This way, any updates you make to the CMS can be committed back to its repository, and will be pulled into other projects as and when they are svn updated (or the external is svn:switch 'ed).
As part of making this easier, you will need to make sure the CMS and the custom functionality sit in different folders, so that svn externals works properly.
IE:
project
project/cms <-- cms here, via svn external
project/lib <-- custom bits here
project/www <-- folder to point apache/iis at
(you could have cms and lib under the www folder if needed)
This will let you branch/tag each project as you wish. You can also switch the svn:external location on a per branch/tag basis.
In terms of getting changes live, I'd suggest that you immediately get rid of ftp and use rsync or svn checkout/exports. Both work well, the choice is up to you.
I've got most experience with the rsync route, rsyncing an svn export to the server. If you go down this route, write some shell scripts, and you can create a test shell script to show you the files it will upload without uploading them as well, using the -n flag. I generally use a pair of scripts for each environment - one a test, and one to actually do it.
Shared key authentication so you don't need a password to send uploads up may also be useful, depending on how secure the server to be given the access is.
You could also maintain another shell script for doing bulk upgrades, which simply calls the relevant shell script for each project you want to upgrade.
Have you looked at Drupal? No, not to deploy and replace what you have, but to see how they handle customizations and site-specific modules?
Basically, there's a "sites" folder which has a directory for every site you're hosting. Within each folder is a separate settings.php which allows you to specify a different database. Finally, you can (optionally) have "themes" and "modules" folders within sites.
This allows you to do site-specific customizations of particular modules and limit certain modules to those sites. As a result, you end up with a site that the vast majority of everything is perfectly identical and only the differences get duplicated. Combine that with the way it handles upgrades and updates and you might have a viable model.
Build into the code a self-updating process.
It will check for updates and run them when/where/how you have configured it for the client.
You will have to create some sort of a list of modules (custom or not) that need to be tested with the new build prior to roll-out. When deploying an update you will have to ensure these are tested and integrated correctly. Hopefully your design can handle this.
Updates are ideally a few key steps.
a) Backup so you can back out. You should be able to back out
the entire update at any time. So,
that means creating a local archive
of the application and database
first.
b) Update Monitoring Process - Have the CMS system phone home to look for a new build.
c) Schedule Update on availability - Chances are you don't want the update to run the second it is available. This means you will have to create a cron/agent of some kind to do the system update automatically in the middle of the night. You can also consider client requirements to update on weekends, or on specific days. You can also stagger rolling out your updates so you don't update 1000 clients in 1 day and get tech support hell. Staggered roll-out of some kind might be beneficial for you.
d) Add maintenance mode to update the site -- Kick the site into maintenance mode.
e) SVN checkout or downloadable packages -- ideally you can deploy via svn checkout, and if not, setup your server to deliver svn generated packages into an archive that can be deployed on client sites.
f) Deploy DB Scripts - Backup the databases, update them, populate them
g) Update site code - All this work for one step.
h) Run some tests on it. If your code has self-tests built in, it would be ideal.
Here's what I do...
Client-specific include path
Shared, common code is in shared/current_version/lib/
Site specific code is in clients/foo.com/lib
The include path is set to include from the clients/foo.com/lib, and then share/lib
The whole thing is in a version control system
This ensures that the code uses shared files wherever possible, but if I need to override a particular class or file for some reason, I can write a client specific version in their folder.
Alias common files
My virtual host configuration will contain a line like
Alias /common <path>/shared/current_version/public_html/common
Which allows common UI elements, icons, etc to be shared across projects
Tag the common code with each site release
After each site release, I tag the common code by creating a branch to effectively freeze that point in time. This allows me to deploy /shared/version_xyz/ to the live server. Then I can have a virtual host use a particular version of the common files, or leave it pointing at the current_version if I want it to pick up the latest updates.
Have you looked at tools such as Puppet (for system administration incl. app deployment) or Capistrano (deployment of apps in RubyOnRails but not limited to these)?
One option would be to set up a read-only version control system (Subversion). You could integrate access to the repository into your CMS and invoke the updates through a menu, or automatically if you do not want the user to have a choice about an update (could be critical). Using a version control system would also allow you to keep different branches easily
As people have already mentioned that using version control (I prefer Subversion due to functionality) and branching would be the best option. Another open source software available on sourceforge called cruisecontrol. Its amazing, you configure cruisecontrol with subversion in sach a way that any code modification or new code added in serversion, Cruise control will know automatically and will do build for you. It will save your hell of time.
I have done the same way in my company. we have four projects and have to deploy that project on different servers. I have setup cruiseconrol in such a way that any modification in code base triggers automatic build. and another script will deploy that build on the server. your are good to go.
If you use a LAMP stack I would definitely turn the solutions files into a package of your distribution and use it for propagate changes. I recommend for that matter Redhat/Fedora because of RPM and it's what I have experience on. Anyway you can use any Debian based distribution too.
Sometime ago I made a LAMP solution for managing an ISP hosting servers. They had multiple servers to take care of web hosting and I needed a way to deploy the changes of my manager, because every machine was self-contained and had a online manager. I made a RPM package containing the solution files (php mostly) and some deploying scripts that runned with the RPM.
For automated updating we had our own RPM repository set on every server in yum.conf. I set an crontab job to update the servers daily with the latest RPMs from that trusted repository.
Trustiness can be achieve too because you can use trust settings in the RPM packages, like signing them with your public key file and accepting only signed packages.
Hm could it be an idea to add configuration files? You wrote that a lot of small script are doing something. Now if you'd build them into the sources and steered them with configuration files shouldn't that "ease" that?
On the other hand having branches for every customer looks like an exponential growth to me. And how would you "know" which areas you've done something and do not forget to "make" changes in all other branches also. That looks quite ugly to me.
It seems a combination of revision controls, configuration options and/or deployment receipts seems to be a "good" idea.....
With that many variations on your core software, I think you really need a version control system to stay on top of pushing updates from the trunk to the individual client sites.
So if you think Subversion would be tedious, you've got a good sense for what the pain points will be... Personally, I wouldn't recommend Subversion for this, since it's not really that good at managing & tracking branches. Although benlumley's suggestion to use externals for your core software is a good one, this breaks down if you need to tweak the core code for your client sites.
Look into Git for version control, it's built for branching, and it's fast.
Check out Capistrano for managing your deployments. It's a ruby script, often used with Rails, but it can be used for all sorts of file management on remote servers, even non-ruby sites. It can get the content to the remote end through various stragegies including ftp, scp, rsync, as well as automatically checking out the latest version from your repository. The nice features it provides include callback hooks for every step of the deploy process (e.g. so you can copy your site-specific configuration files which might not be in version control), and a release log system--done through symlinks--so you can quickly roll back to a previous release in case of trouble.
I'd recommend a config file with the list of branches and their hosted location, then run through that with a script that checks out each branch in turn and uploads the latest changes. This could be cron'd to do nightly updates automatically.

Categories