├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── disksSelector.json
├── main.json
├── old
├── README.md
├── WP_20141105_004.jpg
├── loadbalancers_pg.png
├── machine.json
├── postgresql-primer.md
└── presentation.pptx
├── postgresHAinExistingSubnet.json
├── postgresHAinExistingSubnet.parameters.json
├── postgresHAstandalone.json
├── postgresHAstandalone.parameters.json
└── scripts
├── setup-raid.sh
├── start-pg.sh
└── start-zk.sh
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "editor.renderWhitespace": "all",
4 | "editor.useTabStops": true
5 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Christian
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Deploy to Azure Public
4 |
5 |
6 |
7 |
8 |
9 | ## patroni versions
10 |
11 | ```
12 | 1.1 05951f9b5bbaaf7cd771025f3d8e8f23897d7357
13 | 1.2.4 720d08d1b4bc906fc47ec66ac6d645c75951a1bf
14 | ```
15 |
--------------------------------------------------------------------------------
/disksSelector.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "numDataDisks": {
6 | "type": "string",
7 | "allowedValues": [
8 | "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "32", "64"
9 | ],
10 | "metadata": {
11 | "description": "This parameter allows the user to select the number of disks they want"
12 | }
13 | },
14 | "diskStorageAccountName": {
15 | "type": "string",
16 | "metadata": {
17 | "description": "Name of the storage account where the data disks are stored"
18 | }
19 | },
20 | "diskCaching": {
21 | "type": "string",
22 | "allowedValues": [
23 | "None",
24 | "ReadOnly",
25 | "ReadWrite"
26 | ],
27 | "metadata": {
28 | "description": "Caching type for the data disks"
29 | }
30 | },
31 | "diskSizeGB": {
32 | "type": "int",
33 | "minValue": 1,
34 | "maxValue": 1023,
35 | "metadata": {
36 | "description": "Size of the data disks"
37 | }
38 | },
39 | "storageUrlSuffix": {
40 | "type": "string",
41 | "defaultValue": "', parameters('storageUrlSuffix'), '",
42 | "metadata": {
43 | "description": "Allows the usage of different data centers. (Gov, German, China...)"
44 | }
45 | }
46 | },
47 | "variables": {
48 | "dataDisks": {
49 | "01": [ { "name": "datadisk01", "lun": 0, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk01.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
50 | "02": [ { "name": "datadisk02", "lun": 1, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk02.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
51 | "03": [ { "name": "datadisk03", "lun": 2, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk03.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
52 | "04": [ { "name": "datadisk04", "lun": 3, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk04.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
53 | "05": [ { "name": "datadisk05", "lun": 4, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk05.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
54 | "06": [ { "name": "datadisk06", "lun": 5, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk06.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
55 | "07": [ { "name": "datadisk07", "lun": 6, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk07.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
56 | "08": [ { "name": "datadisk08", "lun": 7, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk08.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
57 | "09": [ { "name": "datadisk09", "lun": 8, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk09.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
58 | "10": [ { "name": "datadisk10", "lun": 9, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk10.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
59 | "11": [ { "name": "datadisk11", "lun": 10, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk11.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
60 | "12": [ { "name": "datadisk12", "lun": 11, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk12.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
61 | "13": [ { "name": "datadisk13", "lun": 12, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk13.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
62 | "14": [ { "name": "datadisk14", "lun": 13, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk14.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
63 | "15": [ { "name": "datadisk15", "lun": 14, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk15.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
64 | "16": [ { "name": "datadisk16", "lun": 15, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk16.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
65 | "17": [ { "name": "datadisk17", "lun": 16, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk17.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
66 | "18": [ { "name": "datadisk18", "lun": 17, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk18.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
67 | "19": [ { "name": "datadisk19", "lun": 18, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk19.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
68 | "20": [ { "name": "datadisk20", "lun": 19, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk20.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
69 | "21": [ { "name": "datadisk21", "lun": 20, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk21.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
70 | "22": [ { "name": "datadisk22", "lun": 21, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk22.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
71 | "23": [ { "name": "datadisk23", "lun": 22, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk23.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
72 | "24": [ { "name": "datadisk24", "lun": 23, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk24.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
73 | "25": [ { "name": "datadisk25", "lun": 24, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk25.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
74 | "26": [ { "name": "datadisk26", "lun": 25, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk26.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
75 | "27": [ { "name": "datadisk27", "lun": 26, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk27.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
76 | "28": [ { "name": "datadisk28", "lun": 27, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk28.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
77 | "29": [ { "name": "datadisk29", "lun": 28, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk29.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
78 | "30": [ { "name": "datadisk30", "lun": 29, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk30.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
79 | "31": [ { "name": "datadisk31", "lun": 30, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk31.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
80 | "32": [ { "name": "datadisk32", "lun": 31, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk32.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
81 | "33": [ { "name": "datadisk33", "lun": 32, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk33.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
82 | "34": [ { "name": "datadisk34", "lun": 33, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk34.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
83 | "35": [ { "name": "datadisk35", "lun": 34, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk35.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
84 | "36": [ { "name": "datadisk36", "lun": 35, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk36.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
85 | "37": [ { "name": "datadisk37", "lun": 36, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk37.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
86 | "38": [ { "name": "datadisk38", "lun": 37, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk38.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
87 | "39": [ { "name": "datadisk39", "lun": 38, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk39.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
88 | "40": [ { "name": "datadisk40", "lun": 39, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk40.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
89 | "41": [ { "name": "datadisk41", "lun": 40, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk41.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
90 | "42": [ { "name": "datadisk42", "lun": 41, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk42.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
91 | "43": [ { "name": "datadisk43", "lun": 42, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk43.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
92 | "44": [ { "name": "datadisk44", "lun": 43, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk44.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
93 | "45": [ { "name": "datadisk45", "lun": 44, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk45.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
94 | "46": [ { "name": "datadisk46", "lun": 45, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk46.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
95 | "47": [ { "name": "datadisk47", "lun": 46, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk47.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
96 | "48": [ { "name": "datadisk48", "lun": 47, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk48.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
97 | "49": [ { "name": "datadisk49", "lun": 48, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk49.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
98 | "50": [ { "name": "datadisk50", "lun": 49, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk50.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
99 | "51": [ { "name": "datadisk51", "lun": 50, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk51.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
100 | "52": [ { "name": "datadisk52", "lun": 51, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk52.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
101 | "53": [ { "name": "datadisk53", "lun": 52, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk53.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
102 | "54": [ { "name": "datadisk54", "lun": 53, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk54.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
103 | "55": [ { "name": "datadisk55", "lun": 54, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk55.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
104 | "56": [ { "name": "datadisk56", "lun": 55, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk56.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
105 | "57": [ { "name": "datadisk57", "lun": 56, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk57.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
106 | "58": [ { "name": "datadisk58", "lun": 57, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk58.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
107 | "59": [ { "name": "datadisk59", "lun": 58, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk59.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
108 | "60": [ { "name": "datadisk60", "lun": 59, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk60.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
109 | "61": [ { "name": "datadisk61", "lun": 60, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk61.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
110 | "62": [ { "name": "datadisk62", "lun": 61, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk62.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
111 | "63": [ { "name": "datadisk63", "lun": 62, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk63.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ],
112 | "64": [ { "name": "datadisk64", "lun": 63, "vhd": { "uri": "[concat('http://', parameters('diskStorageAccountName'),'.blob.', parameters('storageUrlSuffix'), '/vhds/', 'datadisk64.vhd')]" }, "createOption": "Empty", "caching": "[parameters('diskCaching')]", "diskSizeGB": "[parameters('diskSizeGB')]" } ]
113 | },
114 | "_comment2": "The delta arrays below build the difference from 0 to 4, 4 to 8, 8 to 12 disks and so on",
115 | "diskDeltas": {
116 | "4delta": [ "[variables('dataDisks')['01'][0]]", "[variables('dataDisks')['02'][0]]", "[variables('dataDisks')['03'][0]]", "[variables('dataDisks')['04'][0]]" ],
117 | "8delta": [ "[variables('dataDisks')['05'][0]]", "[variables('dataDisks')['06'][0]]", "[variables('dataDisks')['07'][0]]", "[variables('dataDisks')['08'][0]]" ],
118 | "12delta": [ "[variables('dataDisks')['09'][0]]", "[variables('dataDisks')['10'][0]]", "[variables('dataDisks')['11'][0]]", "[variables('dataDisks')['12'][0]]" ],
119 | "16delta": [ "[variables('dataDisks')['13'][0]]", "[variables('dataDisks')['14'][0]]", "[variables('dataDisks')['15'][0]]", "[variables('dataDisks')['16'][0]]" ],
120 | "32delta": [ "[variables('dataDisks')['17'][0]]", "[variables('dataDisks')['18'][0]]", "[variables('dataDisks')['19'][0]]", "[variables('dataDisks')['20'][0]]",
121 | "[variables('dataDisks')['21'][0]]", "[variables('dataDisks')['22'][0]]", "[variables('dataDisks')['23'][0]]", "[variables('dataDisks')['24'][0]]",
122 | "[variables('dataDisks')['25'][0]]", "[variables('dataDisks')['26'][0]]", "[variables('dataDisks')['27'][0]]", "[variables('dataDisks')['28'][0]]",
123 | "[variables('dataDisks')['29'][0]]", "[variables('dataDisks')['30'][0]]", "[variables('dataDisks')['31'][0]]", "[variables('dataDisks')['32'][0]]" ],
124 | "64delta": [ "[variables('dataDisks')['33'][0]]", "[variables('dataDisks')['34'][0]]", "[variables('dataDisks')['35'][0]]", "[variables('dataDisks')['36'][0]]",
125 | "[variables('dataDisks')['37'][0]]", "[variables('dataDisks')['38'][0]]", "[variables('dataDisks')['39'][0]]", "[variables('dataDisks')['40'][0]]",
126 | "[variables('dataDisks')['41'][0]]", "[variables('dataDisks')['42'][0]]", "[variables('dataDisks')['43'][0]]", "[variables('dataDisks')['44'][0]]",
127 | "[variables('dataDisks')['45'][0]]", "[variables('dataDisks')['46'][0]]", "[variables('dataDisks')['47'][0]]", "[variables('dataDisks')['48'][0]]",
128 | "[variables('dataDisks')['49'][0]]", "[variables('dataDisks')['50'][0]]", "[variables('dataDisks')['51'][0]]", "[variables('dataDisks')['52'][0]]",
129 | "[variables('dataDisks')['53'][0]]", "[variables('dataDisks')['54'][0]]", "[variables('dataDisks')['55'][0]]", "[variables('dataDisks')['56'][0]]",
130 | "[variables('dataDisks')['57'][0]]", "[variables('dataDisks')['58'][0]]", "[variables('dataDisks')['59'][0]]", "[variables('dataDisks')['60'][0]]",
131 | "[variables('dataDisks')['61'][0]]", "[variables('dataDisks')['62'][0]]", "[variables('dataDisks')['63'][0]]", "[variables('dataDisks')['64'][0]]" ]
132 | },
133 | "_comment1": "disksArray is ugly :( but it gets the job done. If anyone can make it better, please do!",
134 | "disksArray": {
135 | "1": "[concat(variables('dataDisks')['01'])]",
136 | "2": "[concat(variables('dataDisks')['01'], variables('dataDisks')['02'])]",
137 | "3": "[concat(variables('dataDisks')['01'], variables('dataDisks')['02'], variables('dataDisks')['03'])]",
138 | "4": "[concat(variables('diskDeltas')['4delta'])]",
139 | "5": "[concat(variables('diskDeltas')['4delta'], variables('dataDisks')['05'])]",
140 | "6": "[concat(variables('diskDeltas')['4delta'], variables('dataDisks')['05'], variables('dataDisks')['06'])]",
141 | "7": "[concat(variables('diskDeltas')['4delta'], variables('dataDisks')['05'], variables('dataDisks')['06'], variables('dataDisks')['07'])]",
142 | "8": "[concat(variables('diskDeltas')['4delta'], variables('diskDeltas')['8delta'])]",
143 | "9": "[concat(variables('diskDeltas')['4delta'], variables('diskDeltas')['8delta'], variables('dataDisks')['09'])]",
144 | "10": "[concat(variables('diskDeltas')['4delta'], variables('diskDeltas')['8delta'], variables('dataDisks')['09'], variables('dataDisks')['10'])]",
145 | "11": "[concat(variables('diskDeltas')['4delta'], variables('diskDeltas')['8delta'], variables('dataDisks')['09'], variables('dataDisks')['10'], variables('dataDisks')['11'])]",
146 | "12": "[concat(variables('diskDeltas')['4delta'], variables('diskDeltas')['8delta'], variables('diskDeltas')['12delta'])]",
147 | "13": "[concat(variables('diskDeltas')['4delta'], variables('diskDeltas')['8delta'], variables('diskDeltas')['12delta'], variables('dataDisks')['13'])]",
148 | "14": "[concat(variables('diskDeltas')['4delta'], variables('diskDeltas')['8delta'], variables('diskDeltas')['12delta'], variables('dataDisks')['13'], variables('dataDisks')['14'])]",
149 | "15": "[concat(variables('diskDeltas')['4delta'], variables('diskDeltas')['8delta'], variables('diskDeltas')['12delta'], variables('dataDisks')['13'], variables('dataDisks')['14'], variables('dataDisks')['15'])]",
150 | "16": "[concat(variables('diskDeltas')['4delta'], variables('diskDeltas')['8delta'], variables('diskDeltas')['12delta'], variables('diskDeltas')['16delta'])]",
151 | "32": "[concat(variables('diskDeltas')['4delta'], variables('diskDeltas')['8delta'], variables('diskDeltas')['12delta'], variables('diskDeltas')['16delta'], variables('diskDeltas')['32delta'])]",
152 | "64": "[concat(variables('diskDeltas')['4delta'], variables('diskDeltas')['8delta'], variables('diskDeltas')['12delta'], variables('diskDeltas')['16delta'], variables('diskDeltas')['32delta'], variables('diskDeltas')['64delta'])]"
153 | }
154 | },
155 | "resources": [],
156 | "outputs": {
157 | "dataDiskArray": {
158 | "type": "array",
159 | "value": "[variables('disksArray')[parameters('numDataDisks')]]"
160 | }
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/main.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "tenantName": {
6 | "type": "string",
7 | "defaultValue": "barbaz"
8 | },
9 | "adminUsername": {
10 | "type": "string",
11 | "defaultValue": "chgeuer",
12 | "metadata": { "description": "Admin user name for the Virtual Machines." }
13 | },
14 | "adminSecureShellKey": {
15 | "type": "string",
16 | "defaultValue": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAk/ViUPrGp7KoJLuN2PgofgMyw7SN9zfLYFDDR0TRYa8cOvJlE8NdZYt6Oqa4aL/fslKr9bmlMCdawhZRL7sHccIIS0I0zG7iD15rQL3/Y5aZOf3ML+bebpSj+SE5OeHT9iobgsYpK8gq72d8tmZZAfKhx6fRJsgC2j2xXH/GveoZ5GkHnhJUYuYPmNjEb/PK7LT43XuP+E9Rderr3LPUTuBeGVW9do0HS7X8I2uTn0+BqgkZLOO4FCnSXxh1u6fuD++ZgOZVmB6Q1xEdHSA7LLnPkjDZqbWezLIh5cSdNPUW2JG7tMxQTAZzVoNMb6vAVsfslB16rqZQ21EdIq+0pw== chgeuer-dcos-1",
17 | "metadata": { "description": "Admin SSH key for the Virtual Machines." }
18 | },
19 | "postgresqlUsername": {
20 | "type": "string",
21 | "defaultValue": "pgadmin",
22 | "metadata": { "description": "PostgreSQL user name" }
23 | },
24 | "postgresqlPassword": {
25 | "type": "securestring",
26 | "metadata": { "description": "PostgreSQL password" }
27 | },
28 | "postgresqlInstanceCount": {
29 | "defaultValue": 2, "minValue": 2, "maxValue": 10, "type": "int",
30 | "metadata": { "description": "Number of postgreSQL servers in the cluster." }
31 | },
32 | "postgresqlInstanceSize": {
33 | "defaultValue": "Standard_DS2_v2",
34 | "allowedValues": [
35 | "Standard_DS1", "Standard_DS2", "Standard_DS3", "Standard_DS4",
36 | "Standard_DS11", "Standard_DS12", "Standard_DS13", "Standard_DS14",
37 | "Standard_GS1", "Standard_GS2", "Standard_GS3", "Standard_GS4", "Standard_GS5",
38 | "Standard_DS1_v2", "Standard_DS2_v2", "Standard_DS3_v2", "Standard_DS4_v2", "Standard_DS5_v2",
39 | "Standard_DS11_v2", "Standard_DS12_v2", "Standard_DS13_v2", "Standard_DS14_v2", "Standard_DS15_v2"
40 | ],
41 | "type": "string",
42 | "metadata": { "description": "Size of the postgreSQL servers in the cluster." }
43 | },
44 | "zookeeperInstanceSize": {
45 | "defaultValue": "Standard_DS1_v2",
46 | "allowedValues": [
47 | "Standard_DS1", "Standard_DS2", "Standard_DS3", "Standard_DS4",
48 | "Standard_DS11", "Standard_DS12", "Standard_DS13", "Standard_DS14",
49 | "Standard_GS1", "Standard_GS2", "Standard_GS3", "Standard_GS4", "Standard_GS5",
50 | "Standard_DS1_v2", "Standard_DS2_v2", "Standard_DS3_v2", "Standard_DS4_v2", "Standard_DS5_v2",
51 | "Standard_DS11_v2", "Standard_DS12_v2", "Standard_DS13_v2", "Standard_DS14_v2", "Standard_DS15_v2"
52 | ],
53 | "type": "string",
54 | "metadata": { "description": "Size of the ZooKeeeper servers in the cluster." }
55 | },
56 | "postgresAzureVersion": {
57 | "defaultValue": "master",
58 | "type": "string"
59 | }
60 | },
61 | "variables": {
62 | "commonSettings": {
63 | "baseUrl": "[concat('https://raw.githubusercontent.com/chgeuer/postgres-azure/',parameters('postgresAzureVersion'),'/')]",
64 | "tenantName": "[parameters('tenantName')]",
65 | "constants": {
66 | "apiVersions": {
67 | "availabilitySets": "2016-04-30-preview"
68 | }
69 | },
70 | "vnet": {
71 | "name": "[concat(parameters('tenantName'),'-vnet')]",
72 | "address": "10.0.0.0/16",
73 | "subnet": {
74 | "postgresql": {
75 | "name": "subnet-postgresql",
76 | "nsgName": "nsg-postgresql",
77 | "addressRangePrefix": "10.0.0",
78 | "address": "10.0.0.0/24"
79 | },
80 | "zookeeper": {
81 | "name": "subnet-zookeeper",
82 | "nsgName": "nsg-zookeeper",
83 | "addressRangePrefix": "10.0.1",
84 | "address": "10.0.1.0/24"
85 | }
86 | }
87 | },
88 | "softwareversions": {
89 | "zookeeper": "3.4.9",
90 | "java4zookeeper1": "7u75", "java4zookeeper2": "b13",
91 | "_testedNiko": {
92 | "name": "tested by Niko",
93 | "patroni": "6eb2e2114453545256ac7cbfec55bda285ffb955",
94 | "postgres": "9.5"
95 | },
96 | "patroni_1_1": {
97 | "name": "patroni v1.1",
98 | "patroni": "05951f9b5bbaaf7cd771025f3d8e8f23897d7357",
99 | "postgres": "9.5"
100 | },
101 | "patroni_1_2_4": {
102 | "name": "patroni v1.2.4",
103 | "patroni": "720d08d1b4bc906fc47ec66ac6d645c75951a1bf",
104 | "postgres": "9.6"
105 | }
106 | },
107 | "instanceCount": {
108 | "postgresql": 2,
109 | "postgresqlDataDiskCount": 3,
110 | "zookeeper": 2
111 | },
112 | "vm": {
113 | "postgresql": {
114 | "publisher": "Canonical",
115 | "offer": "UbuntuServer",
116 | "sku": "16.04-LTS",
117 | "version": "latest"
118 | },
119 | "zookeeper": {
120 | "publisher": "Canonical",
121 | "offer": "UbuntuServer",
122 | "sku": "16.04-LTS",
123 | "version": "latest"
124 | }
125 | }
126 | }
127 | },
128 | "resources": [
129 | {
130 | "type": "Microsoft.Network/publicIPAddresses",
131 | "name": "[concat(variables('commonSettings').tenantName, '-publicip')]",
132 | "apiVersion": "2016-09-01",
133 | "location": "[resourceGroup().location]",
134 | "properties": {
135 | "publicIPAllocationMethod": "Dynamic",
136 | "idleTimeoutInMinutes": 30,
137 | "dnsSettings": {
138 | "domainNameLabel": "[concat(variables('commonSettings').tenantName, '-publicip')]"
139 | }
140 | }
141 | },
142 | {
143 | "type": "Microsoft.Network/loadBalancers",
144 | "name": "loadbalancer-postgres",
145 | "apiVersion": "2016-09-01",
146 | "location": "[resourceGroup().location]",
147 | "dependsOn": [
148 | "[concat('Microsoft.Network/publicIPAddresses/', concat(variables('commonSettings').tenantName, '-publicip'))]"
149 | ],
150 | "properties": {
151 | "frontendIPConfigurations": [
152 | {
153 | "name": "postgresqlFrontendIPConfiguration",
154 | "properties": {
155 | "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses', concat(variables('commonSettings').tenantName, '-publicip'))]" }
156 | }
157 | }
158 | ],
159 | "backendAddressPools": [ { "name": "postgresqlBackendAddressPool" } ],
160 | "probes": [
161 | {
162 | "name": "sshProbe",
163 | "properties": {
164 | "protocol": "Tcp",
165 | "port": 22,
166 | "intervalInSeconds": 5,
167 | "numberOfProbes": 2
168 | }
169 | },
170 | {
171 | "name": "postgresqlProbe",
172 | "properties": {
173 | "protocol": "Tcp",
174 | "port": 5000,
175 | "intervalInSeconds": 5,
176 | "numberOfProbes": 2
177 | }
178 | }
179 | ],
180 | "loadBalancingRules": [
181 | {
182 | "name": "loadBalancingRule-ssh",
183 | "properties": {
184 | "protocol": "Tcp",
185 | "frontendPort": 22,
186 | "backendPort": 22,
187 | "enableFloatingIP": false,
188 | "idleTimeoutInMinutes": 30,
189 | "frontendIPConfiguration": { "id": "[concat(resourceId('Microsoft.Network/loadBalancers', 'loadbalancer-postgres'), '/frontendIPConfigurations/', 'postgresqlFrontendIPConfiguration')]" },
190 | "backendAddressPool": { "id": "[concat(resourceId('Microsoft.Network/loadBalancers', 'loadbalancer-postgres'), '/backendAddressPools/', 'postgresqlBackendAddressPool')]" },
191 | "probe": { "id": "[concat(resourceId('Microsoft.Network/loadBalancers', 'loadbalancer-postgres'), '/probes/', 'sshProbe')]" }
192 | }
193 | },
194 | {
195 | "name": "loadBalancingRule-postgresql",
196 | "properties": {
197 | "protocol": "Tcp",
198 | "frontendPort": 5000,
199 | "backendPort": 5000,
200 | "enableFloatingIP": false,
201 | "idleTimeoutInMinutes": 30,
202 | "frontendIPConfiguration": { "id": "[concat(resourceId('Microsoft.Network/loadBalancers', 'loadbalancer-postgres'), '/frontendIPConfigurations/', 'postgresqlFrontendIPConfiguration')]" },
203 | "backendAddressPool": { "id": "[concat(resourceId('Microsoft.Network/loadBalancers', 'loadbalancer-postgres'), '/backendAddressPools/', 'postgresqlBackendAddressPool')]" },
204 | "probe": { "id": "[concat(resourceId('Microsoft.Network/loadBalancers', 'loadbalancer-postgres'), '/probes/', 'postgresqlProbe')]" }
205 | }
206 | }
207 | ]
208 | }
209 | },
210 | {
211 | "type": "Microsoft.Network/networkSecurityGroups",
212 | "name": "[variables('commonSettings').vnet.subnet.postgresql.nsgName]",
213 | "apiVersion": "2016-09-01",
214 | "location": "[resourceGroup().location]",
215 | "properties": {
216 | "securityRules": [
217 | {
218 | "name": "ssh-in",
219 | "properties": {
220 | "priority": 100,
221 | "description": "Allow TCP/22 Inbound (Internet->PostgreSQL Server)",
222 | "access": "Allow",
223 | "direction": "Inbound",
224 | "protocol": "Tcp",
225 | "sourceAddressPrefix": "Internet",
226 | "sourcePortRange": "*",
227 | "destinationAddressPrefix": "[variables('commonSettings').vnet.subnet.postgresql.address]",
228 | "destinationPortRange": "22"
229 | }
230 | },
231 | {
232 | "name": "postgresql-in",
233 | "properties": {
234 | "priority": 101,
235 | "description": "Allow TCP/80 Inbound (Internet->PostgreSQL Server)",
236 | "access": "Allow",
237 | "direction": "Inbound",
238 | "protocol": "Tcp",
239 | "sourceAddressPrefix": "Internet",
240 | "sourcePortRange": "*",
241 | "destinationAddressPrefix": "[variables('commonSettings').vnet.subnet.postgresql.address]",
242 | "destinationPortRange": "5000"
243 | }
244 | }
245 | ]
246 | }
247 | },
248 | {
249 | "type": "Microsoft.Network/networkSecurityGroups",
250 | "name": "[variables('commonSettings').vnet.subnet.zookeeper.nsgName]",
251 | "apiVersion": "2016-09-01",
252 | "location": "[resourceGroup().location]",
253 | "properties": {
254 | "securityRules": [
255 | {
256 | "name": "zookeeper-in",
257 | "properties": {
258 | "priority": 100,
259 | "description": "Allow TCP/2181 Inbound (Patroni --> ZooKeeper)",
260 | "access": "Allow",
261 | "direction": "Inbound",
262 | "protocol": "Tcp",
263 | "sourceAddressPrefix": "[variables('commonSettings').vnet.subnet.postgresql.address]",
264 | "sourcePortRange": "*",
265 | "destinationAddressPrefix": "[variables('commonSettings').vnet.subnet.zookeeper.address]",
266 | "destinationPortRange": "2181"
267 | }
268 | },
269 | {
270 | "name": "zookeeper-cluster-port-1",
271 | "properties": {
272 | "priority": 101,
273 | "description": "Allow TCP/2888 Inbound (ZooKeeper --> ZooKeeper)",
274 | "access": "Allow",
275 | "direction": "Inbound",
276 | "protocol": "Tcp",
277 | "sourceAddressPrefix": "[variables('commonSettings').vnet.subnet.zookeeper.address]",
278 | "sourcePortRange": "*",
279 | "destinationAddressPrefix": "[variables('commonSettings').vnet.subnet.zookeeper.address]",
280 | "destinationPortRange": "2888"
281 | }
282 | },
283 | {
284 | "name": "zookeeper-cluster-port-2",
285 | "properties": {
286 | "priority": 102,
287 | "description": "Allow TCP/3888 Inbound (ZooKeeper --> ZooKeeper)",
288 | "access": "Allow",
289 | "direction": "Inbound",
290 | "protocol": "Tcp",
291 | "sourceAddressPrefix": "[variables('commonSettings').vnet.subnet.zookeeper.address]",
292 | "sourcePortRange": "*",
293 | "destinationAddressPrefix": "[variables('commonSettings').vnet.subnet.zookeeper.address]",
294 | "destinationPortRange": "3888"
295 | }
296 | },
297 | {
298 | "name": "ssh-in",
299 | "properties": {
300 | "priority": 103,
301 | "description": "Allow TCP/22 Inbound",
302 | "access": "Allow",
303 | "direction": "Inbound",
304 | "protocol": "Tcp",
305 | "sourceAddressPrefix": "*",
306 | "sourcePortRange": "*",
307 | "destinationAddressPrefix": "[variables('commonSettings').vnet.subnet.postgresql.address]",
308 | "destinationPortRange": "22"
309 | }
310 | }
311 | ]
312 | }
313 | },
314 | {
315 | "type": "Microsoft.Network/virtualNetworks",
316 | "name": "[variables('commonSettings').vnet.name]",
317 | "apiVersion": "2015-05-01-preview",
318 | "location": "[resourceGroup().location]",
319 | "dependsOn": [
320 | "[concat('Microsoft.Network/networkSecurityGroups/', variables('commonSettings').vnet.subnet.postgresql.nsgName)]",
321 | "[concat('Microsoft.Network/networkSecurityGroups/', variables('commonSettings').vnet.subnet.zookeeper.nsgName)]"
322 | ],
323 | "properties": {
324 | "addressSpace": {
325 | "addressPrefixes": [ "[variables('commonSettings').vnet.address]" ]
326 | },
327 | "subnets": [
328 | {
329 | "name": "[variables('commonSettings').vnet.subnet.postgresql.name]",
330 | "properties": {
331 | "addressPrefix": "[variables('commonSettings').vnet.subnet.postgresql.address]",
332 | "networkSecurityGroup": {
333 | "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('commonSettings').vnet.subnet.postgresql.nsgName)]"
334 | }
335 | }
336 | },
337 | {
338 | "name": "[variables('commonSettings').vnet.subnet.zookeeper.name]",
339 | "properties": {
340 | "addressPrefix": "[variables('commonSettings').vnet.subnet.zookeeper.address]",
341 | "networkSecurityGroup": {
342 | "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('commonSettings').vnet.subnet.zookeeper.nsgName)]"
343 | }
344 | }
345 | }
346 | ]
347 | }
348 | },
349 | {
350 | "type": "Microsoft.Compute/availabilitySets",
351 | "name": "[concat('availabilitySet-postgresql-', variables('commonSettings').tenantName)]",
352 | "apiVersion": "2016-04-30-preview",
353 | "location": "[resourceGroup().location]",
354 | "properties": {
355 | "platformFaultDomainCount": 3,
356 | "platformUpdateDomainCount": 5,
357 | "managed": true
358 | }
359 | },
360 | {
361 | "type": "Microsoft.Network/networkInterfaces",
362 | "name": "[concat('networkInterface-', 'postgresql', '-', copyIndex())]",
363 | "copy": { "name": "postgresqlNicCopy", "count": "[variables('commonSettings').instanceCount.postgresql]" },
364 | "apiVersion": "2016-09-01",
365 | "location": "[resourceGroup().location]",
366 | "dependsOn": [
367 | "[concat('Microsoft.Network/virtualNetworks/', variables('commonSettings').vnet.name)]"
368 | ],
369 | "properties": {
370 | "ipConfigurations": [
371 | {
372 | "name": "[concat('networkInterface-ipConfiguration-', 'postgresql', '-', copyIndex())]",
373 | "properties": {
374 | "privateIPAllocationMethod": "Static",
375 | "privateIPAddress": "[concat(variables('commonSettings').vnet.subnet.postgresql.addressRangePrefix, '.', copyIndex(10))]",
376 | "subnet": { "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', variables('commonSettings').vnet.name), '/subnets/', variables('commonSettings').vnet.subnet.postgresql.name)]" },
377 | "loadBalancerBackendAddressPools": [ { "id": "[concat(resourceId('Microsoft.Network/loadBalancers', 'loadbalancer-postgres'), '/backendAddressPools/', 'postgresqlBackendAddressPool')]" } ]
378 | }
379 | }
380 | ]
381 | }
382 | },
383 | {
384 | "type": "Microsoft.Compute/disks",
385 | "name": "[concat('osDisk-', 'postgresql', '-', copyIndex())]",
386 | "copy": { "name": "postgresqlOsDiskCopy", "count": "[variables('commonSettings').instanceCount.postgresql]" },
387 | "apiVersion": "2016-04-30-preview",
388 | "location": "[resourceGroup().location]",
389 | "properties": {
390 | "osType": "Linux",
391 | "accountType": "Premium_LRS",
392 | "diskSizeGB": 128,
393 | "creationData": {
394 | "createOption": "FromImage",
395 | "imageReference": {
396 | "id": "[concat('/Subscriptions/', subscription().subscriptionId, '/Providers/Microsoft.Compute/Locations/',resourceGroup().location, '/Publishers/', variables('commonSettings').vm.postgresql.publisher, '/ArtifactTypes/VMImage/Offers/', variables('commonSettings').vm.postgresql.offer, '/Skus/', variables('commonSettings').vm.postgresql.sku, '/Versions/', variables('commonSettings').vm.postgresql.version)]"
397 | }
398 | }
399 | }
400 | },
401 | {
402 | "type": "Microsoft.Compute/disks",
403 | "name": "dataDisk1",
404 | "apiVersion": "2016-04-30-preview",
405 | "location": "[resourceGroup().location]",
406 | "properties": {
407 | "accountType": "Premium_LRS",
408 | "diskSizeGB": 128,
409 | "creationData": {
410 | "createOption": "Empty"
411 | }
412 | }
413 | },
414 | {
415 | "type": "Microsoft.Compute/virtualMachines",
416 | "name": "[concat('virtualMachine-', 'postgresql', '-', copyIndex())]",
417 | "copy": { "name": "postgresqlVmCopy", "count": "[variables('commonSettings').instanceCount.postgresql]" },
418 | "apiVersion": "2016-04-30-preview",
419 | "location": "[resourceGroup().location]",
420 | "dependsOn": [
421 | "[concat('Microsoft.Compute/availabilitySets/', concat('availabilitySet-postgresql-', variables('commonSettings').tenantName))]",
422 | "[concat('Microsoft.Network/networkInterfaces/', concat('networkInterface-', 'postgresql', '-', copyIndex()))]",
423 | "[concat('Microsoft.Compute/disks/', concat('osDisk-', 'postgresql', '-', copyIndex()))]"
424 | ],
425 | "properties": {
426 | "hardwareProfile": { "vmSize": "[parameters('postgresqlInstanceSize')]" },
427 | "availabilitySet": {
428 | "id": "[resourceId('Microsoft.Compute/availabilitySets', concat('availabilitySet-postgresql-', variables('commonSettings').tenantName))]"
429 | },
430 | "osProfile": {
431 | "computerName": "[concat('pg', copyIndex())]",
432 | "adminUsername": "[parameters('adminUsername')]",
433 | "linuxConfiguration": {
434 | "disablePasswordAuthentication": true,
435 | "ssh": {
436 | "publicKeys": [
437 | {
438 | "path": "[concat('/home/', parameters('adminUsername'), '/.ssh/authorized_keys')]",
439 | "keyData": "[parameters('adminSecureShellKey')]"
440 | }
441 | ]
442 | }
443 | }
444 | },
445 | "storageProfile": {
446 | "imageReference":
447 | {
448 | "publisher": "[variables('commonSettings').vm.postgresql.publisher]",
449 | "offer": "[variables('commonSettings').vm.postgresql.offer]",
450 | "sku": "[variables('commonSettings').vm.postgresql.sku]",
451 | "version": "[variables('commonSettings').vm.postgresql.version]"
452 | },
453 | "osDisk": {
454 | "name": "[concat('osDisk-', 'postgresql', '-', copyIndex())]",
455 | "caching": "ReadWrite",
456 | "createOption": "FromImage"
457 | }
458 | },
459 | "networkProfile": {
460 | "networkInterfaces": [
461 | {
462 | "id": "[resourceId('Microsoft.Network/networkInterfaces', concat('networkInterface-', 'postgresql', '-', copyIndex()))]"
463 | }
464 | ]
465 | }
466 | }
467 | },
468 | {
469 | "type": "Microsoft.Compute/virtualMachines/extensions",
470 | "name": "[concat('virtualMachine-', 'postgresql', '-', copyIndex(), '/extension')]",
471 | "apiVersion": "2015-05-01-preview",
472 | "location": "[resourceGroup().location]",
473 | "dependsOn": [ "[concat('Microsoft.Compute/virtualMachines/', concat('virtualMachine-', 'postgresql', '-', copyIndex()))]" ],
474 | "copy": { "name": "postgresqlVmExtensionCopy", "count": "[variables('commonSettings').instanceCount.postgresql]" },
475 | "properties": {
476 | "publisher": "Microsoft.OSTCExtensions",
477 | "type": "CustomScriptForLinux",
478 | "typeHandlerVersion": "1.2",
479 | "settings": {
480 | "fileUris": [
481 | "[concat(variables('commonSettings').baseUrl, 'scripts/setup-raid.sh')]",
482 | "[concat(variables('commonSettings').baseUrl, 'scripts/start-zk.sh')]",
483 | "[concat(variables('commonSettings').baseUrl, 'scripts/start-pg.sh')]"
484 | ],
485 | "commandToExecute": "[concat('./start-pg.sh', ' ', parameters('tenantName'), ' ', concat(variables('commonSettings').vnet.subnet.zookeeper.addressRangePrefix, '.10'), ' ', variables('commonSettings').instanceCount.zookeeper, ' ', concat(variables('commonSettings').vnet.subnet.postgresql.addressRangePrefix, '.10'), ' ', variables('commonSettings').instanceCount.postgresql, ' ', copyIndex(), ' ', parameters('postgresqlUsername'), ' ', concat('\"', parameters('postgresqlPassword'), '\"'), ' ', variables('commonSettings').softwareversions._testedNiko.patroni, ' ', variables('commonSettings').softwareversions._testedNiko.postgres)]"
486 | }
487 | }
488 | },
489 | {
490 | "type": "Microsoft.Compute/availabilitySets",
491 | "name": "[concat('availabilitySet-zookeeper-', variables('commonSettings').tenantName)]",
492 | "apiVersion": "2016-04-30-preview",
493 | "location": "[resourceGroup().location]",
494 | "properties": {
495 | "platformFaultDomainCount": 3,
496 | "platformUpdateDomainCount": 5,
497 | "managed": true
498 | }
499 | },
500 | {
501 | "type": "Microsoft.Network/networkInterfaces",
502 | "name": "[concat('networkInterface-', 'zookeeper', '-', copyIndex())]",
503 | "copy": { "name": "zookeeperNicCopy", "count": "[variables('commonSettings').instanceCount.zookeeper]" },
504 | "apiVersion": "2016-09-01",
505 | "location": "[resourceGroup().location]",
506 | "dependsOn": [
507 | "[concat('Microsoft.Network/virtualNetworks/', variables('commonSettings').vnet.name)]"
508 | ],
509 | "properties": {
510 | "ipConfigurations": [
511 | {
512 | "name": "[concat('networkInterface-ipConfiguration-', 'zookeeper', '-', copyIndex())]",
513 | "properties": {
514 | "privateIPAllocationMethod": "Static",
515 | "privateIPAddress": "[concat(variables('commonSettings').vnet.subnet.zookeeper.addressRangePrefix, '.', copyIndex(10))]",
516 | "subnet": { "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', variables('commonSettings').vnet.name), '/subnets/', variables('commonSettings').vnet.subnet.zookeeper.name)]" }
517 | }
518 | }
519 | ]
520 | }
521 | },
522 | {
523 | "type": "Microsoft.Compute/disks",
524 | "name": "[concat('osDisk-', 'zookeeper', '-', copyIndex())]",
525 | "copy": { "name": "zookeeperOsDiskCopy", "count": "[variables('commonSettings').instanceCount.zookeeper]" },
526 | "apiVersion": "2016-04-30-preview",
527 | "location": "[resourceGroup().location]",
528 | "properties": {
529 | "osType": "Linux",
530 | "accountType": "Premium_LRS",
531 | "diskSizeGB": 128,
532 | "creationData": {
533 | "createOption": "FromImage",
534 | "imageReference": {
535 | "id": "[concat('/Subscriptions/', subscription().subscriptionId, '/Providers/Microsoft.Compute/Locations/',resourceGroup().location, '/Publishers/', variables('commonSettings').vm.zookeeper.publisher, '/ArtifactTypes/VMImage/Offers/', variables('commonSettings').vm.zookeeper.offer, '/Skus/', variables('commonSettings').vm.zookeeper.sku, '/Versions/', variables('commonSettings').vm.zookeeper.version)]"
536 | }
537 | }
538 | }
539 | },
540 |
541 | {
542 | "type": "Microsoft.Compute/virtualMachines",
543 | "name": "[concat('virtualMachine-', 'zookeeper', '-', copyIndex())]",
544 | "copy": { "name": "zookeeperVmCopy", "count": "[variables('commonSettings').instanceCount.zookeeper]" },
545 | "apiVersion": "2016-04-30-preview",
546 | "location": "[resourceGroup().location]",
547 | "dependsOn": [
548 | "[concat('Microsoft.Compute/availabilitySets/', concat('availabilitySet-zookeeper-', variables('commonSettings').tenantName))]",
549 | "[concat('Microsoft.Network/networkInterfaces/', concat('networkInterface-', 'zookeeper', '-', copyIndex()))]",
550 | "[concat('Microsoft.Compute/disks/', concat('osDisk-', 'zookeeper', '-', copyIndex()))]"
551 | ],
552 | "properties": {
553 | "hardwareProfile": { "vmSize": "[parameters('zookeeperInstanceSize')]" },
554 | "availabilitySet": {
555 | "id": "[resourceId('Microsoft.Compute/availabilitySets', concat('availabilitySet-zookeeper-', variables('commonSettings').tenantName))]"
556 | },
557 | "osProfile": {
558 | "computerName": "[concat('zk', copyIndex())]",
559 | "adminUsername": "[parameters('adminUsername')]",
560 | "linuxConfiguration": {
561 | "disablePasswordAuthentication": true,
562 | "ssh": {
563 | "publicKeys": [
564 | {
565 | "path": "[concat('/home/', parameters('adminUsername'), '/.ssh/authorized_keys')]",
566 | "keyData": "[parameters('adminSecureShellKey')]"
567 | }
568 | ]
569 | }
570 | }
571 | },
572 | "storageProfile": {
573 | "imageReference":
574 | {
575 | "publisher": "[variables('commonSettings').vm.zookeeper.publisher]",
576 | "offer": "[variables('commonSettings').vm.zookeeper.offer]",
577 | "sku": "[variables('commonSettings').vm.zookeeper.sku]",
578 | "version": "[variables('commonSettings').vm.zookeeper.version]"
579 | },
580 | "osDisk": {
581 | "name": "[concat('osDisk-', 'zookeeper', '-', copyIndex())]",
582 | "caching": "ReadWrite",
583 | "createOption": "FromImage"
584 | }
585 | },
586 | "networkProfile": {
587 | "networkInterfaces": [
588 | {
589 | "id": "[resourceId('Microsoft.Network/networkInterfaces', concat('networkInterface-', 'zookeeper', '-', copyIndex()))]"
590 | }
591 | ]
592 | }
593 | }
594 | },
595 | {
596 | "type": "Microsoft.Compute/virtualMachines/extensions",
597 | "name": "[concat('virtualMachine-', 'zookeeper', '-', copyIndex(), '/extension')]",
598 | "apiVersion": "2015-05-01-preview",
599 | "location": "[resourceGroup().location]",
600 | "dependsOn": [ "[concat('Microsoft.Compute/virtualMachines/', concat('virtualMachine-', 'zookeeper', '-', copyIndex()))]" ],
601 | "copy": { "name": "zookeeperVmExtensionCopy", "count": "[variables('commonSettings').instanceCount.zookeeper]" },
602 | "properties": {
603 | "publisher": "Microsoft.OSTCExtensions",
604 | "type": "CustomScriptForLinux",
605 | "typeHandlerVersion": "1.2",
606 | "settings": {
607 | "fileUris": [
608 | "[concat(variables('commonSettings').baseUrl, 'scripts/start-zk.sh')]"
609 | ],
610 | "commandToExecute": "[concat('./start-zk.sh', ' ', copyIndex(), ' ', variables('commonSettings').instanceCount.zookeeper, ' ', concat(variables('commonSettings').vnet.subnet.zookeeper.addressRangePrefix, '.10'), ' ', variables('commonSettings').softwareversions.zookeeper, ' ', variables('commonSettings').softwareversions.java4zookeeper1, ' ', variables('commonSettings').softwareversions.java4zookeeper2)]"
611 | }
612 | }
613 | }
614 | ],
615 | "outputs": {
616 |
617 | }
618 | }
--------------------------------------------------------------------------------
/old/README.md:
--------------------------------------------------------------------------------
1 | Setting up PostgreSQL on Microsoft Azure Virtual Machines (IaaS)
2 | ================================================================
3 |
4 | # Architecture
5 |
6 |
7 |
8 |
9 |
10 | # Login to Azure
11 |
12 | You'll need an Azure subscription. You can get a [free trial](http://www.windowsazure.com/en-us/pricing/free-trial/?WT.mc_id=AA4C1C935).
13 |
14 | - Download publish settings at https://manage.windowsazure.com/publishsettings/index?client=xplat
15 |
16 | ```console
17 | npm install azure-cli
18 | azure account clear
19 | azure account import "Windows Azure MSDN - Visual Studio Ultimate-credentials.publishsettings"
20 | azure account set "internal"
21 | azure account list
22 | ```
23 |
24 | For more detailed instructions on setting up the Azure CLI tools see https://vmdepot.msopentech.com/help/deploy/cli.html/
25 |
26 | # Create a base Linux image
27 |
28 | We'll use a Debian image from VM Depot, find the most recent with [this search](https://vmdepot.msopentech.com/List/Index?sort=Date&search=platform%3Adebian)
29 |
30 | There are a number of ways to deploy the image, below is an outline of how to do it with the command line tools. VM Depot has documentation on [other methods](https://vmdepot.msopentech.com/help/deploy.html/).
31 |
32 | ```console
33 | azure vm list --json
34 | azure vm create DNS_PREFIX --community vmdepot-65-6-32 --virtual-network-name -l "West Europe" USER_NAME [PASSWORD] [--ssh] [other_options]
35 |
36 | Create an A5 instance
37 | ```
38 |
39 | It would be great if people [published a Postgres image](https://vmdepot.msopentech.com/help/contribute.html/) after following this tutorial (it doesn't cost anything). That way those who follow will not have to do this initial configuration work.
40 |
41 | # Command line for creating a PostgreSQL machine
42 |
43 | Command line:
44 |
45 | ```console
46 | azure vm create-from cloudservicename machine.json --connect --verbose --json
47 | ```
48 |
49 | ## machine.json
50 |
51 | See the [REST API](http://msdn.microsoft.com/en-us/library/azure/jj157194.aspx) for details.
52 |
53 | ```JSON
54 | {
55 | "RoleName": "database-vm-1",
56 | "RoleType": "PersistentVMRole",
57 | "RoleSize": "A5",
58 | "AvailabilitySetName" : "databases",
59 | "OSVirtualHardDisk": {
60 | "OS": "Linux",
61 | "HostCaching": "ReadWrite",
62 | "DiskName": "database-vm-1-disk",
63 | "DiskLabel": "database-vm-1-disk",
64 | "SourceImageName": "Debian-Wheezy-635506180993665396",
65 | "RemoteSourceImageLink": "http://account.blob.core.windows.net/vmdepot-images/TE-2014-11-03-debianwheezy-os-2014-11-03.vhd",
66 | "MediaLink" : "http://account.blob.core.windows.net/vmdepot-images/database-vm-1-disk.vhd"
67 | },
68 | "DataVirtualHardDisks": [
69 | { "DiskLabel": "database-vm-1-data1", "Lun": "0", "MediaLink" : "http://account.blob.core.windows.net/vmdepot-images/database-vm-1-data1.vhd", "HostCaching": "ReadOnly", "LogicalDiskSizeInGB": "1023" },
70 | { "DiskLabel": "database-vm-1-data2", "Lun": "1", "MediaLink" : "http://account.blob.core.windows.net/vmdepot-images/database-vm-1-data2.vhd", "HostCaching": "ReadOnly", "LogicalDiskSizeInGB": "1023" },
71 | { "DiskLabel": "database-vm-1-xlog1", "Lun": "2", "MediaLink" : "http://account.blob.core.windows.net/vmdepot-images/database-vm-1-xlog1.vhd", "HostCaching": "ReadOnly", "LogicalDiskSizeInGB": "1023" }
72 | ],
73 | "ConfigurationSets": [
74 | {
75 | "ConfigurationSetType" : "LinuxProvisioningConfiguration",
76 | "HostName" : "database-vm-1",
77 | "UserName" : "ruth",
78 | "UserPassword" : "Supersecret123!!",
79 | "DisableSshPasswordAuthentication" : false
80 | },
81 | {
82 | "ConfigurationSetType": "NetworkConfiguration",
83 | "SubnetNames": [ "mysubnet" ],
84 | "StaticVirtualNetworkIPAddress": "10.10.0.7",
85 | "InputEndpoints": [],
86 | "PublicIPs": [],
87 | "StoredCertificateSettings": []
88 | }
89 | ],
90 | "ProvisionGuestAgent": "true",
91 | "ResourceExtensionReferences": []
92 | }
93 | ```
94 |
95 | # Bring Linux up to date
96 |
97 | ```console
98 | $ aptitude update && aptitude upgrade
99 | $ aptitude install rsync
100 | $ aptitude install mdadm lvm2 xfsprogs
101 | $ aptitude install pacemaker corosync resource-agents
102 | ```
103 |
104 | # Setup striping
105 |
106 | - Multiple data disks in a [RAID](http://azure.microsoft.com/en-us/documentation/articles/virtual-machines-linux-configure-raid/) in order to achieve higher I/O, given current limitation of 500 IOPS per data disk.
107 | - One data disk for pg_xlog
108 |
109 |
110 | ## A couple of inputs for fdisk
111 |
112 | ```console
113 | # Standard fdisk partition
114 | fdiskStdin=$(cat <<'END_HEREDOC'
115 | n
116 | p
117 | 1
118 |
119 |
120 | w
121 | END_HEREDOC
122 | )
123 |
124 | # cfdisk command for 'FD' (RAID autodetect) for RAID
125 | cfdiskStdinFD=$(cat <<'END_HEREDOC'
126 | np
127 |
128 | tFD
129 | Wyes
130 | q
131 | END_HEREDOC
132 | )
133 |
134 | # cfdisk command for '8E' (LVM)
135 | cfdiskStdin8E=$(cat <<'END_HEREDOC'
136 | np
137 |
138 | t8E
139 | Wyes
140 | q
141 | END_HEREDOC
142 | )
143 | ```
144 |
145 | ## cfdisk and amalgamate the disks
146 |
147 | ```console
148 | # Use 'cfdisk' on /dev/sdc and create a primary partition of type 'FD' (RAID autodetect) for RAID for pg_data
149 | echo "$cfdiskStdinFD" | cfdisk /dev/sdc
150 |
151 | # Use 'cfdisk' on /dev/sdd and create a primary partition of type 'FD' (RAID autodetect) for RAID for pg_data
152 | echo "$cfdiskStdinFD" | cfdisk /dev/sdd
153 |
154 | # Use 'cfdisk' on /dev/sde and create a primary partition of type '8E' (LVM) for pg_xlog
155 | echo "$cfdiskStdin8E" | cfdisk /dev/sde
156 |
157 | #################################
158 |
159 | mdadm --create /dev/md0 --level 0 --raid-devices 2 /dev/sdc1 /dev/sdd1
160 |
161 | # create physical volume
162 | pvcreate /dev/md0
163 |
164 | # create volume group
165 | vgcreate data /dev/md0
166 |
167 | # create logical volume
168 | lvcreate -n pgdata -l100%FREE data
169 |
170 | # show volume group information
171 | vgdisplay
172 |
173 | # Now
174 | ls -als /dev/data/pgdata
175 |
176 | # mkfs -t xfs /dev/data/pgdata
177 | mkfs.xfs /dev/data/pgdata
178 | ```
179 |
180 | Setup automount
181 |
182 | ```console
183 | $ tail /etc/fstab
184 |
185 | /dev/mapper/data-pgdata /space/pgdata xfs defaults 0 0
186 | /dev/mapper/xlog-pgxlog /space/pgxlog xfs defaults 0 0
187 | ```
188 |
189 |
190 |
191 |
192 |
193 |
194 | # PostgreSQL base install
195 |
196 |
197 |
198 | ## Install PostgreSQL
199 |
200 | Install PostgreSQL, as documented under https://wiki.postgresql.org/wiki/Apt
201 |
202 | ```
203 | $ sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
204 |
205 | $ aptitude install wget ca-certificates
206 |
207 | $ wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
208 |
209 | $ aptitude install postgresql-9.3
210 |
211 | $ aptitude install repmgr
212 | ```
213 |
214 |
215 | ## Move database files into striped volume
216 |
217 | ```
218 | mv /var/lib/postgresql/9.3 /space/pgdata/
219 | ln -s /space/pgdata/9.3 /var/lib/postgresql/9.3
220 |
221 | mv /space/pgdata/9.3/main/pg_xlog /space/pgxlog/9.3
222 | ln -s /space/pgxlog/9.3 /space/pgdata/9.3/main/pg_xlog
223 | ```
224 |
225 |
226 | # Distribute SSH keys for user postgres across the cluster
227 |
228 | Whatever it takes
229 |
230 |
231 |
232 |
233 | ## Edit /etc/postgresql/9.3/main/postgresql.conf
234 |
235 | Uncomment listen_addresses (Database only reachable through jump host)
236 |
237 | ```
238 | listen_addresses = '*'
239 | ```
240 |
241 | Switch off SSL
242 |
243 | ```
244 | ssl = false
245 | ```
246 |
247 | Rule of thumb for shared buffers: 25% of RAM should be shared buffers, on an A5
248 |
249 | ```
250 | shared_buffers = 4GB
251 | work_mem = 256MB
252 | maintenance_work_mem = 512MB
253 | ```
254 |
255 | The write-ahead-log needs to be merged at regular checkpoints into the tables:
256 |
257 | ```
258 | checkpoint_segments = 64 # was 3 previously in logfile segments, min 1, 16MB each
259 | checkpoint_timeout = 1min # range 30s-1h
260 | checkpoint_completion_target = 0.8 # checkpoint target duration, 0.0 - 1.0
261 | ```
262 |
263 | Put replication configuration into dedicated file
264 |
265 | ```
266 | include_if_exists = 'replication.conf'
267 | ```
268 |
269 | # Edit /etc/postgresql/9.3/main/replication.conf
270 |
271 | ## wal_keep_segments
272 |
273 | How many segments to hold in xlog folder. Having a longer value allows slaves to keep up. 500*16 MB = 8 GB
274 |
275 | ```
276 | wal_keep_segments=500
277 | ```
278 | ## wal_level
279 |
280 | All nodes (master and slaves) need to be in hot_standby to that slaves can become master.
281 |
282 | ```
283 | wal_level='hot_standby'
284 | ```
285 |
286 | ## archive_mode and archive_command
287 |
288 | ```
289 | archive_mode=on
290 | archive_command='cd .'
291 | ```
292 |
293 | ## max_wal_senders
294 |
295 | Number of machines, takes away from max_connections. Should be very similar to the size of the cluster. Between 5 and 10 is "OK". Numbers like 500 kill the machine
296 |
297 | ```
298 | max_wal_senders=5
299 | ```
300 |
301 | ## hot_standby
302 |
303 | Allows slaves to already answer to read queries.
304 |
305 | ```
306 | hot_standby=on
307 | ```
308 |
309 | # Add postgres user with replication priviledge and superuser
310 |
311 | ```console
312 | # username "repl"
313 | # -P = get password from
314 | # -S = super user, in order to run repmgr (otherwise, error "permission denied for language C" comes)
315 |
316 | $ su postgres
317 | $ createuser --replication -P -S repl
318 | ```
319 |
320 | ## Edit /etc/postgresql/9.3/main/pg_hba.conf
321 |
322 | As postgres user, add the following line to allow subnet 10.10.0.0/16 to do replication with user ID "repl"
323 |
324 | ```
325 | host all all 10.10.0.0/16 md5
326 | host replication repl 10.10.0.0/16 md5
327 | ```
328 |
329 | ## Configure /var/lib/postgresql/repmgr.conf on all hosts.
330 |
331 | As postgres user, These settings are written to the DB, and visible in the cluster, so IPs must be real ones .
332 |
333 | ```
334 | All nodes have the same cluster name
335 | cluster=my_application_cluster
336 | pg_bindir='/usr/lib/postgres/9.3/bin'
337 |
338 | # This must unique be for each respective node
339 | node=1
340 | node_name=postgresvm1
341 | conninfo='host=10.10.0.7 user=repl dbname=repmgr'
342 | ```
343 |
344 |
345 | ## Setup repmgr internals on master node.
346 |
347 | ### vim /var/lib/postgresql/.pgpass
348 |
349 | ```
350 | # hostname:port:database:username:password
351 | *:*:*:repl:supersecret123.-
352 | ```
353 |
354 | Permissions
355 |
356 | ```console
357 | $ chmod 0600 /var/lib/postgresql/.pgpass
358 | ```
359 |
360 | ### Setup repmgr on master node
361 |
362 | ```console
363 | $ sudo postgres / su - postgres
364 | $ repmgr -f /var/lib/postgresql/repmgr.conf --verbose master register
365 | ```
366 |
367 | ### Setup repmgr on standby nodes (slaves) *before starting postgres on the slaves*
368 |
369 | ```console
370 | $ sudo postgres / su - postgres
371 |
372 | $ service postgresql stop
373 |
374 | # -d database
375 | # -U user
376 | # -R rsync user
377 | # -D data dir
378 | # -w WAL keep segments (default is 5000, which is too large)
379 | # 10.10.0.7 IP address of master
380 |
381 | $ repmgr -d repmgr \
382 | -U repl \
383 | -R postgres -w 500 \
384 | -D /var/lib/postgres/9.3/main \
385 | -f /var/lib/postgresql/repmgr.conf \
386 | --verbose \
387 | standby clone 10.10.0.7
388 |
389 | $ service postgresql start
390 |
391 | $ repmgr -f /var/lib/postgresql/repmgr.conf \
392 | --verbose standby register
393 | ```
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 | # Local agent
410 |
411 | ## When the current master goes down
412 |
413 | When master gets shutdown signal,
414 |
415 | 1. Refuse additional (new) connections:
416 | - change file [pg_hba.conf](http://www.postgresql.org/docs/9.1/static/auth-pg-hba-conf.html) to reject new connections
417 | - "SELECT pg_reloadconf();" or "pg_ctl reload conf" or "kill -HUP" to enact configuration
418 | 2. [Drop existing sessions](http://www.devopsderek.com/blog/2012/11/13/list-and-disconnect-postgresql-db-sessions/)
419 | - "SELECT pg_terminate_backend( )"
420 | 3. Instruct PostgreSQL to write (flush) remaining transaction log (WAL records) to tables by creating a checkpoint
421 |
422 |
423 | ### Refuse additional (new) connections
424 |
425 | Edit [pg_hba.conf](http://www.postgresql.org/docs/9.1/static/auth-pg-hba-conf.html): Uncomment the "all/all" line, so that nobody can create additional connections.
426 |
427 | ```
428 | # host all all 10.10.0.0/16 md5
429 | ```
430 |
431 | And reload config
432 |
433 | ```SQL
434 | SELECT pg_reload_conf();
435 | ```
436 |
437 | ### Drop existing sessions from the web tier
438 |
439 | ```SQL
440 | SELECT pg_terminate_backend(pid)
441 | FROM pg_stat_activity
442 | WHERE usename='webfrontend';
443 | ```
444 |
445 | (Yes, it is 'usename', not 'username')...
446 |
447 |
448 | ### Create a checkpoint on master via SQL
449 |
450 | ```SQL
451 | CHECKPOINT;
452 | ```
453 |
454 | ### Determine xlog location
455 |
456 | Determine xlog location of the current xlog position, something after the previously made checkpoint. Here, we can be sure that after the checkpoint, only non-relevant changes (like vacuuming) happened to the tables.
457 |
458 | Now fetch (once) after the checkpoint operation on the master the XLOG location, and store it in a variable `checkpointXlog`:
459 |
460 | ```SQL
461 | SELECT pg_current_xlog_location();
462 | ```
463 |
464 | Determine replication lag for the slaves. When the `pg_xloc_location_diff(...)` function call returns 0, all slaves have catched up. Running below code gives a current view:
465 |
466 | ```SQL
467 | SELECT client_addr,
468 | flush_location,
469 | pg_current_xlog_location(),
470 | pg_xlog_location_diff(
471 | pg_current_xloc_location(),
472 | flush_location)
473 | from pg_stat_replication;
474 | ```
475 |
476 | Using the post-checkpoint variable `checkpointXlog`, you can now determine whether it is safe to kill the master.
477 |
478 | ```ruby
479 | var checkpointXlog = eval("SELECT pg_current_xlog_location();")
480 |
481 | checkpointXlog == '0/14047810'
482 | ```
483 |
484 | Now we can determine the concrete replication lag:
485 |
486 | ```SQL
487 | SELECT client_addr,
488 | flush_location,
489 | '0/14047810',
490 | pg_xlog_location_diff(
491 | '0/14047810',
492 | flush_location)
493 | from pg_stat_replication;
494 | ```
495 |
496 | - When the `pg_xlog_location_diff` column has non-positiv values, it's safe to shoot the master in the head.
497 | - When we compare against `flush_location`, we not it's on the harddisk of the slave.
498 | - When we compare against `replay_location`, we know it's in the actual database tables.
499 |
500 | Stop old master server
501 |
502 | ```console
503 | $ sudo postgres / su - postgres
504 | $ service postgresql stop
505 | ```
506 |
507 | ## Turn one of the slaves into the new master (`repmgr standby promote`)
508 |
509 | Use either `repmgr standby promote` (as a convenient wrapper) or naked `pg_ctl promote`.
510 |
511 | ```bash
512 | $ sudo postgres / su - postgres
513 | $ repmgr -f /var/lib/postgresql/repmgr.conf --verbose standby promote
514 | ```
515 |
516 | ## Tell slaves to sync against the new master (`repmgr standby follow`)
517 |
518 | All nodes (master and slaves) know each other. When calling `repmgr standby follow` is forced upon the slaves, they ask around (via SQL) to determine who the new master is. This is done by calling `pg_is_in_recovery()`, which is `false` on a master. This step recreates the `recovery.conf` file, which lists the IP of the new master.
519 |
520 | ```
521 | $ sudo postgres / su - postgres
522 | $ repmgr -f /var/lib/postgresql/repmgr.conf --verbose standby follow
523 | ```
524 |
525 | ## Turn old master into new slave (`repmgr standby clone`)
526 |
527 | 1. Stop PostgreSQL
528 | 2. Enable `all/all` in `pg_hba.conf` again
529 | 3. Clone from new master (`repmgr standby clone`)
530 | 4. Start PostgreSQL
531 | 5. Hook up to synchronisation (`repmgr standby register`)
532 |
533 | Make a `repmgr standby clone` against a previous slave, who became master
534 |
535 | ```console
536 | $ sudo postgres / su - postgres
537 |
538 | $ vim /etc/postgresql/9.3/main/pg_hba.conf
539 |
540 | $ service postgresql stop
541 |
542 | $ repmgr -d repmgr \
543 | -U repl \
544 | -R postgres -w 500 \
545 | -D /var/lib/postgres/9.3/main \
546 | -f /var/lib/postgresql/repmgr.conf \
547 | --verbose \
548 | standby clone 10.10.0.5
549 |
550 | $ service postgresql start
551 |
552 | $ repmgr -f /var/lib/postgresql/repmgr.conf \
553 | --verbose standby register
554 | ```
555 |
556 | # pgbouncer
557 |
558 | ## /etc/pgbouncer/pgbouncer.ini contents
559 |
560 | Assumptions:
561 |
562 | - pgbouncer service is on 10.10.0.20 (and similarly on other boxes), behind an internal load balancer
563 | - current master is 10.10.0.5
564 | - current slaves are 10.10.0.6 and 10.10.0.7
565 | - The application logic uses two different endpoints for updates (writes) and pure queries (reads).
566 |
567 |
568 | ```ini
569 | [databases]
570 | myapp-write = host=primary port=5433
571 | myapp-readonly = port=5434
572 |
573 | [pgbouncer]
574 | listen_addr = 10.10.0.20, 127.0.0.1
575 | listen_port = 5432
576 | pool_mode = transaction
577 | max_client_conn = 500
578 | default_pool_size = 20
579 | ```
580 |
581 | ## Configure internal load balancer
582 |
583 | ```powershell
584 | Add-AzureAccount
585 | Set-AzureSubscription -SubscriptionName "BizSpark Plus" -SubscriptionId "8eefc6f2-7216-4aef-8394-fce57df325a3"
586 | Select-AzureSubscription -SubscriptionName "BizSpark Plus" -Default
587 |
588 | Add-AzureInternalLoadBalancer -InternalLoadBalancerName pgbouncer -ServiceName fantasyweb -SubnetName fantasy -StaticVNetIPAddress 10.10.0.100
589 |
590 | Get-AzureVM -ServiceName fantasyweb -Name pooler1 | Add-AzureEndpoint -Name "pgbouncer" -LBSetName "pgbouncer" -Protocol tcp -LocalPort 5432 -PublicPort 5432 -ProbePort 5432 -ProbeProtocol tcp -ProbeIntervalInSeconds 10 -InternalLoadBalancerName pgbouncer | Update-AzureVM
591 |
592 | ```
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 | # PostgreSQL admin stuff
615 |
616 | ```console
617 | $ createuser application_admin
618 |
619 | # -O owner
620 | $ createdb -O application_admin my_database
621 |
622 | # Add application_admin to administrators in /etc/postgresql/9.3/main/pg_hba.conf
623 | $ vim /etc/postgresql/9.3/main/pg_hba.conf
624 |
625 | # -s n scaling factor
626 | # -i initialization
627 | # -U username
628 | % pgbench -s 10 -i -U application_admin my_database
629 |
630 | $ service postgresql start
631 | ```
632 |
633 | # pg_control.rb
634 |
635 | - A "clone" is a resource that gets active on multiple nodes. There are also stateful clones.
636 | - It seems PostgreSQL is a "[multi-state resource][pacemaker-resource-multi-state]" are clones which can have multiple modes.
637 | - [OCF Operations][pacemaker-ocf-operations] are promote / demote / notify
638 | - CRM resources define three nodes. One resource per node. One master per cluster.
639 | - The "script" which needs to be developed is an "OCF resource agent".
640 | - This script must implement four operations: start / stop / monitor / notify
641 | - A sample script can be seen in `/usr/lib/ocf/resource.d/heartbeat/*`
642 | - Possible commands from CRM which hit the script:
643 | - Node should be a completely new master: this is never the case
644 | - Node should become slave of an existing master:
645 | - Current master VM gets rebootet or shutdown:
646 | - Previous slave should become master: "start MASTER"
647 | - The [OCF return codes][pacemaker-ocf-return-codes] must be returned for operations
648 | - start, stop, monitor, validate-all, promote, demote, notify, meta-data
649 |
650 |
651 |
652 |
653 |
654 | ## Pseudo code for "the script"
655 |
656 |
657 |
658 | ```
659 | // http://clusterlabs.org/doc/en-US/Pacemaker/1.1-pcs/html-single/Pacemaker_Explained/index.html#_multi_state_resource_agent_requirements
660 | if (monitor) {
661 | OCF_NOT_RUNNING = Stopped
662 | OCF_SUCCESS = Running (Slave)
663 | OCF_RUNNING_MASTER = Running (Master)
664 | OCF_FAILED-master = Failed (Master)
665 | Other = Failed (Slave)
666 | }
667 |
668 | var isRunningAsSlave = sqleval("localhost", "SELECT pg_is_in_recovery()");
669 | var isRunningAsMaster = ! isRunningAsSlave;
670 |
671 | if (stop && isRunningAsMaster) {
672 | // refuse new connections
673 | modify("pg_hba.conf", remove "all/all") && sqleval("localhost", "SELECT pg_reloadconf();");
674 |
675 | // drop existing connections
676 | sqleval("localhost", "SELECT pg_terminate_backend(pid) \
677 | FROM pg_stat_activity \
678 | WHERE usename='webfrontend';");
679 |
680 | // create checkoint
681 | sqleval("localhost", "CHECKPOINT;");
682 |
683 | // determine current location
684 | var flush_location = sqleval("localhost", "SELECT pg_current_xlog_location();");
685 |
686 | string diffStatement = "pg_xlog_location_diff(pg_current_xloc_location(), " + flush_location + ") from pg_stat_replication;"
687 | string determineReplicationLag = "SELECT client_addr, pg_current_xlog_location()," + diffStatement;
688 |
689 | bool allSlavesSynced = false;
690 | while (!allSlavesSynced) {
691 | bool foundUnsyncedSlave = false;
692 | var replicationStates = sqleval("localhost", determineReplicationLag);
693 | foreach (var replicationState in replicationStates) {
694 | (client,current,diff) = replicationState;
695 | if (diff > 0) {
696 | foundUnsyncedSlave = true;
697 | }
698 | }
699 | allSlavesSynced = !foundUnsyncedSlave;
700 | }
701 |
702 | shutdownPostgreSQL();
703 | // remove current node from master ILB
704 | configureInternalLoadBalancer("ilb_master", "remove `uname -n`");
705 |
706 | return 0; // machine can shut down
707 | }
708 |
709 |
710 | if (start && isMaster) {
711 | var isMaster = via CRM;
712 | if (isMaster) {
713 | // add current node to master ILB
714 | configureInternalLoadBalancer("ilb_master", "add `uname -n`");
715 | }
716 | }
717 |
718 | ```
719 |
720 |
721 | ```
722 | database-vm1 shutdown
723 | -> crm standby on (automatisch durch shutdown)
724 |
725 | database-vm2 MASTER (received clean shutdown from crm database-vm1)
726 | -> tecontrolpg.rb start MASTER
727 | -> rpmgr promote -> leave recovery mode, timeline switch happened
728 | -> add to internal MASTER LB and remove from SLAVE LB
729 | -> assure pg_hba.conf is accepting connections
730 | -> local test write query
731 |
732 | database-vm3 SLAVE
733 | -> follow new master (rpmgr standby follow)
734 | -> local test read query
735 | ```
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 | ## Determine whether you're on master or slave
746 |
747 | `SELECT pg_is_in_recovery()` returns `false` on the master (who is not in recovery), and `true` for slaves (who are in constant recovery mode).
748 |
749 | # Enable fiddler to sniff azure-cli
750 |
751 | http://blogs.msdn.com/b/avkashchauhan/archive/2013/01/30/using-fiddler-to-decipher-windows-azure-powershell-or-rest-api-https-traffic.aspx
752 |
753 | ```console
754 | SET HTTP_PROXY=http://127.0.0.1:8888/
755 | SET HTTPS_PROXY=http://127.0.0.1:8888/
756 | SET HTTPPROXY=http://127.0.0.1:8888/
757 | SET HTTPSPROXY=http://127.0.0.1:8888/
758 | SET NODE_TLS_REJECT_UNAUTHORIZED=0
759 | ```
760 |
761 | ## CustomRules.js
762 |
763 | ```javascript
764 | static function OnBeforeRequest(oSession: Session) {
765 | oSession["https-Client-Certificate"]= "C:\\Users\\chgeuer\\Desktop\\txxx.cer";
766 | ```
767 |
768 | # Questions:
769 |
770 | - For the block device driver for Azure Linux IaaS, what's supported or optimal? open_datasync, fdatasync (default on Linux), fsync, fsync_writethrough, open_sync. This is relevant to configure wal_sync_method
771 | - It seems that the guest OS does not see a detached data disk. An attached disk shows up in dmesg, while a detach process doesn't show up. When trying to open a formerly attached device (with cfdisk), the
772 |
773 | # Arbitrary Unix vodoo :-)
774 |
775 | ## See what's happening
776 |
777 | ```console
778 | watch dmesg \| tail -5
779 | ```
780 |
781 | # Next steps
782 |
783 | - Understand corosync model and how it should be used for the PostgreSQL cluster (Felix)
784 | - Extend the [OCF resource agent for pgsql](https://github.com/ClusterLabs/resource-agents/blob/master/heartbeat/pgsql) to support multiple slaves, because then the remaining slave needs to follow a new master. The current script only has one master and one slave. (Felix)
785 | - Scripting/API access to reconfiguring the internal load balancer (Christian)
786 |
787 |
788 |
789 | # References
790 |
791 | - Azure
792 | - [Azure - azure-cli / node.js command-line tool for Mac and Linux](http://azure.microsoft.com/en-us/documentation/articles/command-line-tools/)
793 | - [Azure - Exporting and Importing VM settings with the Azure Command-Line Tools](http://blogs.msdn.com/b/silverlining/archive/2012/10/25/exporting-and-importing-vm-settings-with-the-azure-command-line-tools.aspx)
794 | - [Azure - Create Virtual Machine Deployment REST API](http://msdn.microsoft.com/en-us/library/azure/jj157194.aspx)
795 | - [Azure - Linux and Graceful Shutdowns](http://azure.microsoft.com/blog/2014/05/06/linux-and-graceful-shutdowns-2/)
796 | - [Azure - Internal Load Balancing](http://azure.microsoft.com/blog/2014/05/20/internal-load-balancing/)
797 | - [Azure - Load balancing highly available Linux services: OpenLDAP and MySQL](http://channel9.msdn.com/Blogs/Open/Load-balancing-highly-available-Linux-services-on-Windows-Azure-OpenLDAP-and-MySQL)
798 | - [Using load-balanced sets to clusterize MySQL on Linux](http://azure.microsoft.com/en-us/documentation/articles/virtual-machines-linux-mysql-cluster/)
799 | - [Azure STONITH Provider on GitHub](https://github.com/bureado/aztonith/blob/master/azure-vm)
800 | - Pacemaker & Corosync
801 | - [An A-Z guide to Pacemaker's Configuration Options](http://clusterlabs.org/doc/en-US/Pacemaker/1.1-pcs/html-single/Pacemaker_Explained/index.html)
802 | - [Clusters from Scratch - Creating Active/Passive and Active/Active Clusters on Fedora](http://clusterlabs.org/doc/en-US/Pacemaker/1.1-pcs/html-single/Clusters_from_Scratch/index.html)
803 | - [corosync wiki](https://github.com/corosync/corosync/wiki)
804 | - [OCF resource agent for pgsql](https://github.com/ClusterLabs/resource-agents/blob/master/heartbeat/pgsql)
805 | - Ruby
806 | - [Ruby and PostgreSQL](https://bitbucket.org/ged/ruby-pg/wiki/Home)
807 | - [Ruby and Azure Service Bus](https://github.com/Azure/azure-content/blob/master/articles/service-bus-ruby-how-to-use-topics-subscriptions.md)
808 |
809 | [pacemaker-resource-multi-state]: http://clusterlabs.org/doc/en-US/Pacemaker/1.1-pcs/html-single/Pacemaker_Explained/index.html#s-resource-multistate
810 | [pacemaker-ocf-operations]: http://clusterlabs.org/doc/en-US/Pacemaker/1.1-pcs/html-single/Pacemaker_Explained/index.html#_actions
811 | [pacemaker-ocf-return-codes]: http://clusterlabs.org/doc/en-US/Pacemaker/1.1-pcs/html/Pacemaker_Explained/s-ocf-return-codes.html
812 | [stonith]: http://ourobengr.com/ha/
813 |
814 | # Acronyms
815 |
816 | ```
817 | OCF - open cluster framework (from Pacemaker)
818 | CRM - cluster resource manager (from Pacemaker)
819 | linbit - company who wrote
820 | ```
821 |
--------------------------------------------------------------------------------
/old/WP_20141105_004.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chgeuer/postgres-azure/5a5e7bfbac01d70c3f25c5b5e4db72a70366ea96/old/WP_20141105_004.jpg
--------------------------------------------------------------------------------
/old/loadbalancers_pg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chgeuer/postgres-azure/5a5e7bfbac01d70c3f25c5b5e4db72a70366ea96/old/loadbalancers_pg.png
--------------------------------------------------------------------------------
/old/machine.json:
--------------------------------------------------------------------------------
1 | {
2 | "RoleName": "database-vm",
3 | "RoleType": "PersistentVMRole",
4 | "RoleSize": "A5",
5 | "AvailabilitySetName" : "databases",
6 | "OSVirtualHardDisk": {
7 | "OS": "Linux",
8 | "HostCaching": "ReadWrite",
9 | "DiskName": "database-vm-disk",
10 | "DiskLabel": "database-vm-disk",
11 | "SourceImageName": "Debian-Wheezy-635506180993665396",
12 | "RemoteSourceImageLink": "http://account.blob.core.windows.net/vmdepot-images/TE-2014-11-03-debianwheezy-os-2014-11-03.vhd",
13 | "MediaLink" : "http://account.blob.core.windows.net/vmdepot-images/database-vm-disk.vhd"
14 | },
15 | "DataVirtualHardDisks" : [
16 | {"HostCaching": "ReadOnly", "DiskLabel": "database-vm-data1", "Lun": "0", "LogicalDiskSizeInGB": "1023", "MediaLink" : "http://account.blob.core.windows.net/vmdepot-images/database-vm-data1.vhd"},
17 | {"HostCaching": "ReadOnly", "DiskLabel": "database-vm-data2", "Lun": "1", "LogicalDiskSizeInGB": "1023", "MediaLink" : "http://account.blob.core.windows.net/vmdepot-images/database-vm-data2.vhd"},
18 | {"HostCaching": "ReadOnly", "DiskLabel": "database-vm-xlog1", "Lun": "2", "LogicalDiskSizeInGB": "1023", "MediaLink" : "http://account.blob.core.windows.net/vmdepot-images/database-vm-xlog1.vhd"}
19 | ],
20 | "ConfigurationSets": [
21 | {
22 | "ConfigurationSetType" : "LinuxProvisioningConfiguration",
23 | "HostName" : "database-vm",
24 | "UserName" : "ruth",
25 | "UserPassword" : "Supersecret123!!",
26 | "DisableSshPasswordAuthentication" : false
27 | },
28 | {
29 | "ConfigurationSetType": "NetworkConfiguration",
30 | "SubnetNames": [ "mysubnet" ],
31 | "InputEndpoints": [],
32 | "PublicIPs": [],
33 | "StoredCertificateSettings": []
34 | }
35 | ],
36 | "ProvisionGuestAgent": "true",
37 | "ResourceExtensionReferences": []
38 | }
39 |
--------------------------------------------------------------------------------
/old/postgresql-primer.md:
--------------------------------------------------------------------------------
1 |
2 | # PostgreSQL Primer
3 |
4 | - PostgreSQL developers are employed by a variety of companies, therefore the OSS dev team tries to re-use as much as possible
5 | - PostgreSQL is pretty robust. One customer hat 3-5 bluescreens per week, without data corruption
6 | - Two different data storages
7 | - General ledger == Write Ahead Log (WAL) records, "I will do the following", + fsync. Write caching is really bad here. Pure sequential writes. This must be written before a commit can be done.
8 | - Dann noch die eigentlichen DB files
9 | - Wenn die Tables nicht in Sync mit dem WAL record ist, wird postgres in den recovery modus gesetzt.
10 | - WAL records können auf andere Systeme kopiert werden (in 16MB chunks), WAL shipping, z.B.
11 | - für einen nachlaufenden Slave
12 | - Point in time recovery
13 | - Backup
14 | - Anderen Storage (S3, Glacier)
15 | - WAL records (binäre diffs) haben immer 16MB; können aber schon verschickt werden, wenn die 16MB noch nicht voll sind. (PGX log verzeichnis), rufen eine Shell auf, die irgendwas macht (archive command)
16 | - Seit 9.0 können WAL records auch per "streaming replication" versendet werden (bytes an einen TCP Port senden)
17 | - Wenn man "streaming replication" oder "WAL shipping" auf einen secondary server machen, ist der gewissermaßen immer im Recovery Modus. Auch wenn der Server im "Recovery Modus" ist, kann man lese-Queries dagegen schicken
18 | - 9.0 mach async streaming machen
19 | - 9.1 kann synchronous streaming replication erzwingen (garantiert auf mindestens einem Streaming Slave). Dieser Slave ist immer der erste in der Liste der Slaves.
20 | - "Synchronous streaming replicatoin" kann man auch für einzelne Transaktionen einschalten, also z.B. nur für wichtige Writes.
21 | - Trigger-basierte replication ("Slony" und "Londiste" sind trigger-based replication implementations). Slony (fragile C Code Base), Londiste (Python) . Diesen Trigger (on-update / on-insert) setzt man auf eine Datenbank. Londiste kommt von Skype. Londiste schreibt Änderungen in eine Queue in Postgres (Listen&Notify) rein.
22 | - Londiste nutzt man für "cross-version upgrade",
23 | - Trigger-based replication kann Probleme bei Schema-Updates erzeugen
24 | - Jedes Byte, welches in einer Tabelle geschrieben wird, sind mindestens 2 Bytes Festplatten-I/O
25 | - Ab 9.4 gibt es "Logical decoding", welches aus einem WAL Record rekonstruieren kann, was auf Anwendungsebene wohl passiert ist (menschenlesbar)
26 | - Logical Decoding used for multi-master replication (bi-directional replication sync hin- und her)
27 | - Problem ist in geo-verteilten Datacentern mit high latency. US-Datenbank für US-Kunden, EU-Datenbank für EU Kunden, und mit bi-directional replication alle Daten überall, die Daten der Kollegen halt etwas später (5 mins)
28 | - Streaming Replication ermöglicht "Read Scaling", also schreiben auf eine einzelne DB, und aus mehreren Read-Slaves rauslesen. Man kann in einem View schauen, wie weit der Slave hinterher ist.
29 | - Die Read-Slaves können zum Master promoted werden, wird von Read-Only zu Read-Write. Mit PGBouncer und DNS die Clients umbiegen. Wenn der Master wieder hochkommt, wird per RSYNC die letzten Änderungen vom neuen Master auf den wieder hochkommenden alten Master repliziert. (rep manager http://www.repmgr.org / https://github.com/2ndQuadrant/repmgr)
30 | - PostgreSQL forked bei neuen Verbindungen. pgBouncer ist ein Service, der Connection-Pooling für mis-behaving clients anbietet. pgBouncer authentifiziert Clients.
31 |
32 |
--------------------------------------------------------------------------------
/old/presentation.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chgeuer/postgres-azure/5a5e7bfbac01d70c3f25c5b5e4db72a70366ea96/old/presentation.pptx
--------------------------------------------------------------------------------
/postgresHAinExistingSubnet.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "environment": {
6 | "type": "string",
7 | "allowedValues": [
8 | "Azure Cloud",
9 | "Azure German Cloud"
10 | ],
11 | "defaultValue": "Azure Cloud"
12 | },
13 | "vNetRessourceGroup": {
14 | "type": "string"
15 | },
16 | "vNetName": {
17 | "type": "string"
18 | },
19 | "vNetSubnetName": {
20 | "type": "string"
21 | },
22 | "vNetSubnetPrefix": {
23 | "type": "string",
24 | "defaultValue": "10.0.1."
25 | },
26 | "vNetSubnetStartIP": {
27 | "type": "int",
28 | "defaultValue": 10
29 | },
30 | "clusterName": {
31 | "type": "string"
32 | },
33 | "instanceCount": {
34 | "defaultValue": 2,
35 | "minValue": 2,
36 | "maxValue": 250,
37 | "type": "int",
38 | "metadata": {
39 | "description": "Number of postgreSQL servers in the cluster."
40 | }
41 | },
42 | "instanceSize": {
43 | "type": "string",
44 | "allowedValues": [
45 | "Standard_DS1",
46 | "Standard_DS2",
47 | "Standard_DS3",
48 | "Standard_DS4",
49 | "Standard_DS11",
50 | "Standard_DS12",
51 | "Standard_DS13",
52 | "Standard_DS14",
53 | "Standard_GS1",
54 | "Standard_GS2",
55 | "Standard_GS3",
56 | "Standard_GS4",
57 | "Standard_GS5",
58 | "Standard_DS1_v2",
59 | "Standard_DS2_v2",
60 | "Standard_DS3_v2",
61 | "Standard_DS4_v2",
62 | "Standard_DS5_v2",
63 | "Standard_DS11_v2",
64 | "Standard_DS12_v2",
65 | "Standard_DS13_v2",
66 | "Standard_DS14_v2",
67 | "Standard_DS15_v2"
68 | ],
69 | "defaultValue": "Standard_DS2_v2",
70 | "metadata": {
71 | "description": "Size of the postgreSQL server in the cluster."
72 | }
73 | },
74 | "dataDiskSizeInGB": {
75 | "type": "int",
76 | "defaultValue": 128,
77 | "allowedValues": [
78 | 128,
79 | 512,
80 | 1024
81 | ],
82 | "metadata": {
83 | "description": "Defines the size of each data disk (premium storage sizes)"
84 | }
85 | },
86 | "dataDiscCount": {
87 | "type": "string",
88 | "defaultValue": "4",
89 | "allowedValues": [
90 | "0",
91 | "1",
92 | "2",
93 | "3",
94 | "4",
95 | "5",
96 | "6",
97 | "7",
98 | "8",
99 | "9",
100 | "10",
101 | "11",
102 | "12",
103 | "13",
104 | "14",
105 | "15",
106 | "16"
107 | ],
108 | "metadata": {
109 | "description": "This parameter allows the user to select the number of disks wanted"
110 | }
111 | },
112 | "adminUsername": {
113 | "type": "string"
114 | },
115 | "adminPassword": {
116 | "type": "securestring"
117 | }
118 | },
119 | "variables": {
120 | "selectedEnvironmentIndex": "[int(replace(replace(parameters('environment'), 'Azure Cloud', '0'), 'Azure German Cloud', '1'))]",
121 | "storageEndpoints": [
122 | "core.windows.net",
123 | "core.cloudapi.de"
124 | ],
125 | "storageEndpoint": "[variables('storageEndpoints')[variables('selectedEnvironmentIndex')]]",
126 | "lbName": "postgresLoadBalancer",
127 | "lbId": "[resourceId('Microsoft.Network/loadBalancers/', variables('lbName'))]",
128 | "vnetName": "[parameters('vNetName')]",
129 | "vnetId": "[resourceId(parameters('vNetRessourceGroup'), 'Microsoft.Network/virtualNetworks', variables('vnetName'))]",
130 | "zookeeperNetName": "[parameters('vNetSubnetName')]",
131 | "zookeeperNetPrefix": "[parameters('vNetSubnetPrefix')]",
132 | "zookeeperNetStartIP": "[parameters('vNetSubnetStartIP')]",
133 | "zookeeperInstanceCount": 3,
134 | "postgresNetName": "[parameters('vNetSubnetName')]",
135 | "postgresNetPrefix": "[parameters('vNetSubnetPrefix')]",
136 | "postgresNetStartIP": "[add(parameters('vNetSubnetStartIP'), variables('zookeeperInstanceCount'))]",
137 | "postgresInstanceCount": "[parameters('instanceCount')]",
138 | "osType": {
139 | "publisher": "Canonical",
140 | "offer": "UbuntuServer",
141 | "sku": "14.04.4-LTS",
142 | "version": "latest"
143 | },
144 | "diskCaching": "ReadOnly",
145 | "fileroot": "https://.../public/postgresha/"
146 | },
147 | "resources": [
148 | {
149 | "type": "Microsoft.Storage/storageAccounts",
150 | "name": "[concat(copyIndex(), 'zk', parameters('clusterName'))]",
151 | "apiVersion": "2015-06-15",
152 | "location": "[resourceGroup().location]",
153 | "copy": {
154 | "name": "zookeeperStorageLoop",
155 | "count": "[variables('zookeeperInstanceCount')]"
156 | },
157 | "properties": {
158 | "accountType": "Standard_LRS"
159 | }
160 | },
161 | {
162 | "type": "Microsoft.Storage/storageAccounts",
163 | "name": "[concat(copyIndex(), 'pg', parameters('clusterName'))]",
164 | "apiVersion": "2015-06-15",
165 | "location": "[resourceGroup().location]",
166 | "copy": {
167 | "name": "postgresStorageLoop",
168 | "count": "[variables('postgresInstanceCount')]"
169 | },
170 | "properties": {
171 | "accountType": "Premium_LRS"
172 | }
173 | },
174 | {
175 | "type": "Microsoft.Compute/availabilitySets",
176 | "name": "postgresAvailabilitySet",
177 | "apiVersion": "2015-05-01-preview",
178 | "location": "[resourceGroup().location]",
179 | "properties": {
180 | "platformFaultDomainCount": 3,
181 | "platformUpdateDomainCount": 3
182 | }
183 | },
184 | {
185 | "type": "Microsoft.Compute/availabilitySets",
186 | "name": "zookeeperAvailabilitySet",
187 | "apiVersion": "2015-05-01-preview",
188 | "location": "[resourceGroup().location]",
189 | "properties": {
190 | "platformFaultDomainCount": 3,
191 | "platformUpdateDomainCount" : 3
192 | }
193 | },
194 | {
195 | "type": "Microsoft.Network/networkInterfaces",
196 | "name": "[concat('zookeeper', copyIndex(), '-nic')]",
197 | "dependsOn": [
198 | "[variables('lbId')]"
199 | ],
200 | "apiVersion": "2015-05-01-preview",
201 | "location": "[resourceGroup().location]",
202 | "copy": {
203 | "name": "zookeeperNicLoop",
204 | "count": "[variables('zookeeperInstanceCount')]"
205 | },
206 | "properties": {
207 | "ipConfigurations": [
208 | {
209 | "name": "zookeeperIp",
210 | "properties": {
211 | "privateIPAllocationMethod": "Static",
212 | "privateIPAddress": "[concat(variables('zookeeperNetPrefix'), add(variables('zookeeperNetStartIP'), copyIndex()))]",
213 | "subnet": {
214 | "id": "[concat(variables('vnetId'), '/subnets/', variables('zookeeperNetName'))]"
215 | }
216 | }
217 | }
218 | ]
219 | }
220 | },
221 | {
222 | "type": "Microsoft.Compute/virtualMachines",
223 | "name": "[concat('zookeeper', copyIndex())]",
224 | "apiVersion": "2015-05-01-preview",
225 | "location": "[resourceGroup().location]",
226 | "copy": {
227 | "name": "zookeeperVmLoop",
228 | "count": "[variables('zookeeperInstanceCount')]"
229 | },
230 | "properties": {
231 | "availabilitySet": {
232 | "id": "[resourceId('Microsoft.Compute/availabilitySets', 'zookeeperAvailabilitySet')]"
233 | },
234 | "hardwareProfile": {
235 | "vmSize": "Standard_A0"
236 | },
237 | "osProfile": {
238 | "computerName": "[concat('zookeeper', copyIndex())]",
239 | "adminUsername": "[parameters('adminUserName')]",
240 | "adminPassword": "[parameters('adminPassword')]"
241 | },
242 | "storageProfile": {
243 | "imageReference": {
244 | "publisher": "Canonical",
245 | "offer": "UbuntuServer",
246 | "sku": "14.04.4-LTS",
247 | "version": "latest"
248 | },
249 | "osDisk": {
250 | "name": "osdisk",
251 | "vhd": {
252 | "uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', copyIndex(), 'zk', parameters('clusterName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).primaryEndpoints.blob, 'vhds/', 'zookeeperosdisk', copyIndex(), '.vhd')]"
253 | },
254 | "caching": "ReadWrite",
255 | "createOption": "FromImage"
256 | }
257 | },
258 | "networkProfile": {
259 | "networkInterfaces": [
260 | {
261 | "id": "[resourceId('Microsoft.Network/networkInterfaces', concat('zookeeper', copyIndex(), '-nic'))]"
262 | }
263 | ]
264 | }
265 | },
266 | "dependsOn": [
267 | "zookeeperStorageLoop",
268 | "[concat('Microsoft.Storage/storageAccounts/', copyIndex(), 'zk', parameters('clusterName'))]",
269 | "[concat('Microsoft.Network/networkInterfaces/', 'zookeeper', copyIndex(), '-nic')]",
270 | "[concat('Microsoft.Compute/availabilitySets/', 'zookeeperAvailabilitySet')]"
271 | ]
272 | },
273 | {
274 | "type": "Microsoft.Compute/virtualMachines/extensions",
275 | "name": "[concat('zookeeper', copyIndex(), '/zookeeperExtension')]",
276 | "apiVersion": "2015-05-01-preview",
277 | "location": "[resourceGroup().location]",
278 | "copy": {
279 | "name": "zookeeperExtLoop",
280 | "count": "[variables('zookeeperInstanceCount')]"
281 | },
282 | "properties": {
283 | "publisher": "Microsoft.OSTCExtensions",
284 | "type": "CustomScriptForLinux",
285 | "typeHandlerVersion": "1.2",
286 | "settings": {
287 | "fileUris": [
288 | "[concat(variables('fileroot'), 'start-zk.sh')]"
289 | ],
290 | "commandToExecute": "[concat('./start-zk.sh ', copyIndex(), ' ', variables('zookeeperInstanceCount'), ' ', variables('zookeeperNetPrefix'), variables('zookeeperNetStartIP'))]"
291 | }
292 | },
293 | "dependsOn": [
294 | "[concat('Microsoft.Compute/virtualMachines/', 'zookeeper', copyIndex())]"
295 | ]
296 | },
297 | {
298 | "type": "Microsoft.Network/networkInterfaces",
299 | "name": "[concat('postgres', copyIndex(), '-nic')]",
300 | "apiVersion": "2015-05-01-preview",
301 | "location": "[resourceGroup().location]",
302 | "copy": {
303 | "name": "postgresNicLoop",
304 | "count": "[variables('postgresInstanceCount')]"
305 | },
306 | "properties": {
307 | "ipConfigurations": [
308 | {
309 | "name": "postgresIp",
310 | "properties": {
311 | "privateIPAllocationMethod": "Static",
312 | "privateIPAddress": "[concat(variables('postgresNetPrefix'), add(variables('postgresNetStartIP'), copyIndex()))]",
313 | "subnet": {
314 | "id": "[concat(variables('vnetId'), '/subnets/', variables('postgresNetName'))]"
315 | },
316 | "loadBalancerBackendAddressPools": [
317 | {
318 | "id": "[concat(variables('lbId'), '/backendAddressPools/loadBalancerBackEnd')]"
319 | }
320 | ]
321 | }
322 | }
323 | ]
324 | },
325 | "dependsOn": [
326 | "[variables('lbId')]"
327 | ]
328 | },
329 | {
330 | "apiVersion": "2015-01-01",
331 | "name": "[concat('postgresDataDisksConfigForVM', copyIndex())]",
332 | "type": "Microsoft.Resources/deployments",
333 | "copy": {
334 | "name": "postgresDataDisksConfigLoop",
335 | "count": "[variables('postgresInstanceCount')]"
336 | },
337 | "properties": {
338 | "mode": "Incremental",
339 | "templateLink": {
340 | "uri": "[concat(variables('fileroot'), 'disksSelector.json')]",
341 | "contentVersion": "1.0.0.0"
342 | },
343 | "parameters": {
344 | "numDataDisks": {
345 | "value": "[parameters('dataDiscCount')]"
346 | },
347 | "diskStorageAccountName": {
348 | "value": "[concat(copyIndex(), 'pg', parameters('clusterName'))]"
349 | },
350 | "diskCaching": {
351 | "value": "[variables('diskCaching')]"
352 | },
353 | "diskSizeGB": {
354 | "value": "[parameters('dataDiskSizeInGB')]"
355 | },
356 | "storageUrlSuffix": {
357 | "value": "[variables('storageEndpoint')]"
358 | }
359 | }
360 | }
361 | },
362 | {
363 | "type": "Microsoft.Compute/virtualMachines",
364 | "name": "[concat('postgres', copyIndex())]",
365 | "apiVersion": "2015-05-01-preview",
366 | "location": "[resourceGroup().location]",
367 | "copy": {
368 | "name": "postgresVmLoop",
369 | "count": "[variables('postgresInstanceCount')]"
370 | },
371 | "properties": {
372 | "availabilitySet": {
373 | "id": "[resourceId('Microsoft.Compute/availabilitySets', 'postgresAvailabilitySet')]"
374 | },
375 | "hardwareProfile": {
376 | "vmSize": "[parameters('instanceSize')]"
377 | },
378 | "osProfile": {
379 | "computerName": "[concat('postgres', copyIndex())]",
380 | "adminUsername": "[parameters('adminUserName')]",
381 | "adminPassword": "[parameters('adminPassword')]"
382 | },
383 | "storageProfile": {
384 | "imageReference": {
385 | "publisher": "Canonical",
386 | "offer": "UbuntuServer",
387 | "sku": "14.04.4-LTS",
388 | "version": "latest"
389 | },
390 | "osDisk": {
391 | "name": "osdisk",
392 | "vhd": {
393 | "uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', copyIndex(), 'pg', parameters('clusterName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).primaryEndpoints.blob, 'vhds/', 'postgresosdisk', copyIndex(), '.vhd')]"
394 | },
395 | "caching": "ReadWrite",
396 | "createOption": "FromImage"
397 | },
398 | "dataDisks": "[reference(concat('postgresDataDisksConfigForVM', copyIndex())).outputs.dataDiskArray.value]"
399 | },
400 | "networkProfile": {
401 | "networkInterfaces": [
402 | {
403 | "id": "[resourceId('Microsoft.Network/networkInterfaces', concat('postgres', copyIndex(), '-nic'))]"
404 | }
405 | ]
406 | }
407 | },
408 | "dependsOn": [
409 | "postgresStorageLoop",
410 | "zookeeperVmLoop",
411 | "zookeeperExtLoop",
412 | "postgresDataDisksConfigLoop",
413 | "[concat('Microsoft.Storage/storageAccounts/', copyIndex(), 'pg', parameters('clusterName'))]",
414 | "[concat('Microsoft.Network/networkInterfaces/', 'postgres', copyIndex(), '-nic')]",
415 | "[concat('Microsoft.Compute/availabilitySets/', 'postgresAvailabilitySet')]"
416 | ]
417 | },
418 | {
419 | "type": "Microsoft.Compute/virtualMachines/extensions",
420 | "name": "[concat('postgres', copyIndex(), '/postgresExtension')]",
421 | "apiVersion": "2015-05-01-preview",
422 | "location": "[resourceGroup().location]",
423 | "copy": {
424 | "name": "postgresExtLoop",
425 | "count": "[variables('postgresInstanceCount')]"
426 | },
427 | "properties": {
428 | "publisher": "Microsoft.OSTCExtensions",
429 | "type": "CustomScriptForLinux",
430 | "typeHandlerVersion": "1.2",
431 | "settings": {
432 | "fileUris": [
433 | "[concat(variables('fileroot'), 'ebs_raid0.sh')]",
434 | "[concat(variables('fileroot'), 'postgres_startup_existing_net.sh')]"
435 | ],
436 | "commandToExecute": "[concat('./postgres_startup_existing_net.sh ', parameters('clusterName'), ' ', variables('zookeeperNetPrefix'), variables('zookeeperNetStartIP'), ' ', variables('zookeeperInstanceCount'), ' ', variables('postgresNetPrefix'), variables('postgresNetStartIP'), ' ', variables('postgresInstanceCount'), ' ', copyIndex(), ' ', parameters('adminUsername'), ' \"', parameters('adminPassword'), '\" ')]"
437 | }
438 | },
439 | "dependsOn": [
440 | "[concat('Microsoft.Compute/virtualMachines/', 'postgres', copyIndex())]"
441 | ]
442 | },
443 | {
444 | "type": "Microsoft.Network/loadBalancers",
445 | "name": "[variables('lbName')]",
446 | "apiVersion": "2015-06-15",
447 | "location": "[resourceGroup().location]",
448 | "properties": {
449 | "availabilitySet": {
450 | "id": "[resourceId('Microsoft.Compute/availabilitySets', 'postgresHaAvailabilitySet')]"
451 | },
452 | "frontendIPConfigurations": [
453 | {
454 | "name": "loadBalancerFrontEnd",
455 | "properties": {
456 | "privateIPAllocationMethod": "Static",
457 | "privateIPAddress": "[concat(variables('postgresNetPrefix'), add(variables('postgresNetStartIP'), variables('postgresInstanceCount')))]",
458 | "subnet": {
459 | "id": "[concat(variables('vnetId'), '/subnets/', variables('postgresNetName'))]"
460 | }
461 |
462 | }
463 | }
464 | ],
465 | "backendAddressPools": [
466 | {
467 | "name": "loadBalancerBackEnd"
468 | }
469 | ],
470 | "loadBalancingRules": [
471 | {
472 | "name": "postgresLbRule",
473 | "properties": {
474 | "frontendIPConfiguration": {
475 | "id": "[concat(variables('lbId'), '/frontendIPConfigurations/loadBalancerFrontEnd')]"
476 | },
477 | "backendAddressPool": {
478 | "id": "[concat(variables('lbId'), '/backendAddressPools/loadBalancerBackEnd')]"
479 | },
480 | "protocol": "Tcp",
481 | "frontendPort": 5432,
482 | "backendPort": 5000,
483 | "probe": {
484 | "id": "[concat(variables('lbId'), '/probes/postgresProbe')]"
485 | }
486 | }
487 | }
488 | ],
489 | "probes": [
490 | {
491 | "name": "postgresProbe",
492 | "properties": {
493 | "protocol": "Tcp",
494 | "port": 5000,
495 | "intervalInSeconds": 5,
496 | "numberOfProbes": 2
497 | }
498 | }
499 | ]
500 | },
501 | "dependsOn": []
502 | }
503 | ],
504 | "outputs":
505 | {
506 | "postgresLoadBalancerIpAddress": {
507 | "type": "string",
508 | "value": "[reference(variables('lbName')).frontendIPConfigurations[0].properties.privateIPAddress]"
509 | },
510 | "port": {
511 | "type": "int",
512 | "value": 5432
513 | },
514 | "postgresUser": {
515 | "type": "string",
516 | "value": "admin"
517 | },
518 | "postgresUserPassword": {
519 | "type": "securestring",
520 | "value": "[parameters('adminPassword')]"
521 | }
522 | }
523 | }
--------------------------------------------------------------------------------
/postgresHAinExistingSubnet.parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "environment": {
6 | "value": "Azure German Cloud"
7 | },
8 | "clusterName": {
9 | "value": "tani0"
10 | },
11 | "adminUsername": {
12 | "value": "director"
13 | },
14 | "adminPassword": {
15 | "value": "Start1234!!!"
16 | },
17 | "vNetName": {
18 | "value": "postgresHAnet"
19 | },
20 | "vNetSubnetName": {
21 | "value": "default"
22 | },
23 | "vNetSubnetPrefix": {
24 | "value": "10.1.0."
25 | },
26 | "vNetRessourceGroup": {
27 | "value": "postgresHAnet"
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/postgresHAstandalone.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "environment": {
6 | "type": "string",
7 | "allowedValues": [
8 | "Azure Cloud",
9 | "Azure German Cloud"
10 | ],
11 | "defaultValue": "Azure Cloud"
12 | },
13 | "clusterName": {
14 | "type": "string"
15 | },
16 | "postgresqlInstanceCount": {
17 | "defaultValue": 2,
18 | "minValue": 2,
19 | "maxValue": 10,
20 | "type": "int",
21 | "metadata": { "description": "Number of postgreSQL servers in the cluster." }
22 | },
23 | "instanceSize": {
24 | "type": "string",
25 | "allowedValues": [
26 | "Standard_DS1", "Standard_DS2", "Standard_DS3", "Standard_DS4",
27 | "Standard_DS11", "Standard_DS12", "Standard_DS13", "Standard_DS14",
28 | "Standard_GS1", "Standard_GS2", "Standard_GS3", "Standard_GS4", "Standard_GS5",
29 | "Standard_DS1_v2", "Standard_DS2_v2", "Standard_DS3_v2", "Standard_DS4_v2", "Standard_DS5_v2",
30 | "Standard_DS11_v2", "Standard_DS12_v2", "Standard_DS13_v2", "Standard_DS14_v2", "Standard_DS15_v2"
31 | ],
32 | "defaultValue": "Standard_DS2_v2",
33 | "metadata": {
34 | "description": "Size of the postgreSQL server in the cluster."
35 | }
36 | },
37 | "dataDiskSizeInGB": {
38 | "type": "int",
39 | "defaultValue": 128,
40 | "allowedValues": [
41 | 128,
42 | 512,
43 | 1024
44 | ],
45 | "metadata": {
46 | "description": "Defines the size of each data disk (premium storage sizes)"
47 | }
48 | },
49 | "dataDiscCount": {
50 | "type": "string",
51 | "defaultValue": "4",
52 | "allowedValues": [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16" ],
53 | "metadata": {
54 | "description": "This parameter allows the user to select the number of disks wanted"
55 | }
56 | },
57 | "adminUsername": {
58 | "type": "string"
59 | },
60 | "adminPassword": {
61 | "type": "securestring"
62 | }
63 | },
64 | "variables": {
65 | "selectedEnvironmentIndex": "[int(replace(replace(parameters('environment'), 'Azure Cloud', '0'), 'Azure German Cloud', '1'))]",
66 | "storageEndpoints": [
67 | "core.windows.net",
68 | "core.cloudapi.de"
69 | ],
70 | "storageEndpoint": "[variables('storageEndpoints')[variables('selectedEnvironmentIndex')]]",
71 | "ipName": "[concat(parameters('clusterName'), '-ip')]",
72 | "ipId": "[resourceId('Microsoft.Network/publicIPAddresses/', variables('ipName'))]",
73 | "lbName": "postgresLoadBalancer",
74 | "lbId": "[resourceId('Microsoft.Network/loadBalancers/', variables('lbName'))]",
75 | "vnetName": "[concat(parameters('clusterName'), '-net')]",
76 | "vnetId": "[resourceId('Microsoft.Network/virtualNetworks', variables('vnetName'))]",
77 | "zookeeperNetName": "zookeeper-subnet",
78 | "zookeeperNetPrefix": "10.0.100.",
79 | "zookeeperNetStartIP": 10,
80 | "zookeeperInstanceCount": 3,
81 | "postgresNetName": "postgres-subnet",
82 | "postgresNetPrefix": "10.0.101.",
83 | "postgresNetStartIP": 10,
84 | "postgresInstanceCount": "[parameters('instanceCount')]",
85 | "osType": {
86 | "publisher": "Canonical",
87 | "offer": "UbuntuServer",
88 | "sku": "14.04.4-LTS",
89 | "version": "latest"
90 | },
91 | "diskCaching": "ReadOnly",
92 | "fileroot": "https://raw.githubusercontent.com/chgeuer/postgres-azure/master/scripts/"
93 | },
94 | "resources": [
95 | {
96 | "type": "Microsoft.Network/virtualNetworks",
97 | "name": "[variables('vnetName')]",
98 | "apiVersion": "2015-06-15",
99 | "location": "[resourceGroup().location]",
100 | "tags": { },
101 | "properties": {
102 | "addressSpace": {
103 | "addressPrefixes": [
104 | "10.0.0.0/16"
105 | ]
106 | },
107 | "subnets": [
108 | {
109 | "name": "[variables('zookeeperNetName')]",
110 | "properties": {
111 | "addressPrefix": "[concat(variables('zookeeperNetPrefix'), '0/24')]"
112 | }
113 | },
114 | {
115 | "name": "[variables('postgresNetName')]",
116 | "properties": {
117 | "addressPrefix": "[concat(variables('postgresNetPrefix'), '0/24')]"
118 | }
119 | }
120 | ]
121 | },
122 | "dependsOn": [ ]
123 | },
124 | {
125 | "type": "Microsoft.Storage/storageAccounts",
126 | "name": "[concat(copyIndex(), 'zk', parameters('clusterName'))]",
127 | "apiVersion": "2015-06-15",
128 | "location": "[resourceGroup().location]",
129 | "copy": {
130 | "name": "zookeeperStorageLoop",
131 | "count": "[variables('zookeeperInstanceCount')]"
132 | },
133 | "properties": {
134 | "accountType": "Standard_LRS"
135 | }
136 | },
137 | {
138 | "type": "Microsoft.Storage/storageAccounts",
139 | "name": "[concat(copyIndex(), 'pg', parameters('clusterName'))]",
140 | "apiVersion": "2015-06-15",
141 | "location": "[resourceGroup().location]",
142 | "copy": {
143 | "name": "postgresStorageLoop",
144 | "count": "[variables('postgresInstanceCount')]"
145 | },
146 | "properties": {
147 | "accountType": "Premium_LRS"
148 | }
149 | },
150 | {
151 | "type": "Microsoft.Network/publicIPAddresses",
152 | "name": "[variables('ipName')]",
153 | "apiVersion": "2016-03-30",
154 | "location": "[resourceGroup().location]",
155 | "properties": {
156 | "publicIPAllocationMethod": "Dynamic",
157 | "dnsSettings": {
158 | "domainNameLabel": "[parameters('clusterName')]"
159 | }
160 | }
161 | },
162 | {
163 | "type": "Microsoft.Compute/availabilitySets",
164 | "name": "postgresAvailabilitySet",
165 | "apiVersion": "2015-05-01-preview",
166 | "location": "[resourceGroup().location]",
167 | "properties": {
168 | "platformFaultDomainCount": 3,
169 | "platformUpdateDomainCount": 3
170 | }
171 | },
172 | {
173 | "type": "Microsoft.Compute/availabilitySets",
174 | "name": "zookeeperAvailabilitySet",
175 | "apiVersion": "2015-05-01-preview",
176 | "location": "[resourceGroup().location]",
177 | "properties": { }
178 | },
179 | {
180 | "type": "Microsoft.Network/networkInterfaces",
181 | "name": "[concat('zookeeper', copyIndex(), '-nic')]",
182 | "apiVersion": "2015-05-01-preview",
183 | "location": "[resourceGroup().location]",
184 | "copy": {
185 | "name": "zookeeperNicLoop",
186 | "count": "[variables('zookeeperInstanceCount')]"
187 | },
188 | "properties": {
189 | "ipConfigurations": [
190 | {
191 | "name": "zookeeperIp",
192 | "properties": {
193 | "privateIPAllocationMethod": "Static",
194 | "privateIPAddress": "[concat(variables('zookeeperNetPrefix'), add(variables('zookeeperNetStartIP'), copyIndex()))]",
195 | "subnet": {
196 | "id": "[concat(variables('vnetId'), '/subnets/', variables('zookeeperNetName'))]"
197 | }
198 | }
199 | }
200 | ]
201 | },
202 | "dependsOn": [
203 | "[variables('lbId')]"
204 | ]
205 | },
206 | {
207 | "type": "Microsoft.Compute/virtualMachines",
208 | "name": "[concat('zookeeper', copyIndex())]",
209 | "apiVersion": "2015-05-01-preview",
210 | "location": "[resourceGroup().location]",
211 | "copy": {
212 | "name": "zookeeperVmLoop",
213 | "count": "[variables('zookeeperInstanceCount')]"
214 | },
215 | "properties": {
216 | "availabilitySet": {
217 | "id": "[resourceId('Microsoft.Compute/availabilitySets', 'zookeeperAvailabilitySet')]"
218 | },
219 | "hardwareProfile": {
220 | "vmSize": "Standard_A0"
221 | },
222 | "osProfile": {
223 | "computerName": "[concat('zookeeper', copyIndex())]",
224 | "adminUsername": "[parameters('adminUserName')]",
225 | "adminPassword": "[parameters('adminPassword')]"
226 | },
227 | "storageProfile": {
228 | "imageReference": {
229 | "publisher": "Canonical",
230 | "offer": "UbuntuServer",
231 | "sku": "14.04.4-LTS",
232 | "version": "latest"
233 | },
234 | "osDisk": {
235 | "name": "osdisk",
236 | "vhd": {
237 | "uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', copyIndex(), 'zk', parameters('clusterName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).primaryEndpoints.blob, 'vhds/', 'zookeeperosdisk', copyIndex(), '.vhd')]"
238 | },
239 | "caching": "ReadWrite",
240 | "createOption": "FromImage"
241 | }
242 | },
243 | "networkProfile": {
244 | "networkInterfaces": [
245 | {
246 | "id": "[resourceId('Microsoft.Network/networkInterfaces', concat('zookeeper', copyIndex(), '-nic'))]"
247 | }
248 | ]
249 | }
250 | },
251 | "dependsOn": [
252 | "zookeeperStorageLoop",
253 | "[concat('Microsoft.Storage/storageAccounts/', copyIndex(), 'zk', parameters('clusterName'))]",
254 | "[concat('Microsoft.Network/networkInterfaces/', 'zookeeper', copyIndex(), '-nic')]",
255 | "[concat('Microsoft.Compute/availabilitySets/', 'zookeeperAvailabilitySet')]"
256 | ]
257 | },
258 | {
259 | "type": "Microsoft.Compute/virtualMachines/extensions",
260 | "name": "[concat('zookeeper', copyIndex(), '/zookeeperExtension')]",
261 | "apiVersion": "2015-05-01-preview",
262 | "location": "[resourceGroup().location]",
263 | "dependsOn": [
264 | "[concat('Microsoft.Compute/virtualMachines/', 'zookeeper', copyIndex())]"
265 | ],
266 | "copy": {
267 | "name": "zookeeperExtLoop",
268 | "count": "[variables('zookeeperInstanceCount')]"
269 | },
270 | "properties": {
271 | "publisher": "Microsoft.OSTCExtensions",
272 | "type": "CustomScriptForLinux",
273 | "typeHandlerVersion": "1.2",
274 | "settings": {
275 | "fileUris": [
276 | "[concat(variables('fileroot'), 'start-zk.sh')]"
277 | ],
278 | "commandToExecute": "[concat('./start-zk.sh ', copyIndex(), ' ', variables('zookeeperInstanceCount'), ' ', variables('zookeeperNetPrefix'), variables('zookeeperNetStartIP'))]"
279 | }
280 | }
281 | },
282 | {
283 | "type": "Microsoft.Network/networkInterfaces",
284 | "name": "[concat('postgres', copyIndex(), '-nic')]",
285 | "apiVersion": "2015-05-01-preview",
286 | "location": "[resourceGroup().location]",
287 | "copy": {
288 | "name": "postgresNicLoop",
289 | "count": "[variables('postgresInstanceCount')]"
290 | },
291 | "properties": {
292 | "ipConfigurations": [
293 | {
294 | "name": "postgresIp",
295 | "properties": {
296 | "privateIPAllocationMethod": "Static",
297 | "privateIPAddress": "[concat(variables('postgresNetPrefix'), add(variables('postgresNetStartIP'), copyIndex()))]",
298 | "subnet": {
299 | "id": "[concat(variables('vnetId'), '/subnets/', variables('postgresNetName'))]"
300 | },
301 | "loadBalancerBackendAddressPools": [
302 | {
303 | "id": "[concat(variables('lbId'), '/backendAddressPools/loadBalancerBackEnd')]"
304 | }
305 | ],
306 | "loadBalancerInboundNatRules": [
307 | {
308 | "id": "[concat(variables('lbId'), '/inboundNatRules/postgresSsh', copyIndex())]"
309 | }
310 | ]
311 | }
312 | }
313 | ]
314 | },
315 | "dependsOn": [
316 | "[variables('lbId')]"
317 | ]
318 | },
319 | {
320 | "apiVersion": "2015-01-01",
321 | "name": "[concat('postgresDataDisksConfigForVM', copyIndex())]",
322 | "type": "Microsoft.Resources/deployments",
323 | "copy": {
324 | "name": "postgresDataDisksConfigLoop",
325 | "count": "[variables('postgresInstanceCount')]"
326 | },
327 | "properties": {
328 | "mode": "Incremental",
329 | "templateLink": {
330 | "uri": "[concat(variables('fileroot'), 'disksSelector.json')]",
331 | "contentVersion": "1.0.0.0"
332 | },
333 | "parameters": {
334 | "numDataDisks": {
335 | "value": "[parameters('dataDiscCount')]"
336 | },
337 | "diskStorageAccountName": {
338 | "value": "[concat(copyIndex(), 'pg', parameters('clusterName'))]"
339 | },
340 | "diskCaching": {
341 | "value": "[variables('diskCaching')]"
342 | },
343 | "diskSizeGB": {
344 | "value": "[parameters('dataDiskSizeInGB')]"
345 | },
346 | "storageUrlSuffix": {
347 | "value": "[variables('storageEndpoint')]"
348 | }
349 | }
350 | }
351 | },
352 | {
353 | "type": "Microsoft.Compute/virtualMachines",
354 | "name": "[concat('postgres', copyIndex())]",
355 | "apiVersion": "2015-05-01-preview",
356 | "location": "[resourceGroup().location]",
357 | "copy": {
358 | "name": "postgresVmLoop",
359 | "count": "[variables('postgresInstanceCount')]"
360 | },
361 | "properties": {
362 | "availabilitySet": {
363 | "id": "[resourceId('Microsoft.Compute/availabilitySets', 'postgresAvailabilitySet')]"
364 | },
365 | "hardwareProfile": {
366 | "vmSize": "[parameters('instanceSize')]"
367 | },
368 | "osProfile": {
369 | "computerName": "[concat('postgres', copyIndex())]",
370 | "adminUsername": "[parameters('adminUserName')]",
371 | "adminPassword": "[parameters('adminPassword')]"
372 | },
373 | "storageProfile": {
374 | "imageReference": {
375 | "publisher": "Canonical",
376 | "offer": "UbuntuServer",
377 | "sku": "14.04.4-LTS",
378 | "version": "latest"
379 | },
380 | "osDisk": {
381 | "name": "osdisk",
382 | "vhd": {
383 | "uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', copyIndex(), 'pg', parameters('clusterName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).primaryEndpoints.blob, 'vhds/', 'postgresosdisk', copyIndex(), '.vhd')]"
384 | },
385 | "caching": "ReadWrite",
386 | "createOption": "FromImage"
387 | },
388 | "dataDisks": "[reference(concat('postgresDataDisksConfigForVM', copyIndex())).outputs.dataDiskArray.value]"
389 | },
390 | "networkProfile": {
391 | "networkInterfaces": [
392 | {
393 | "id": "[resourceId('Microsoft.Network/networkInterfaces', concat('postgres', copyIndex(), '-nic'))]"
394 | }
395 | ]
396 | }
397 | },
398 | "dependsOn": [
399 | "postgresStorageLoop",
400 | "zookeeperVmLoop",
401 | "zookeeperExtLoop",
402 | "postgresDataDisksConfigLoop",
403 | "[concat('Microsoft.Storage/storageAccounts/', copyIndex(), 'pg', parameters('clusterName'))]",
404 | "[concat('Microsoft.Network/networkInterfaces/', 'postgres', copyIndex(), '-nic')]",
405 | "[concat('Microsoft.Compute/availabilitySets/', 'postgresAvailabilitySet')]"
406 | ]
407 | },
408 | {
409 | "type": "Microsoft.Compute/virtualMachines/extensions",
410 | "name": "[concat('postgres', copyIndex(), '/postgresExtension')]",
411 | "apiVersion": "2015-05-01-preview",
412 | "location": "[resourceGroup().location]",
413 | "copy": {
414 | "name": "postgresExtLoop",
415 | "count": "[variables('postgresInstanceCount')]"
416 | },
417 | "properties": {
418 | "publisher": "Microsoft.OSTCExtensions",
419 | "type": "CustomScriptForLinux",
420 | "typeHandlerVersion": "1.2",
421 | "settings": {
422 | "fileUris": [
423 | "[concat(variables('fileroot'), 'setup-raid.sh')]",
424 | "[concat(variables('fileroot'), 'start-pg.sh')]"
425 | ],
426 | "commandToExecute": "[concat('./start-pg.sh ', parameters('clusterName'), ' ', variables('zookeeperNetPrefix'), variables('zookeeperNetStartIP'), ' ', variables('zookeeperInstanceCount'), ' ', variables('postgresNetPrefix'), variables('postgresNetStartIP'), ' ', variables('postgresInstanceCount'), ' ', copyIndex(), ' ', parameters('adminUsername'), ' \"', parameters('adminPassword'), '\" ')]"
427 | }
428 | },
429 | "dependsOn": [
430 | "[concat('Microsoft.Compute/virtualMachines/', 'postgres', copyIndex())]"
431 | ]
432 | },
433 | {
434 | "type": "Microsoft.Network/loadBalancers",
435 | "name": "[variables('lbName')]",
436 | "apiVersion": "2015-06-15",
437 | "location": "[resourceGroup().location]",
438 | "properties": {
439 | "availabilitySet": {
440 | "id": "[resourceId('Microsoft.Compute/availabilitySets', 'postgresHaAvailabilitySet')]"
441 | },
442 | "frontendIPConfigurations": [
443 | {
444 | "name": "loadBalancerFrontEnd",
445 | "properties": {
446 | "publicIPAddress": {
447 | "id": "[variables('ipId')]"
448 | }
449 | }
450 | }
451 | ],
452 | "backendAddressPools": [
453 | {
454 | "name": "loadBalancerBackEnd"
455 | }
456 | ],
457 | "loadBalancingRules": [
458 | {
459 | "name": "postgresLbRule",
460 | "properties": {
461 | "frontendIPConfiguration": {
462 | "id": "[concat(variables('lbId'), '/frontendIPConfigurations/loadBalancerFrontEnd')]"
463 | },
464 | "backendAddressPool": {
465 | "id": "[concat(variables('lbId'), '/backendAddressPools/loadBalancerBackEnd')]"
466 | },
467 | "protocol": "Tcp",
468 | "frontendPort": 5432,
469 | "backendPort": 5000,
470 | "probe": {
471 | "id": "[concat(variables('lbId'), '/probes/postgresProbe')]"
472 | }
473 | }
474 | }
475 | ],
476 | "probes": [
477 | {
478 | "name": "postgresProbe",
479 | "properties": {
480 | "protocol": "Tcp",
481 | "port": 5000,
482 | "intervalInSeconds": 5,
483 | "numberOfProbes": 2
484 | }
485 | }
486 | ],
487 | "inboundNatRules": [
488 | {
489 | "name": "postgresSsh0",
490 | "properties": {
491 | "frontendIPConfiguration": {
492 | "id": "[concat(variables('lbId'), '/frontendIPConfigurations/loadBalancerFrontEnd')]"
493 | },
494 | "protocol": "Tcp",
495 | "frontendPort": 10110,
496 | "backendPort": 22
497 | }
498 | },
499 | {
500 | "name": "postgresSsh1",
501 | "properties": {
502 | "frontendIPConfiguration": {
503 | "id": "[concat(variables('lbId'), '/frontendIPConfigurations/loadBalancerFrontEnd')]"
504 | },
505 | "protocol": "Tcp",
506 | "frontendPort": 10111,
507 | "backendPort": 22
508 | }
509 | },
510 | {
511 | "name": "postgresSsh2",
512 | "properties": {
513 | "frontendIPConfiguration": {
514 | "id": "[concat(variables('lbId'), '/frontendIPConfigurations/loadBalancerFrontEnd')]"
515 | },
516 | "protocol": "Tcp",
517 | "frontendPort": 10112,
518 | "backendPort": 22
519 | }
520 | },
521 | {
522 | "name": "postgresSsh3",
523 | "properties": {
524 | "frontendIPConfiguration": {
525 | "id": "[concat(variables('lbId'), '/frontendIPConfigurations/loadBalancerFrontEnd')]"
526 | },
527 | "protocol": "Tcp",
528 | "frontendPort": 10113,
529 | "backendPort": 22
530 | }
531 | },
532 | {
533 | "name": "postgresSsh4",
534 | "properties": {
535 | "frontendIPConfiguration": {
536 | "id": "[concat(variables('lbId'), '/frontendIPConfigurations/loadBalancerFrontEnd')]"
537 | },
538 | "protocol": "Tcp",
539 | "frontendPort": 10114,
540 | "backendPort": 22
541 | }
542 | },
543 | {
544 | "name": "postgresSsh5",
545 | "properties": {
546 | "frontendIPConfiguration": {
547 | "id": "[concat(variables('lbId'), '/frontendIPConfigurations/loadBalancerFrontEnd')]"
548 | },
549 | "protocol": "Tcp",
550 | "frontendPort": 10115,
551 | "backendPort": 22
552 | }
553 | },
554 | {
555 | "name": "postgresSsh6",
556 | "properties": {
557 | "frontendIPConfiguration": {
558 | "id": "[concat(variables('lbId'), '/frontendIPConfigurations/loadBalancerFrontEnd')]"
559 | },
560 | "protocol": "Tcp",
561 | "frontendPort": 10116,
562 | "backendPort": 22
563 | }
564 | },
565 | {
566 | "name": "postgresSsh7",
567 | "properties": {
568 | "frontendIPConfiguration": {
569 | "id": "[concat(variables('lbId'), '/frontendIPConfigurations/loadBalancerFrontEnd')]"
570 | },
571 | "protocol": "Tcp",
572 | "frontendPort": 10117,
573 | "backendPort": 22
574 | }
575 | },
576 | {
577 | "name": "postgresSsh8",
578 | "properties": {
579 | "frontendIPConfiguration": {
580 | "id": "[concat(variables('lbId'), '/frontendIPConfigurations/loadBalancerFrontEnd')]"
581 | },
582 | "protocol": "Tcp",
583 | "frontendPort": 10118,
584 | "backendPort": 22
585 | }
586 | },
587 | {
588 | "name": "postgresSsh9",
589 | "properties": {
590 | "frontendIPConfiguration": {
591 | "id": "[concat(variables('lbId'), '/frontendIPConfigurations/loadBalancerFrontEnd')]"
592 | },
593 | "protocol": "Tcp",
594 | "frontendPort": 10119,
595 | "backendPort": 22
596 | }
597 | }
598 | ]
599 | },
600 | "dependsOn": [
601 | "[variables('ipId')]"
602 | ]
603 | }
604 | ],
605 | "outputs":
606 | {
607 | "fqdn": {
608 | "type": "string",
609 | "value": "[reference(variables('ipName')).dnsSettings.fqdn]"
610 | },
611 | "port": {
612 | "type": "int",
613 | "value": 5432
614 | },
615 | "postgresUser": {
616 | "type": "string",
617 | "value": "admin"
618 | },
619 | "postgresUserPassword": {
620 | "type": "securestring",
621 | "value": "[parameters('adminPassword')]"
622 | }
623 | }
624 | }
--------------------------------------------------------------------------------
/postgresHAstandalone.parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "environment": {
6 | "value": "Azure German Cloud"
7 | },
8 | "clusterName": {
9 | "value": "tani2"
10 | },
11 | "instanceSize": {
12 | "value": "Standard_DS2_v2"
13 | },
14 | "adminUsername": {
15 | "value": "director"
16 | },
17 | "adminPassword": {
18 | "value": "Start1234!!!"
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/scripts/setup-raid.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #
4 | # ./setup-raid.sh
5 | #
6 |
7 | if [ "$#" -ne 1 ]; then
8 | echo "Illegal number of parameters: ./ebs_raid0.sh "
9 | exit
10 | fi
11 |
12 | mount_point=$1
13 |
14 | drive_names=$(lsblk | grep ^sd | grep -w -v -e sda -e sdb | awk '{print $1;}')
15 | count=0
16 | drives=""
17 | for i in $drive_names; do
18 | drives="$drives /dev/$i"
19 | count=$((count+1))
20 | done
21 |
22 | mkdir -p "${mount_point}"
23 |
24 | root_drive=$(df -h | grep /dev/sda)
25 |
26 | if [[ "$root_drive" == "" ]]; then
27 | echo "Detected 'xvd' drive naming scheme \(root: $root_drive\)"
28 | DRIVE_SCHEME='xvd'
29 | else
30 | echo "Detected 'sd' drive naming scheme \(root: $root_drive\)"
31 | DRIVE_SCHEME='sd'
32 | fi
33 |
34 | partprobe
35 | mdadm --verbose --create /dev/md1 --level=0 --name=raid -c256 --raid-devices=$count $drives
36 | md=$(grep sdc /proc/mdstat | cut -d':' -f1)
37 |
38 | echo "dev.raid.speed_limit_min = 1000000" >> /etc/sysctl.conf
39 | echo "dev.raid.speed_limit_max = 2000000" >> /etc/sysctl.conf
40 |
41 | echo DEVICE "$drives" | tee /etc/mdadm.conf
42 | mdadm --detail --scan | tee -a /etc/mdadm.conf
43 |
44 |
45 | mkfs.xfs -f -d su=256k,sw=4 -l version=2,su=256k -i size=1024 /dev/$md
46 | mount -t xfs -o rw,uqnoenforce,gqnoenforce,noatime,nodiratime,logbufs=8,logbsize=256k,largeio,inode64,swalloc,allocsize=131072k,nobarrier /dev/$md $mount_point
47 |
48 | for i in $drive_names; do
49 | echo 8192 > "/sys/block/$i/queue/nr_requests"
50 | echo noop > "/sys/block/$i/queue/scheduler"
51 | done
52 |
53 | for i in $md
54 | do
55 | echo noop > "/sys/block/$i/queue/scheduler"
56 | echo 256 > "/sys/block/$i/queue/read_ahead_kb"
57 | echo 0 > "/sys/block/$i/queue/rotational"
58 | done
59 |
60 | echo 30 > /proc/sys/vm/vfs_cache_pressure
61 | echo never > /sys/kernel/mm/transparent_hugepage/enabled
62 | echo 20 > /proc/sys/vm/dirty_ratio
63 | echo 10 > /proc/sys/vm/dirty_background_ratio
64 |
65 | # Remove xvdb/sdb from fstab
66 | chmod 644 /etc/fstab
67 | sed -i "/${DRIVE_SCHEME}b/d" /etc/fstab
68 |
69 | # Make raid appear on reboot
70 | echo "/dev/$md $mount_point xfs noatime 0 0" | tee -a /etc/fstab
71 |
--------------------------------------------------------------------------------
/scripts/start-pg.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # /var/lib/waagent/Microsoft.OSTCExtensions.CustomScriptForLinux-1.2.2.0/download/0
4 | # /usr/local/patroni-6eb2e2114453545256ac7cbfec55bda285ffb955
5 |
6 | # http://jvns.ca/blog/2017/03/26/bash-quirks/
7 | # https://google.github.io/styleguide/shell.xml#Checking_Return_Values
8 | # http://www.kfirlavi.com/blog/2012/11/14/defensive-bash-programming/
9 |
10 | function createIp {
11 | startIpInput=$1
12 | index=$2
13 |
14 | #change internal field separator
15 | oldIFS=$IFS
16 | IFS=.
17 | #parse IP into array
18 | ary=($startIpInput)
19 | #reset internal field separator
20 | IFS=$oldIFS
21 |
22 | #create C-Net of Ip
23 | ip=""
24 | for (( i=0; i<$((${#ary[@]}-1)); i++ ))
25 | do
26 | ip="$ip${ary[$i]}."
27 | done
28 |
29 | #create D-Net of Ip
30 | ip="$ip$((${ary[-1]}+index))"
31 | printf "%s" "$ip"
32 | }
33 |
34 | # curl -L https://raw.githubusercontent.com/chgeuer/postgres-azure/master/scripts/start-pg.sh -o start-pg.sh
35 | # ./0start-pg.sh clustername 10.0.0.10 3 10.0.1.10 2 0 chgeuer supersecret123.-
36 | # lint using https://www.shellcheck.net/#
37 |
38 | # "commandToExecute": "[concat('./start-pg.sh ',
39 | # parameters('clusterName'), ' ',
40 | # concat(variables('commonSettings').vnet.subnet.zookeeper.addressRangePrefix, '.10'), ' ',
41 | # variables('commonSettings').instanceCount.zookeeper, ' ',
42 | # concat(variables('commonSettings').vnet.subnet.postgresql.addressRangePrefix, '.10'), ' ',
43 | # variables('commonSettings').instanceCount.postgresql, ' ',
44 | # copyIndex(), ' ',
45 | # parameters('postgresqlUsername'), ' ',
46 | # concat('\"', parameters('postgresqlPassword'), '\"'), ' '
47 | # variables('commonSettings').softwareversions.patroni, ' ',
48 | # variables('commonSettings').softwareversions.postgres )]"
49 |
50 | clusterName=$1
51 | startIpZooKeepers=$2
52 | amountZooKeepers=$3
53 | startIpPostgres=$4
54 | amountPostgres=$5
55 | myIndex=$6
56 | postgresqlUsername=$7
57 | postgresqlPassword=$8
58 | patroniversion=$9
59 | pgversion=${10}
60 |
61 | patroniDir="/usr/local/patroni-${patroniversion}"
62 | patroniCfg="${patroniDir}/postgres.yml"
63 | hacfgFile="${patroniDir}/postgresha.cfg"
64 |
65 | cat > startup.log <<-EOF
66 | Cluster name: $clusterName
67 | startIpZooKeepers: $startIpZooKeepers
68 | amountZooKeepers: $amountZooKeepers
69 | startIpPostgres: $startIpPostgres
70 | amountPostgres: $amountPostgres
71 | myIndex: $myIndex
72 | postgresqlUsername: $postgresqlUsername
73 | postgresqlPassword: $postgresqlPassword
74 | pgversion: $pgversion
75 | patroniversion: $patroniversion
76 | EOF
77 |
78 | #
79 | # install & configure saltstack
80 | #
81 | curl -L https://bootstrap.saltstack.com -o bootstrap_salt.sh
82 | sh bootstrap_salt.sh
83 |
84 | cat >> /etc/salt/minion <<-EOF
85 | file_client: local
86 | EOF
87 |
88 | mkdir --parents /srv/salt
89 |
90 | cat > /srv/salt/top.sls <<-EOF
91 | base:
92 | '*':
93 | - webserver
94 | - postgres-pkgs
95 | - patroni
96 | EOF
97 |
98 | cat > /srv/salt/webserver.sls <<-EOF
99 | python-pip:
100 | pkg.installed
101 | webserver:
102 | pkg.installed:
103 | - pkgs:
104 | - mdadm
105 | - xfsprogs
106 | - supervisor
107 | - curl
108 | - jq
109 | - haproxy
110 | - libpq-dev
111 | - python
112 | - python-dev
113 | - python-psycopg2
114 | - python-yaml
115 | - python-requests
116 | - python-six
117 | - python-dateutil
118 | - python-urllib3
119 | - python-dnspython
120 | - python-pip
121 | - python-setuptools
122 | - python-kazoo
123 | - python-prettytable
124 | - python-wheel
125 | pip.installed:
126 | - require:
127 | - pkg: python-pip
128 | - upgrade:
129 | - pip >= 9.0.1
130 | - PyYAML
131 | - requests
132 | - six
133 | - prettytable
134 | - names:
135 | - boto
136 | - psycopg2
137 | - kazoo
138 | - python-etcd == 0.4.3
139 | - python-consul == 0.7.0
140 | - click
141 | - tzlocal
142 | - python-dateutil
143 | - urllib3
144 | - PySocks
145 | EOF
146 |
147 | cat > /srv/salt/postgres-pkgs.sls <<-EOF
148 | postgres-pkgs:
149 | pkg.installed:
150 | - pkgs:
151 | - postgresql-$pgversion
152 | - postgresql-contrib-$pgversion
153 | postgres_repo:
154 | pkgrepo.managed:
155 | - name: "deb http://apt.postgresql.org/pub/repos/apt/ {{ grains['oscodename'] }}-pgdg main"
156 | - file: /etc/apt/sources.list.d/pgdg.list
157 | - key_url: https://www.postgresql.org/media/keys/ACCC4CF8.asc
158 | - require_in:
159 | - pkg: postgres-pkgs
160 | EOF
161 |
162 | cat > /srv/salt/patroni.sls <<-EOF
163 | patroni:
164 | pkg.installed:
165 | - pkgs:
166 | - unzip
167 | cmd.run:
168 | - name: curl -L https://github.com/zalando/patroni/archive/${patroniversion}.zip -o /etc/salt/patroni-${patroniversion}.zip
169 | - creates: /etc/salt/patroni-${patroniversion}.zip
170 | archive.extracted:
171 | - name: /tmp/patroni-${patroniversion}
172 | - source: /etc/salt/patroni-${patroniversion}.zip
173 | - use_cmd_unzip: true
174 | - force: true
175 | file.copy:
176 | - source: /tmp/patroni-${patroniversion}/patroni-${patroniversion}
177 | - name: ${patroniDir}
178 | - force: true
179 | EOF
180 |
181 | salt-call --local state.apply
182 |
183 | export PATH=/usr/lib/postgresql/${pgversion}/bin:$PATH
184 |
185 | # create RAID
186 |
187 | mount_point=/mnt/database
188 |
189 | sh setup-raid.sh "$mount_point"
190 | mkdir "$mount_point/data"
191 | chmod 777 "$mount_point/data"
192 |
193 | # write configuration
194 | echo "START IP PROGRESS $startIpPostgres"
195 |
196 | cat > $patroniCfg <<-EOF
197 | scope: &scope $clusterName
198 | ttl: &ttl 30
199 | loop_wait: &loop_wait 10
200 | EOF
201 |
202 | if [[ $myIndex -eq 0 ]]; then
203 | cat >> $patroniCfg <<-EOF
204 | name: postgres$myIndex
205 | EOF
206 | fi
207 |
208 | cat >> $patroniCfg <<-EOF
209 | restapi:
210 | listen: $(createIp "$startIpPostgres" "$myIndex"):8008
211 | connect_address: $(createIp "$startIpPostgres" "$myIndex"):8008
212 | zookeeper:
213 | scope: *scope
214 | session_timeout: *ttl
215 | reconnect_timeout: *loop_wait
216 | hosts:
217 | EOF
218 |
219 | for i in `seq 0 $((instanceCount-1))`
220 | do
221 | cat >> $patroniCfg <<-EOF
222 | - $(createIp "$startIpZooKeepers" "$i"):2181
223 | EOF
224 | done
225 |
226 | echo "" >> $patroniCfg
227 |
228 | if [[ $myIndex -eq 0 ]]; then
229 | cat >> $patroniCfg <<-EOF
230 | bootstrap:
231 | dcs:
232 | ttl: *ttl
233 | loop_wait: *loop_wait
234 | retry_timeout: *loop_wait
235 | maximum_lag_on_failover: 1048576
236 | postgresql:
237 | use_pg_rewind: true
238 | use_slots: true
239 | parameters:
240 | archive_mode: "on"
241 | archive_timeout: 1800s
242 | archive_command: mkdir -p ../wal_archive && test ! -f ../wal_archive/%f && cp %p ../wal_archive/%f
243 | recovery_conf:
244 | restore_command: cp ../wal_archive/%f %p
245 | initdb:
246 | - encoding: UTF8
247 | - data-checksums
248 | pg_hba:
249 | - host replication all 0.0.0.0/0 md5
250 | - host all all 0.0.0.0/0 md5
251 | users:
252 | admin:
253 | password: "$postgresqlPassword"
254 | options:
255 | - createrole
256 | - createdb
257 | EOF
258 | fi
259 |
260 | cat >> $patroniCfg <<-EOF
261 | tags:
262 | nofailover: false
263 | noloadbalance: false
264 | clonefrom: false
265 | postgresql:
266 | EOF
267 |
268 | if [[ $myIndex -ne 0 ]]; then
269 | cat >> $patroniCfg <<-EOF
270 | name: postgres${myIndex}
271 | EOF
272 | fi
273 |
274 | cat >> $patroniCfg <<-EOF
275 | listen: '*:5433'
276 | connect_address: $(createIp "$startIpPostgres" "$myIndex"):5433
277 | data_dir: ${mount_point}/data/postgresql
278 | pgpass: /tmp/pgpass
279 | EOF
280 |
281 | if [[ $myIndex -ne 0 ]]; then
282 | cat >> $patroniCfg <<-EOF
283 | maximum_lag_on_failover: 1048576
284 | use_slots: true
285 | initdb:
286 | - encoding: UTF8
287 | - data-checksums
288 | pg_rewind:
289 | username: postgres
290 | password: "$postgresqlPassword"
291 | pg_hba:
292 | - host replication all 0.0.0.0/0 md5
293 | - host all all 0.0.0.0/0 md5
294 | replication:
295 | username: replicator
296 | password: "$postgresqlPassword"
297 | superuser:
298 | username: postgres
299 | password: "$postgresqlPassword"
300 | admin:
301 | username: admin
302 | password: "$postgresqlPassword"
303 | create_replica_method:
304 | - basebackup
305 | recovery_conf:
306 | restore_command: cp ../wal_archive/%f %p
307 | parameters:
308 | archive_mode: "on"
309 | wal_level: hot_standby
310 | archive_command: mkdir -r ../wal_archive && test ! -f ../wal_archive/%f && cp %cp ../wal_archive/%f
311 | max_wal_senders: 10
312 | wal_keep_segments: 8
313 | archive_timeout: 1800s
314 | max_replication_slots: 10
315 | hot_standby: "on"
316 | wal_log_hints: "on"
317 | unix_socket_directories: '.'
318 | EOF
319 | else
320 | cat >> $patroniCfg <<-EOF
321 | authentication:
322 | replication:
323 | username: replicator
324 | password: "$postgresqlPassword"
325 | superuser:
326 | username: postgres
327 | password: "$postgresqlPassword"
328 | parameters:
329 | unix_socket_directories: '.'
330 | EOF
331 | fi
332 |
333 | chmod 666 $patroniCfg
334 |
335 | cat > $hacfgFile <<-EOF
336 | global
337 | maxconn 100
338 | defaults
339 | log global
340 | mode tcp
341 | retries 2
342 | timeout client 30m
343 | timeout connect 4s
344 | timeout server 30m
345 | timeout check 5s
346 | frontend ft_postgresql
347 | bind *:5000
348 | default_backend bk_db
349 | backend bk_db
350 | option httpchk
351 | EOF
352 |
353 | for i in `seq 0 $((amountPostgres-1))`
354 | do
355 | cat >> $hacfgFile <<-EOF
356 | server Postgres$i $(createIp "$startIpPostgres" "$i"):5433 maxconn 100 check port 8008
357 | EOF
358 | done
359 | chmod 666 $hacfgFile
360 |
361 | cat > ${patroniDir}/patroni_start.sh <<-EOF
362 | #!/bin/bash
363 | export PATH=/usr/lib/postgresql/${pgversion}/bin:\$PATH
364 | ${patroniDir}/patroni.py ${patroniCfg}
365 | EOF
366 | chmod +x ${patroniDir}/patroni_start.sh
367 |
368 | cat > /etc/supervisor/conf.d/patroni.conf <<-EOF
369 | [program:patroni]
370 | command=${patroniDir}/patroni_start.sh
371 | user=$postgresqlUsername
372 | autostart=true
373 | autorestart=true
374 | stderr_logfile=/var/log/patroni.err.log
375 | stdout_logfile=/var/log/patroni.out.log
376 | EOF
377 |
378 | cat > /etc/supervisor/conf.d/haproxy.conf <<-EOF
379 | [program:haproxy]
380 | command=haproxy -D -f $hacfgFile
381 | autostart=true
382 | autorestart=true
383 | stderr_logfile=/var/log/haproxy.err.log
384 | stdout_logfile=/var/log/haproxy.out.log
385 | EOF
386 |
387 | service supervisor restart
388 | supervisorctl reread
389 | supervisorctl update
390 |
391 | exit 0
392 |
--------------------------------------------------------------------------------
/scripts/start-zk.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function createIp {
4 | startIpInput=$1
5 | index=$2
6 |
7 | #change internal field separator
8 | oldIFS=$IFS
9 | IFS=.
10 | #parse IP into array
11 | ary=($startIpInput)
12 | #reset internal field separator
13 | IFS=$oldIFS
14 |
15 | #create C-Net of Ip
16 | ip=""
17 | for (( i=0; i<$((${#ary[@]}-1)); i++ ))
18 | do
19 | ip="$ip${ary[$i]}."
20 | done
21 |
22 | #create D-Net of Ip
23 | ip="$ip$((${ary[-1]}+index))"
24 | printf "%s" "$ip"
25 | }
26 |
27 | # "commandToExecute": "[concat('./start-zk.sh', ' ',
28 | # copyIndex(), ' ',
29 | # variables('commonSettings').instanceCount.zookeeper, ' ',
30 | # concat(variables('commonSettings').vnet.subnet.zookeeper.addressRangePrefix, '.10'), ' ',
31 | # variables('commonSettings').softwareversions.zookeeper, ' ',
32 | # variables('commonSettings').softwareversions.java4zookeeper1, ' ',
33 | # variables('commonSettings').softwareversions.java4zookeeper2)]"
34 |
35 | myIndex=$1
36 | zookeeperInstanceCount=$2
37 | startIp=$3
38 | zkversion=$4
39 | javaversion1=$5
40 | javaversion2=$6
41 |
42 | # myIndex=1
43 | # zookeeperInstanceCount=3
44 | # startIp=10.0.0.10
45 | # zkversion=3.4.9
46 | # javaversion1=7u75
47 | # javaversion2=b13
48 |
49 | apt-get -y install jq supervisor
50 |
51 | #
52 | # Install Java
53 | #
54 | # wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" -c -O "jdk-8u121-linux-x64.tar.gz" "http://download.oracle.com/otn-pub/java/jdk/8u121-b13/e9e7ea248e2c4826b92b3f075a80e441/jdk-8u121-linux-x64.tar.gz"
55 | wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" -c -O "jdk-${javaversion1}-linux-x64.tar.gz" "http://download.oracle.com/otn-pub/java/jdk/${javaversion1}-${javaversion2}/jdk-${javaversion1}-linux-x64.tar.gz"
56 |
57 | mkdir --parents /usr/lib/jvm/jdk-${javaversion1}
58 | tar -xvf jdk-${javaversion1}-linux-x64.tar.gz --strip-components=1 --directory /usr/lib/jvm/jdk-${javaversion1}
59 | update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/jdk-${javaversion1}/bin/java" 1
60 | update-alternatives --install "/usr/bin/javac" "javac" "/usr/lib/jvm/jdk-${javaversion1}/bin/javac" 1
61 | update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/lib/jvm/jdk-${javaversion1}/bin/javaws" 1
62 | chmod a+x /usr/bin/java
63 | chmod a+x /usr/bin/javac
64 | chmod a+x /usr/bin/javaws
65 |
66 | #
67 | # Install ZooKeeper
68 | #
69 | zkbindir=/usr/local/zookeeper-${zkversion}
70 | zkworkdir=/var/lib/zookeeper
71 | mkdir --parents $zkbindir
72 | mkdir --parents $zkworkdir
73 | mirror=$(curl -s "https://www.apache.org/dyn/closer.cgi?as_json=1" | jq --raw-output .preferred)
74 | curl --get --url "${mirror}zookeeper/zookeeper-${zkversion}/zookeeper-${zkversion}.tar.gz" --output "zookeeper-${zkversion}.tar.gz"
75 | tar -xvf "zookeeper-${zkversion}.tar.gz" --strip-components=1 --directory "$zkbindir"
76 |
77 | cat > "$zkbindir/conf/zoo.cfg" <<-EOF
78 | tickTime=2000
79 | dataDir=${zkworkdir}
80 | clientPort=2181
81 | initLimit=5
82 | syncLimit=2
83 | EOF
84 |
85 | for i in $(seq 1 $zookeeperInstanceCount)
86 | do
87 | cat >> "$zkbindir/conf/zoo.cfg" <<-EOF
88 | server.$i=$(createIp "$startIp" "$((i-1))"):2888:3888
89 | EOF
90 | done
91 |
92 | cat > "${zkworkdir}/myid" <<-EOF
93 | $((myIndex + 1))
94 | EOF
95 |
96 | # command = /usr/lib/jvm/jdk-${javaversion1}/bin/java -Dzookeeper.log.dir="." -Dzookeeper.root.logger="INFO,CONSOLE" -cp "$zkbindir/build/classes:$zkbindir/build/lib/*.jar:$zkbindir/lib/slf4j-log4j12-1.6.1.jar:$zkbindir/lib/slf4j-api-1.6.1.jar:$zkbindir/lib/netty-3.10.5.Final.jar:$zkbindir/lib/log4j-1.2.16.jar:$zkbindir/lib/jline-0.9.94.jar:$zkbindir/zookeeper-3.4.9.jar:$zkbindir/src/java/lib/*.jar:$zkbindir/conf:" -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=false org.apache.zookeeper.server.quorum.QuorumPeerMain "$zkbindir/conf/zoo.cfg"
97 |
98 | cat > /etc/supervisor/conf.d/zookeeper.conf <<-EOF
99 | [program:zookeeper]
100 | command=$zkbindir/bin/zkServer.sh start-foreground
101 | autostart=true
102 | autorestart=true
103 | stopsignal=KILL
104 | startsecs=10
105 | startretries=999
106 | stderr_logfile=/var/log/zookeeper.err.log
107 | stdout_logfile=/var/log/zookeeper.out.log
108 | logfile_maxbytes=20MB
109 | logfile_backups=10d;
110 | EOF
111 |
112 | service supervisor restart
113 | supervisorctl reread
114 | supervisorctl update
115 |
116 | exit 0
117 |
--------------------------------------------------------------------------------