Tag Archives: Yum

PHP Deployment: RPM/yum, whatever your OS uses

This is an article that is based off of a talk I did covering various deployment mechanisms.  The slides can be found at Slideshare.

Our final examination is going to be my prefered method, which, ironically, I don’t actually use… yet.  That is, the operating system specific method.  Because I’m using CentoOS that means using RPM and yum for me.  I don’t always deploy my applications, but when I do, I prefer yum.  OK, that sounded funnier in my head.

The reason I like this method is because it blurs the line between the application and the operating system.  Consider for a moment a goal that needs more than one person to be achieved.  Can the goal be achieved without the two of them working closely together?  Yes, but it will be less likely than if they know what each other is doing and how it is going to affect progress to the goal.  The application and the operating system cannot be thought of as two separate entities.  Also, most developers know squat about how to administer on operating system.  There’s nothing wrong with that, but it’s mostly true.  Yes, they may know about things like symbolic links and that log files exist but my experience has shown that a lot of developers, especially if they are not directly building onto the features of an OS, are not in-depth experts about the OS.  Some developers are, but they are not the majority.

Do you need to update an operating system?  Yes.  Do you need to update an application?  Yes.  Do your administrators need to do both?  Yes.  (Developers shouldn’t have access to systems that could run away, frightened that a developer might look at them) So why not use what is already there that your admins already know.

rpm.spec

This file is the basis for the whole thing.  They can be relatively complex when you’re dealing with compiled files, but with PHP it can actually be relatively simple.  So let’s take a look at what one of these looks like.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
%define version 0.0.1
%define release 1
%define name HelloWorld
 
Name: %{name}
Summary: Our HelloWorld application
Vendor: OurOrg
Release: %{release}
License: GPL
Group: Applications/ExampleOrg
Version: %{version}
Source: %{name}-%{version}-%{release}
BuildArch: noarch
Requires: zend-server >= 5.0, zend-server-framework > 1.10.0
 
%description
This is a basic application for demonstrating yum-based repositories
 
%build
 
%install
rm -rf /var/www/application
svn export svn://localhost/repos/HelloWorld/tags/%{version} /var/www/application
 
%clean
mkdir -p /var/www/repos/noarch
cp /usr/src/redhat/RPMS/noarch/%{name}-%{version}-%{release}.noarch.rpm /var/www/repos/noarch
createrepo /var/www/repos
 
%files
/var/www/application
 
%post
service httpd restart


So let’s go through these lines.

The first three are just some constant definitions.  All 3 of them are required for rpmbuild (the package builder).  They don’t have to be defined there, but the values do need to be in that header section.  Name and version are self-explanatory.  Revision is simply a number that you are supposed to increment when you create a new package for the same release number.  What you see in that header section is about the minimum that you require, with the exception of the Requires.  That’s not required.  That’s optional.  But here’s the good thing about using Requires.  It does not separate the application from the environment.  So when you install the application, you are also installing the environment.  Kinda a neat idea.

%description is required.  Nuff sed.

After that we have a series of macros that need are going to be run.  That’s what the %build, %install, etc. all are is macros.  And order is sometimes important, especially with the %files macro.  %build is empty because we’re not building anything.

%files lists the locations of all the files that you want to include in the package.  Directories will be included recursively, though you can specify individual files as well.  You can also exclude files by setting up an %exclude list.

%install is where we script how it is that we want the deployment box to create the installation.  What that means is that we set up the application’s structure as we want it to be on the production systems.  I am installing my application in /var/www/application.  So what I do is first remove that directory and then export the version that I had tagged during my testing process.

Then what I want to do is automatically take the resulting RPM file and place it in a yum repository so I can deploy it to my production machines.  Why do it during %clean?  Because %clean is run after the RPM is written.  So while I’m technically not doing an actual clean I am able to hook in there and copy the built RPM file from its build location to the yum repository.  After that I run createrepo to yumify it.

There are also several hooks that can be set up that can be run pre and post installation, or unintallation.  So what I do in mine is, for the macro %post, restart Apache to make sure that my opcode cache is cleared.

Building the RPM file

To create the RPM file I run the following command (I have version 0.0.3 tagged as my most current one).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
[root@deploy ~]# rpmbuild -bb /build-rpm/rpm.spec
Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.16948
+ umask 022
+ cd /usr/src/redhat/BUILD
+ exit 0
Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.16948
+ umask 022
+ cd /usr/src/redhat/BUILD
+ rm -rf /var/www/application
+ svn export svn://localhost/repos/HelloWorld/tags/0.0.3 /var/www/application
A    /var/www/application
A    /var/www/application/tests
A    /var/www/application/tests/application
A    /var/www/application/tests/application/bootstrap.php
/snip/
A    /var/www/application/public/index.php
Exported revision 23.
+ /usr/lib/rpm/brp-compress
+ /usr/lib/rpm/brp-strip
+ /usr/lib/rpm/brp-strip-static-archive
+ /usr/lib/rpm/brp-strip-comment-note
Processing files: HelloWorld-0.0.3-1
Requires(interp): /bin/sh
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires(post): /bin/sh
Requires: zend-server >= 5.0 zend-server-framework > 1.10.0
Checking for unpackaged file(s): /usr/lib/rpm/check-files %{buildroot}
Wrote: /usr/src/redhat/RPMS/noarch/HelloWorld-0.0.3-1.noarch.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.16948
+ umask 022
+ cd /usr/src/redhat/BUILD
+ mkdir -p /var/www/repos/noarch
+ cp /usr/src/redhat/RPMS/noarch/HelloWorld-0.0.3-1.noarch.rpm /var/www/repos/noarch
+ createrepo /var/www/repos
3/3 - noarch/HelloWorld-0.0.2-1.noarch.rpm                                      
Saving Primary metadata
Saving file lists metadata
Saving other metadata
+ exit 0

If we look in our /var/ww/repos directory (which is where our yum repository lies) we see several files.

1
2
3
4
5
6
7
8
9
10
11
[root@deploy ~]# find /var/www/repos/
/var/www/repos/
/var/www/repos/noarch
/var/www/repos/noarch/HelloWorld-0.0.3-1.noarch.rpm
/var/www/repos/noarch/HelloWorld-0.0.1-1.noarch.rpm
/var/www/repos/noarch/HelloWorld-0.0.2-1.noarch.rpm
/var/www/repos/repodata
/var/www/repos/repodata/other.xml.gz
/var/www/repos/repodata/primary.xml.gz
/var/www/repos/repodata/filelists.xml.gz
/var/www/repos/repodata/repomd.xml

That is our repository.

Setting up Production

Setting up your production environment is really easy.  All you need to do is create a new file in /etc/yum.repos.d.  I named mine org.repo.

1
2
3
4
5
[OurOrg]
name=OurOrg
baseurl=http://deploy/repos
enabled=1
gpgcheck=0

Makes sense.

Now to install our application.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
[root@xen1 ~]# yum install HelloWorld
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * addons: centos.omnispring.com
 * base: mirror.steadfast.net
 * extras: mirror.team-cymru.org
 * updates: centos.mirror.netriplex.com
Setting up Install Process
Resolving Dependencies
--> Running transaction check
---> Package HelloWorld.noarch 0:0.0.3-1 set to be updated
--> Finished Dependency Resolution
 
Dependencies Resolved
 
====================================================================================================================================================================================================================
 Package                                               Arch                                              Version                                            Repository                                         Size
====================================================================================================================================================================================================================
Installing:
 HelloWorld                                            noarch                                            0.0.3-1                                            OurOrg                                             10 k
 
Transaction Summary
====================================================================================================================================================================================================================
Install       1 Package(s)
Upgrade       0 Package(s)
 
Total download size: 10 k
Is this ok [y/N]: y
Downloading Packages:
HelloWorld-0.0.3-1.noarch.rpm                                                                                                                                                                |  10 kB     00:00     
Running rpm_check_debug
Running Transaction Test
Finished Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing     : HelloWorld                                                                                                                                                                                   1/1
Stopping httpd: [FAILED]
Starting httpd: httpd: Could not reliably determine the server's fully qualified domain name, using 192.168.0.77 for ServerName
[  OK  ]
 
Installed:
  HelloWorld.noarch 0:0.0.3-1                                                                                                                                                                                       
 
Complete!


Easy.

Rollbacks

Rollbacks are a snap.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
[root@xen1 ~]# yum downgrade HelloWorld
Loaded plugins: fastestmirror
Setting up Downgrade Process
Loading mirror speeds from cached hostfile
 * addons: centos.omnispring.com
 * base: mirror.steadfast.net
 * extras: mirror.team-cymru.org
 * updates: centos.mirror.netriplex.com
Resolving Dependencies
--> Running transaction check
---> Package HelloWorld.noarch 0:0.0.2-1 set to be updated
---> Package HelloWorld.noarch 0:0.0.3-1 set to be erased
--> Finished Dependency Resolution
 
Dependencies Resolved
 
====================================================================================================================================================================================================================
 Package                                               Arch                                              Version                                            Repository                                         Size
====================================================================================================================================================================================================================
Downgrading:
 HelloWorld                                            noarch                                            0.0.2-1                                            OurOrg                                             10 k
 
Transaction Summary
====================================================================================================================================================================================================================
Remove        0 Package(s)
Reinstall     0 Package(s)
Downgrade     1 Package(s)
 
Total download size: 10 k
Is this ok [y/N]: y
Downloading Packages:
HelloWorld-0.0.2-1.noarch.rpm                                                                                                                                                                |  10 kB     00:00     
Running rpm_check_debug
Running Transaction Test
Finished Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing     : HelloWorld                                                                                                                                                                                   1/2
Stopping httpd: [  OK  ]
Starting httpd: httpd: Could not reliably determine the server's fully qualified domain name, using 192.168.0.77 for ServerName
[  OK  ]
  Cleanup        : HelloWorld                                                                                                                                                                                   2/2
 
Removed:
  HelloWorld.noarch 0:0.0.3-1                                                                                                                                                                                       
 
Installed:
  HelloWorld.noarch 0:0.0.2-1                                                                                                                                                                                       
 
Complete!


Conclusion

This is probably my personal favorite out of all the deployment mechanisms for reasons that I stated earlier.

Anyway, that’s it for deployment.  Thanks for reading all of these articles (or at least this one).  If you have any thoughts feel free to post them here, Twitter, Facebook or wherever.

Web Analytics