{"id":6559,"date":"2017-03-20T16:31:53","date_gmt":"2017-03-20T08:31:53","guid":{"rendered":"http:\/\/rmohan.com\/?p=6559"},"modified":"2017-03-20T16:31:53","modified_gmt":"2017-03-20T08:31:53","slug":"configuring-file-replication-in-rhel-centos-sl-67-with-lsyncd-and-csync2","status":"publish","type":"post","link":"https:\/\/mohan.sg\/?p=6559","title":{"rendered":"Configuring File Replication in RHEL \/ CentOS \/ SL 6\/7 with lsyncd and csync2"},"content":{"rendered":"<p>CentOS \/ SL 6\/7 with lsyncd and csync2<\/p>\n<p>Configuring File Replication in RHEL \/ CentOS \/ SL 6\/7 with lsyncd and csync2<\/p>\n<p>If you want some directory of yours actively backed after every change, they are a lot of sync options to choose from.<br \/>\nSoftware like csync, rsync, csync2, lsyncd and many others will all do the job, but in this article we will only review one of them. We will introduce features of lsyncd, a synchronization daemon that enables you to mirror your designated directory with to any other directory on the network or locally.<br \/>\nTo save network and disk bandwidth, it only mirror changes to your directory. So lets start.<\/p>\n<p>Installing the necessary packages<\/p>\n<p>To install lsyncd and csync2 in CentOS \/ RHEL 6 you only need the EPEL repository and it installs directly via yum as detailed below.<\/p>\n<p>RHEL \/ CentOS \/ SL 6<\/p>\n<p>Configure the EPEL repository<\/p>\n<p>rpm -Uhv https:\/\/dl.fedoraproject.org\/pub\/epel\/epel-release-latest-6.noarch.rpm<br \/>\nInstall the necessary packages<br \/>\nYum install csync2 lsyncd xinetd<br \/>\nRHEL \/ CentOS \/ SL 7<br \/>\nFor versions of RHEL 7 you need to download the version of csync2 that is for Fedora20,<\/p>\n<p>it can be downloaded from the following URL http:\/\/rpm.pbone.net\/index.php3\/stat\/3\/limit\/1\/srodzaj\/ 1 \/ dl \/ 40 \/ search \/ csync2 \/ field% 5B% 5D \/ 1 \/ field% 5B% 5D \/ 2<\/p>\n<p>Once downloaded we installed with the command:<\/p>\n<p>Yum install \/ruta\/del\/rpm\/que\/download.rpm<\/p>\n<p>The previous steps are the only ones that differ as to version 7 of version 6, once installed the steps are the same in both versions<\/p>\n<p>Configure csync2<\/p>\n<p>Enable the csync2 service under xinetd:<\/p>\n<p>To enable the csync2 service through xinetd<\/p>\n<p>sed -i.bak &#8216;s#yes#no#g&#8217; \/etc\/xinetd.d\/csync2<br \/>\nThen we lift the xinetd service<br \/>\nservice xinetd start<br \/>\nGenerate .key for authentication between servers<\/p>\n<p>For the authentication between the servers it is necessary to create a .key file,<br \/>\nWe can create it with the command csync2 and the -k option:<\/p>\n<p>csync2 -k \/etc\/csync2\/csync2.key<br \/>\nConfigure csync2<\/p>\n<p>To configure csync2 we must modify the file \/etc\/csync2\/csync2.cfg, loading the following:<br \/>\nvim \/etc\/csync2\/csync2.cfg<\/p>\n<p>nossl * *;<\/p>\n<p>group web<\/p>\n<p>{<\/p>\n<p>host node1;<\/p>\n<p>host node2;<\/p>\n<p>host node3;<\/p>\n<p>key \/etc\/csync2\/csync2.key;<\/p>\n<p>include \/home\/website\/public_html;<\/p>\n<p>exclude *.log;<\/p>\n<p>auto younger;<\/p>\n<p>}<br \/>\nIt should be noted that the host name (in this case node1) must be the hostname or fqdn of each server<\/p>\n<p>Copy the csync files to the other nodes:<\/p>\n<p>Before copying the settings to the other nodes, the file must be copied \/etc\/csync2\/csync2.cfg a \/etc\/csync2\/csync2_node1.cfg \/etc\/csync2\/csync2_node2.cfg \/etc\/csync2\/csync2_node3.cfg:<br \/>\ncp \/etc\/csync2\/csync2.cfg \/etc\/csync2\/csync2_node1.cfg<br \/>\ncp \/etc\/csync2\/csync2.cfg \/etc\/csync2\/csync2_node2.cfg<br \/>\ncp \/etc\/csync2\/csync2.cfg \/etc\/csync2\/csync2_node3.cfg<br \/>\nFinally we copy to the other nodes:<br \/>\nscp \/etc\/csync2\/* node2:\/etc\/csync2<\/p>\n<p>scp \/etc\/csync2\/* node3:\/etc\/csync3<\/p>\n<p>Start csync2 replication<\/p>\n<p>For the initial synchronization it is necessary to run the following command on all the nodes<br \/>\ncsyncs2 -xv<br \/>\nConfigure lsyncd<\/p>\n<p>Create configuration files<\/p>\n<p>The following lines must be added to the file \/etc\/lsyncd.conf<br \/>\nvim \/etc\/lsyncd.conf<\/p>\n<p>settings {<\/p>\n<p>logident\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = &#8220;lsyncd&#8221;,<\/p>\n<p>logfacility\u00a0\u00a0\u00a0\u00a0 = &#8220;user&#8221;,<\/p>\n<p>logfile\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = &#8220;\/var\/log\/lsyncd.log&#8221;,<\/p>\n<p>statusFile\u00a0\u00a0\u00a0\u00a0\u00a0 = &#8220;\/var\/log\/lsyncd_status.log&#8221;,<\/p>\n<p>statusInterval\u00a0 = 1<\/p>\n<p>}<\/p>\n<p>initSync = {<\/p>\n<p>delay = 1,<\/p>\n<p>maxProcesses = 1,<\/p>\n<p>action = function(inlet)<\/p>\n<p>local config = inlet.getConfig()<\/p>\n<p>local elist = inlet.getEvents(function(event)<\/p>\n<p>return event.etype ~= &#8220;Init&#8221;<\/p>\n<p>end)<\/p>\n<p>local directory = string.sub(config.source, 1, -2)<\/p>\n<p>local paths = elist.getPaths(function(etype, path)<\/p>\n<p>return &#8220;\\t&#8221; .. config.syncid .. &#8220;:&#8221; .. directory .. path<\/p>\n<p>end)<\/p>\n<p>log(&#8220;Normal&#8221;, &#8220;Processing syncing list:\\n&#8221;, table.concat(paths, &#8220;\\n&#8221;))<\/p>\n<p>spawn(elist, &#8220;\/usr\/sbin\/csync2.sh&#8221;, &#8220;-C&#8221;, config.syncid, &#8220;-x&#8221;)<\/p>\n<p>end,<\/p>\n<p>collect = function(agent, exitcode)<\/p>\n<p>local config = agent.config<\/p>\n<p>if not agent.isList and agent.etype == &#8220;Init&#8221; then<\/p>\n<p>if exitcode == 0 then<\/p>\n<p>log(&#8220;Normal&#8221;, &#8220;Startup of &#8216;&#8221;, config.syncid, &#8220;&#8216; instance finished.&#8221;)<\/p>\n<p>elseif config.exitcodes and config.exitcodes[exitcode] == &#8220;again&#8221; then<\/p>\n<p>log(&#8220;Normal&#8221;, &#8220;Retrying startup of &#8216;&#8221;, config.syncid, &#8220;&#8216; instance.&#8221;)<\/p>\n<p>return &#8220;again&#8221;<\/p>\n<p>else<\/p>\n<p>log(&#8220;Error&#8221;, &#8220;Failure on startup of &#8216;&#8221;, config.syncid, &#8220;&#8216; instance.&#8221;)<\/p>\n<p>terminate(-1)<\/p>\n<p>end<\/p>\n<p>return<\/p>\n<p>end<\/p>\n<p>local rc = config.exitcodes and config.exitcodes[exitcode]<\/p>\n<p>if rc == &#8220;die&#8221; then<\/p>\n<p>return rc<\/p>\n<p>end<\/p>\n<p>if agent.isList then<\/p>\n<p>if rc == &#8220;again&#8221; then<\/p>\n<p>log(&#8220;Normal&#8221;, &#8220;Retrying events list on exitcode = &#8220;, exitcode)<\/p>\n<p>else<\/p>\n<p>log(&#8220;Normal&#8221;, &#8220;Finished events list = &#8220;, exitcode)<\/p>\n<p>end<\/p>\n<p>else<\/p>\n<p>if rc == &#8220;again&#8221; then<\/p>\n<p>log(&#8220;Normal&#8221;, &#8220;Retrying &#8220;, agent.etype, &#8221; on &#8220;, agent.sourcePath, &#8221; = &#8220;, exitcode)<\/p>\n<p>else<\/p>\n<p>log(&#8220;Normal&#8221;, &#8220;Finished &#8220;, agent.etype, &#8221; on &#8220;, agent.sourcePath, &#8221; = &#8220;, exitcode)<\/p>\n<p>end<\/p>\n<p>end<\/p>\n<p>return rc<\/p>\n<p>end,<\/p>\n<p>init = function(event)<\/p>\n<p>local inlet = event.inlet;<\/p>\n<p>local config = inlet.getConfig();<\/p>\n<p>log(&#8220;Normal&#8221;, &#8220;Recursive startup sync: &#8220;, config.syncid, &#8220;:&#8221;, config.source)<\/p>\n<p>spawn(event, &#8220;\/usr\/sbin\/csync2.sh&#8221;, &#8220;-C&#8221;, config.syncid, &#8220;-x&#8221;)<\/p>\n<p>end,<\/p>\n<p>prepare = function(config)<\/p>\n<p>if not config.syncid then<\/p>\n<p>error(&#8220;Missing &#8216;syncid&#8217; parameter.&#8221;, 4)<\/p>\n<p>end<\/p>\n<p>local c = &#8220;csync2_&#8221; .. config.syncid .. &#8220;.cfg&#8221;<\/p>\n<p>local f, err = io.open(&#8220;\/etc\/csync2\/&#8221; .. c, &#8220;r&#8221;)<\/p>\n<p>if not f then<\/p>\n<p>error(&#8220;Invalid &#8216;syncid&#8217; parameter: &#8221; .. err, 4)<\/p>\n<p>end<\/p>\n<p>f:close()<\/p>\n<p>end<\/p>\n<p>}<\/p>\n<p>local sources = {<\/p>\n<p>&#8212; change the node1 value with respective host<\/p>\n<p>[&#8220;\/home\/website\/public_html&#8221;] = &#8220;node1&#8221;,<\/p>\n<p>[&#8220;\/otrodirectorio&#8221;] = &#8220;node1&#8221;<\/p>\n<p>}<\/p>\n<p>for key, value in pairs(sources) do<\/p>\n<p>sync {initSync, source=key, syncid=value}<\/p>\n<p>end<br \/>\nDo not forget to change the &#8220;node1&#8243; in each node. For example node2, your \/etc\/lsyncd.conf file definition &#8216;local source&#8217; should use &#8216;node2&#8217;.<\/p>\n<p>Add the path of the lsync configuration file<\/p>\n<p>We must add the path of the file created in the previous step in the file \/etc\/sysconfig\/lsyncd, that we can do with the command sed:<br \/>\nsed -i.bak &#8216;s#^LSYNCD_OPTIONS=.*#LSYNCD_OPTIONS=&#8221; \/etc\/lsyncd.conf&#8221;#g&#8217; \/etc\/sysconfig\/lsyncd<br \/>\nCreate the script that will run lsync<\/p>\n<p>To synchronize the folders, lsync will try to execute the script \/usr\/sbin\/csync2.sh, el cual debemos crear:<br \/>\n\/usr\/sbin\/<br \/>\ncat &lt;&lt;EOF &gt; csync2.sh<br \/>\n#!\/bin\/bash<\/p>\n<p>\/usr\/sbin\/csync2 -xXrv<\/p>\n<p>exit 0<\/p>\n<p>## Exit 0 is added so that lsyncd does not stop when it gives an error<br \/>\nEOF<br \/>\nGive Execution Permissions to Script<br \/>\nChmod 755 \/usr\/sbin\/csync2.sh<br \/>\nEnable and Start the lsyncd service:<\/p>\n<p>We enable the service to interact with the Operating System<br \/>\nChkconfig lsyncd on<br \/>\nThen we lift the service<br \/>\nService lsyncd start<br \/>\n#!\/bin\/sh<br \/>\nfor ((i=0; i&lt;100; i++)); do<br \/>\ntouch \/home\/website\/${i}.html<br \/>\ndone<br \/>\n#!\/bin\/bash<br \/>\nfor ((i=0;i&lt;10;i++))<br \/>\ndo<br \/>\nnumber=$((1000000 + ($(od -An -N2 -i \/dev\/random)) % (10000 + 1000)))<br \/>\nfor ((j=0; j&lt;1000; j++))<br \/>\ndo<br \/>\ntouch \/home\/website\/${i}-${j}.html<br \/>\ndone<br \/>\nsleep ${number}<br \/>\ndone<\/p>\n","protected":false},"excerpt":{"rendered":"<p>CentOS \/ SL 6\/7 with lsyncd and csync2<\/p>\n<p>Configuring File Replication in RHEL \/ CentOS \/ SL 6\/7 with lsyncd and csync2<\/p>\n<p>If you want some directory of yours actively backed after every change, they are a lot of sync options to choose from. Software like csync, rsync, csync2, lsyncd and many others will all [&#8230;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,73],"tags":[],"_links":{"self":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts\/6559"}],"collection":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6559"}],"version-history":[{"count":1,"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts\/6559\/revisions"}],"predecessor-version":[{"id":6560,"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts\/6559\/revisions\/6560"}],"wp:attachment":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6559"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6559"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6559"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}