How Do You Install Zabbix Server on RHEL 7.x Running in AWS?

Problem scenario
You have a RedHat Linux server with only 1 vCPU and 1 GB of RAM.  You want to install Zabbix Server to monitor other servers.  How do you deploy Zabbix server to an AWS instance of RHEL?

Solution
1. Install the LAMP stack components by running this command:
sudo yum -y install php httpd mariadb-server

2.  Install essential Zabbix components with these four commands:
sudo rpm --import http://repo.zabbix.com/RPM-GPG-KEY-ZABBIX

sudo rpm -Uv  http://repo.zabbix.com/zabbix/2.4/rhel/7/x86_64/zabbix-release-2.4-1.el7.noarch.rpm

sudo yum-config-manager --enable rhui-REGION-rhel-server-extras rhui-REGION-rhel-server-optional

sudo yum -y install zabbix-server-mysql zabbix-web-mysql zabbix-agent zabbix-java-gateway php-mbstring php-bcmath

3.  Configure the zabbix.conf file.
i.  sudo vi /etc/httpd/conf.d/zabbix.conf
Change the time zone entry by first uncommenting it out.  To find your time zone in the Americas, go to this link in a web browser.

ii.  This entry may look like this when you are done:

        php_value date.timezone America/New_York

iii. Save the changes to zabbix.conf.

4.  Restart the Apache web service daemon with this command:  sudo systemctl restart httpd

5. Start the MariaDB service with this command:  sudo systemctl start mariadb.service

6. This step of a command will assign the MySQL/MariaDB administrator password (for the database user "root"). Replace "strongpassword" with the password of your choice when you actually run this Linux command.

i.  Run this command: stty -echo
Please note that you will not see keystrokes on the terminal after you run the above command.  This is so you can type in a password and have no one else view it.

ii.  Replace "strongPassword" below with the password you want the root user of your MySQL server to have.  Once "strongPassword" is substituted, run the command below and press enter.

var1=strongPassword

iii.  Run this command:  stty echo

iv.  Run this command:  mysqladmin -u root password $var1

7.i.  Now you should be able to use this command to get into a SQL command prompt with this command:
mysql -u root -p

ii.  Type in the password (the one entered in step #6.ii) to the prompt you see.

8.  Now that you are the MariaDB prompt, enter this command: create database zabbixdb character set utf8;

9.  Now run this command but ask other people looking at your screen to turn away (and replace "strongPassword" with the password for root):

grant all privileges on zabbixdb.* to 'zabbixuser'@'localhost' identified by 'strongPassword';

#Expect to see "0 rows affected" by the above command.

10. Now run this command (which should display "0 rows affected" after it is succesfully run):

flush privileges;

11. Then exit the SQL command prompt with this command:  exit

12. i. Run this command:  sudo find / -name schema.sql

ii. With the result from the above command, run a new command like this (just substitute the "/path/to/file/found/above/schema.sql" with the file found in the above command):
mysql -u zabbixuser -p zabbixdb < /path/to/file/found/above/schema.sql

iii. At the prompt you now see, enter the password you chose for mysql above (in step 6.ii).

13. i. Run this command: sudo find / -name images.sql

ii. With the result from the above command run a new command like this  (just substitute the "/path/to/file/found/above/images.sql" with the file found in the above command):
mysql -u zabbixuser -p zabbixdb < /path/to/file/found/above/images.sql

iii. At the prompt you now see, enter the password you chose for mysql above (in step 6.ii).

14. i. Run this command: sudo find / -name data.sql

ii. With the result from the above command run a new command like this  (just substitute the "/path/to/file/found/above/data.sql" with the file found in the above command):

mysql -u zabbixuser -p zabbixdb < /path/to/file/found/above/data.sql

iii.  At the prompt you now see, enter the password you chose for mysql above (in step 6.ii).

15.  Modify the zabbix_server configuration file.

i. sudo vi /etc/zabbix/zabbix_server.conf

ii. Uncomment out the DBPassword stanza on line 106.  It will look like this at first:

# DBPassword=

It will look like this when you have uncommented it:

 DBPassword=

iii. Make sure these stanzas have the values as follows:

DBName=zabbixdb  #(unless you deviated from these directions above),

DBUser=zabbixuser #(unless you deviated from these directions above),

DBPassword=strongPassword #replace "strongPassword" with the password you chose above in step 6.ii.

iv. Save the changes.

16. i. sudo vi /etc/zabbix/zabbix_agentd.conf

ii.  #Change line number137 to look like this:

Hostname=127.0.0.1

iii. Save the changes.

17. i.  sudo vi /etc/php.ini

ii.  Find the following five settings and change them so their numbers reflect the following:

max_execution_time = 600
max_input_time = 600
memory_limit = 256M
post_max_size = 32M
upload_max_filesize = 16M

(These suggested settings above were taken from this link.)

iii.   Find the "date.timezone" stanza and change it to your time zone as found in this link.  For example, it may end up being like this (with no semi-colon):

date.timezone = America/New_York

iv. Save the changes to /etc/php.ini.

18.  Start many services.  You can cut and paste the following:
sudo systemctl restart httpd; sudo systemctl restart mariadb;
sudo systemctl enable zabbix-server; sudo systemctl enable zabbix-agent;
sudo systemctl start zabbix-server; sudo systemctl start zabbix-agent;

19.  i. Open a web browser.  Craft the URL like this:

http://<external IP address of the RHEL server>/zabbix

ii.  Click "Next" in the lower right hand corner.

iii.  On the right hand column, you should see green OKs.  Click next.

iv. For the "3. Configure DB connection" menu, enter the password you entered above (step 6.ii) in the password field.  Change the database name to zabbixdb unless you deviated from these directions.

v.  Click "Test Connection."  It should say "OK" after the menu refreshes.  Click "Next."

vi.  For Zabbix server details (#4 menu option), just click "Next."

vii.  For the "5. Pre-installation summary", just click "Next."

viii.  For the "6. Install" menu, just click "Finish."

ix.  Go back to the back end (command prompt of the Linux server).  Run this command:
sudo setsebool -P httpd_can_connect_zabbix=1

20.  At the Zabbix GUI login, enter admin for the user and zabbix for the password.

Happy Constitution Day!

Today is Constitution Day.  It was the final day of what was then called The Grand Convention or The Federal Convention.  We now know that almost three month convention in Philadelphia as the Constitutional Convention.  The meeting place was then called the State House.  This building still stands, and is now called Independence Hall.  We recommend people make a trip to Independence Hall and the nearby The National Constitution Center in Philadelphia to learn more about how the Constitution was drafted, debated, and adopted.  It is wise to have a copy of the U.S. Constitution.

During the convention the small states and larger states had different opinions about how representation in a legislature would work.  When the delegates of the states finally agreed on having a two-chamber legislature with one body (the House) having proportional representation and another (the Senate) having fixed representation, there was far greater harmony in the convention.  Small states wanted a say in this new government, but larger (more populous) states did not want to lose control of their tax dollars.  This blended system is known as The Connecticut Compromise and was the idea of Oliver Ellsworth and Roger Sherman

Today DevOps engineering seeks to blend development with I.T. operations. 

How Do You Install the Zabbix Client on a RHEL 7.x Server in AWS?

Problem scenario
You have set up Zabbix server (i.e., using these directions).  How do you configure another RedHat Linux server in AWS to be configured with the client so the Zabbix will monitor it?

Solution

Section 1
1.  Make sure your AWS Security group (that governs this AWS instance that will be a client) allows for inbound connections from the internal IP address of the Zabbix server on any TCP port.  Otherwise the client will not be able to be monitored.

Section 2
2.  One the AWS instance (Linux server) that will be the Zabbix client, run these three commands:

sudo rpm --import http://repo.zabbix.com/RPM-GPG-KEY-ZABBIX
sudo rpm -Uv  http://repo.zabbix.com/zabbix/2.4/rhel/7/x86_64/zabbix-release-2.4-1.el7.noarch.rpm
sudo yum install zabbix-agent -y

Section 3
3.  Go to the back end of the Zabbix server. Find the internal IP address of the Zabbix server's back end, run this command and find a different IP address from 127.0.0.1:  ip addr show | grep inet

Then run "hostname -f".  Keep this IP address and FQDN for the next steps performed on the other server.

Section 4
4.  Return to the AWS instance (Linux server) that will receive the agent.
i.  Run this command:  sudo vi /etc/zabbix/zabbix_agentd.conf

ii.  Edit line 84 and change the "127.0.0.1" to the internal IP address of the Zabbix server.    It will look like this:
Server=10.1.1.1

iii.  Edit line 126 so "ServerActive=" is assigned the internal IP address of the Zabbix server.  It will look like this:
ServerActive=10.1.1.1

iv.  Edit line 135 so that "Hostname=" is assigned the internal FQDN of the Zabbix server.  It will look like this:
Hostname=ip-172-31-29-241.us-east-2.compute.internal

v.  Save the changes.

vi.  Run these two commands:
sudo systemctl start zabbix-agent
sudo systemctl enable zabbix-agent

vii.  Find the internal IP address of the Zabbix client server's back end, run this command and find a different IP address from 127.0.0.1:  ip addr show | grep inet
Then run "hostname -f".  Keep this IP address and FQDN for the next steps performed on the other server.

Section 5
5.  i.  Go to the web UI of the Zabbix server.  Go to Configuration -> Hosts -> Create Host.

ii.  In hostname, enter the internal FQDN of the client server.  In the Groups section, highlight "Linux servers" and "Virtual Machines."  Click the "left arrow" button to move these two groups to the "In Groups" section. 

iii. In the "IP Address" of the "Agent interfaces" section, enter the IP address found in Section 4 above.

iv.  Click "Add" in the lower left-center section.

v.  Click the hostname that is hyperlinked.

vi.  Click "Templates" (but not the highest of the "Templates" tab) that is below other tabs.  Here is a picture of where to click.

The resulting view, after you click on the correct "Templates" tab, should look like this:

vii.  In the "Link new templates" field, type "Template OS Linux."  Click the correct suggestion as it appears.  Then type in "Template App SSH Service."  Click the correct suggestion as it appears. 

viii.  Click "Add."  

ix.  Then click "Update."

x.  You are done.  Be prepared to see this alert "Lack of free swap space on ..."   These directions are just designed to get you started.

Why Does PHP Return “Resource Id #2” Or “Resource Id #3”?

Problem scenario
In a LAPP stack deployment, a PHP variable is displaying a value "Resource id #2" or "Resource id #3."  You are expecting a different value.  The PHP variable having the problem is the result of a SQL command ran against a PostgreSQL database.  What should you do?

Solution
Assuming that $var1 is displaying the undesirable "Resource id #2" or "Resource id #3", do something like this:

   $var1 = pg_query($query);
   $rowa = pg_fetch_row($var1);
   $rowb = current($rowa);

Now use $rowb in the capacity you were trying to use $var1.  It should display a human readable value.

How Do You Troubleshoot “docker attach” Commands That Hang?

Problem scenario
You are using RedHat Linux in AWS.  You have installed Docker and have a running container.  You notice that "docker attach <docker ID>" commands are hanging.  What do you to get inside the container?

Solution
Use "docker ps -a" to find the Docker container's name.  Then use a modified version of this draft of a command:

docker exec -it docker-name bash

#Replace "docker-name" above with the name of the Docker container as found from a "docker ps -a"command.

How Do You Edit Text inside a Docker Container?

Problem scenario
The server you have is a RHEL (RedHat Enterprise Linux) or Ubuntu instance.  You are in a Docker container that you pulled from the internet for Nginx.  Inside this Docker container you cannot use vi because it is not a recognized command.  What do you do to install a text editor in the Docker container?

Solution for non-SUSE Linux
#1  Inside the Docker container, even if the server is a RedHat or SUSE distribution, run these two commands:
apt-get -y update
apt-get -y install vim

#2  Ignore errors like these if they appear:

"update-alternatives: warning: skip creation of /usr/share/man/ru/man1/editor.1.gz because associated file /usr/share/man/ru/man1/vim.1.gz (of link group editor) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/ja/man1/editor.1.gz because associated file /usr/share/man/ja/man1/vim.1.gz (of link group editor) doesn't exist
update-alternatives: warning: skip creation of /usr/share/man/man1/editor.1.gz because associated file /usr/share/man/man1/vim.1.gz (of link group editor) doesn't exist"

#3  Now vi should work.  You can use a semicolon between the above two commands and press enter only once (e.g., "apt-get update; apt-get -y install vim").

Solution for SUSE Linux
In our experience, apt-get commands will not work in a Docker container from a SUSE Docker host.

Step #1  Download four .deb files:
curl http://security.debian.org/debian-security/pool/updates/main/v/vim/vim_7.3.547-7+deb7u4_amd64.deb > vim_7.3.547-7+deb7u4_amd64.deb
curl http://security.debian.org/debian-security/pool/updates/main/v/vim/vim-common_7.3.547-7+deb7u4_amd64.deb > vim-common_7.3.547-7+deb7u4_amd64.deb
curl http://security.debian.org/debian-security/pool/updates/main/v/vim/vim-runtime_7.3.547-7+deb7u4_all.deb > vim-runtime_7.3.547-7+deb7u4_all.deb
curl http://ftp.us.debian.org/debian/pool/main/g/gpm/libgpm2_1.20.4-6_amd64.deb > libgpm2_1.20.4-6_amd64.deb

Step #2  Find the Docker container ID that you want to have a text editor.  To do this, run this command:  docker ps -a

Step #3  Copy the .deb files into the Docker container.  In the below commands replace <containerID> with the alphanumeric container ID as found in the above command.

docker cp vim_7.3.547-7+deb7u4_amd64.deb <containerID>:/tmp/vim_7.3.547-7+deb7u4_amd64.deb
docker cp vim-common_7.3.547-7+deb7u4_amd64.deb <containerID>:/tmp/vim-common_7.3.547-7+deb7u4_amd64.deb
docker cp vim-runtime_7.3.547-7+deb7u4_all.deb <containerID>:/tmp/vim-runtime_7.3.547-7+deb7u4_all.deb
docker cp libgpm2_1.20.4-6_amd64.deb <containerID>:/tmp/libgpm2_1.20.4-6_amd64.deb

Step #4  Enter the Docker container by running a command like this:  docker exec -it <containerID> bash

Step #5  Install the four .deb packages
cd /tmp/
dpkg -i *.deb

How Do You Get Nginx in a Docker Container to Log Web Server Activity to a Regular File inside the Container?

Problem scenario
Normally the Nginx web service logs operations (e.g., a user going to a website with a web browser).  By default Nginx Docker containers do not have good logging for web server usage.  You want regular Nginx logging inside the Docker container.  What do you do?

Solution
1.  Go inside the Docker container (e.g., docker exec -it <containerName> bash).  Go to /etc/nginx/

2.  Modify the nginx.conf file.  Find the "access_log" and "error_log" stanzas.  Change the file name to a file that does not yet exist.  Keep the location (/var/log/nginx/) the same in the stanzas.

3.  Restart the Docker container.  

4.  Now you will get regular logging of Nginx activity in the Docker container (e.g., someone accesses the web services from the front end, e.g., opening a web browser and going to the web page that the Nginx in Docker container supports).

“No Day Shall Erase You From the Memory of Time”

While this quote from Virgil's Aeneid is controversial in its 9/11 Museum usage, it is an interesting idea that people may be remembered no matter what happens in the future.

On Patriot Day, also known as the National Day of Service and Rememberance, we have the opportunity to reflect on Americans who have given the full measure of devotion to our country.  The United States of America is a great country with the greatest technology companies in the world.  We recommend everyone make one trip to the 9/11 Museum in his/her lifetime.  To learn more about the terrorist attacks, you may want to read The National Commission's authorized report.

How Do You Find the IP Address Assigned to a Docker Container When It Was Created?

Problem scenario
You have inherited several Docker containers to manage.  They were assigned IP addresses and assigned user-defined networks when they were created.  You do not know what IP addresses that they were given.  You want to know the IP addresses so you can add them to a load balancer.  The external IP address of the Docker host combined with identifying port numbers of the containers can create sockets that are unique.  But you want the internal IP addresses of each of the Docker containers.  How do you find them?

Solution
Run a command like this but substitute "8debfc9b4c32" for the container ID as found in the results of a "docker ps -a" command:

docker inspect 8debfc9b4c32 | grep IPAddress | tail -n 1

How Do You Troubleshoot the Docker Error “User specified IP address is supported only when connecting to networks with user configured subnets.”?

Problem scenario
You are trying to create a Docker image and assign it an IP address with the --ip flag. But you get this error: "/usr/bin/docker-current: Error response from daemon: User specified IP address is supported only when connecting to networks with user configured subnets."  How do you get your Docker command to work and resolve this problem?

Solution
#1  From the Linux server, run this command:  ip addr show

#2  Look at the results for eth0.  Find its "inet" IP address and subnet mask (e.g., 172.31.38.151/20). This is the internal IP address of the Docker server and its subnet mask in shorthand notation.  To determine the IP address of this Docker network you will create, mentally increment the last octet's integer value by 1 and keep the subnet mask for the construction of a command below.  If the calculated number is above 255, find an addressable IP number not being used and within the subnet mask for the server's IP address.

#3  Run a command like the following, however you may want to substitute "isolated_nw1" with the name of your choice for this user-defined network.  You must substitute x.x.x.x in the draft of the command below with the IP address this network will have (possibly as simple as one greater than the last octet of the server's internal IP address).  You will likely substitute 20 with the subnet mask short hand notation that the server's internal IP address has.  

docker network create --driver bridge isolated_nw1 --subnet x.x.x.x/20

The result may look like this:

docker network create --driver bridge isolated_nw1 --subnet 172.31.38.152/20

Take a note of this IP address and mentally increment the last octet one more time.  You'll use that IP address later for a Docker container.  But now you should have a user-defined Docker network with a subnet mask.