mirror of
https://github.com/stefanprodan/podinfo.git
synced 2026-04-07 03:26:54 +00:00
Compare commits
720 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b501abd1f0 | ||
|
|
e0a79a4ddd | ||
|
|
be8baac695 | ||
|
|
f539517440 | ||
|
|
01219a196e | ||
|
|
b9acae4064 | ||
|
|
64a8da1836 | ||
|
|
420d0db8bf | ||
|
|
6b67f2bdd6 | ||
|
|
095b1cd251 | ||
|
|
0a27dbe40c | ||
|
|
2da74a4ec2 | ||
|
|
c7ffdba3bd | ||
|
|
06f7cd3777 | ||
|
|
620b9b7e2c | ||
|
|
83deb7fcb7 | ||
|
|
550ee9f7b9 | ||
|
|
dd185df435 | ||
|
|
07a524ba01 | ||
|
|
5d97df9c89 | ||
|
|
a8cadef09b | ||
|
|
32f6e3d8c9 | ||
|
|
77dc46241d | ||
|
|
3a31e973c0 | ||
|
|
e15511a92d | ||
|
|
4656ca0517 | ||
|
|
1f66430364 | ||
|
|
117533e329 | ||
|
|
29827dd944 | ||
|
|
9525259938 | ||
|
|
a53ddbcffc | ||
|
|
e3c8277e58 | ||
|
|
420b2f64b8 | ||
|
|
0a93807324 | ||
|
|
d73d94eec9 | ||
|
|
a723c9447d | ||
|
|
eca2d3a1d9 | ||
|
|
2dfda568b2 | ||
|
|
4d7604ab63 | ||
|
|
f3c2e57a6f | ||
|
|
8bded1ba80 | ||
|
|
da120efc04 | ||
|
|
ea672716dd | ||
|
|
47742372b9 | ||
|
|
30be5f5b6a | ||
|
|
4fb3be1de0 | ||
|
|
d532cc2a24 | ||
|
|
f1eb631ac9 | ||
|
|
03172452ee | ||
|
|
b6b680fe50 | ||
|
|
e51374c0ec | ||
|
|
80b5bf5495 | ||
|
|
f53a3109cf | ||
|
|
11b7ac4319 | ||
|
|
396a56493b | ||
|
|
4991d2e6d0 | ||
|
|
c0669703ab | ||
|
|
0f360bb788 | ||
|
|
d7fee06b63 | ||
|
|
4f64661bff | ||
|
|
1318ba1bd1 | ||
|
|
1267688401 | ||
|
|
3ed50e4d85 | ||
|
|
d9fec9778d | ||
|
|
7ac390bb27 | ||
|
|
576ad0ff2f | ||
|
|
74ac24bc86 | ||
|
|
902e62b5f3 | ||
|
|
6a069aed1a | ||
|
|
bca20328fb | ||
|
|
d81ac93a8a | ||
|
|
71fc0d8096 | ||
|
|
81654006ee | ||
|
|
c74b0d4ccb | ||
|
|
e335313b04 | ||
|
|
ca375ee533 | ||
|
|
d8e8054876 | ||
|
|
e86405a867 | ||
|
|
a51de59edb | ||
|
|
1ff6fff334 | ||
|
|
98e8cd39d4 | ||
|
|
65b9e92db3 | ||
|
|
c6536c75ce | ||
|
|
3c4910d1c7 | ||
|
|
c831679d1e | ||
|
|
94a9f99f79 | ||
|
|
86ac641693 | ||
|
|
cdd09cdd3d | ||
|
|
0b8a7dace7 | ||
|
|
e50f88a43d | ||
|
|
67e4628d95 | ||
|
|
73f5e936c8 | ||
|
|
0e26c3b934 | ||
|
|
dc39bd9a08 | ||
|
|
c23d57a4e9 | ||
|
|
85d22b2172 | ||
|
|
ff906f2242 | ||
|
|
2dbf735c46 | ||
|
|
1318243ec9 | ||
|
|
12e7f14ff0 | ||
|
|
fb3b01be30 | ||
|
|
be955e76b0 | ||
|
|
3e79d79447 | ||
|
|
cd555cf439 | ||
|
|
2927336ecd | ||
|
|
8f5425b6d5 | ||
|
|
1cd88028c7 | ||
|
|
ca101e6728 | ||
|
|
c8419e386a | ||
|
|
9356c1c0c4 | ||
|
|
60b5e4c4fe | ||
|
|
322b71c1e5 | ||
|
|
b3396adb98 | ||
|
|
c6e70a7aa0 | ||
|
|
6810566623 | ||
|
|
8efcd73510 | ||
|
|
eb81ed6ed2 | ||
|
|
916f1a298a | ||
|
|
7cc399463c | ||
|
|
78755636d0 | ||
|
|
b99bf8c252 | ||
|
|
e7928cfbc7 | ||
|
|
dc5d3d559e | ||
|
|
71f618320e | ||
|
|
c4e601b4cb | ||
|
|
6b7aab8a10 | ||
|
|
b7d3d71d8f | ||
|
|
abcd272293 | ||
|
|
4af7854aa2 | ||
|
|
fc1e4a48ed | ||
|
|
08238eada7 | ||
|
|
892a66ea93 | ||
|
|
0b1481aa8e | ||
|
|
ff32a1fc4b | ||
|
|
3de84d2360 | ||
|
|
ba6f4ffd7c | ||
|
|
6d4405a1ef | ||
|
|
752950cb4f | ||
|
|
b10c3067c8 | ||
|
|
85cd1c46d4 | ||
|
|
2687a13c75 | ||
|
|
5fb6597929 | ||
|
|
1fbdd9420f | ||
|
|
30cd3b27d7 | ||
|
|
1d7de0bb82 | ||
|
|
c52654c59e | ||
|
|
1a6838a4a2 | ||
|
|
b0c487c6b2 | ||
|
|
b28069ac51 | ||
|
|
d8a136cf74 | ||
|
|
614f74f6df | ||
|
|
0c4f327390 | ||
|
|
d791dedb24 | ||
|
|
220d4e909c | ||
|
|
eba7fe186e | ||
|
|
9108833214 | ||
|
|
386ceb09be | ||
|
|
f350624047 | ||
|
|
37ba3e854f | ||
|
|
70335812c6 | ||
|
|
8d010c498e | ||
|
|
8b3079a417 | ||
|
|
37fa020bcd | ||
|
|
d879d0f4fb | ||
|
|
16191504d1 | ||
|
|
d042732a44 | ||
|
|
649864583b | ||
|
|
c07eb64558 | ||
|
|
44942884c3 | ||
|
|
d562a2a82a | ||
|
|
d7c1bf015c | ||
|
|
cdec0786ef | ||
|
|
e6d611e1e2 | ||
|
|
36bea810ef | ||
|
|
50047dab3a | ||
|
|
2b936e6700 | ||
|
|
55e4e51eba | ||
|
|
47090ad9e1 | ||
|
|
6a0bbda8a5 | ||
|
|
357009a863 | ||
|
|
0f98770296 | ||
|
|
f9032836a6 | ||
|
|
5368c3fe10 | ||
|
|
b1207aa9b1 | ||
|
|
c7f9b521fa | ||
|
|
24405a5a5d | ||
|
|
5195b158fc | ||
|
|
532db405f8 | ||
|
|
2251bee699 | ||
|
|
8535efccb7 | ||
|
|
e008d1f261 | ||
|
|
22097353d2 | ||
|
|
c305843105 | ||
|
|
0d2c428859 | ||
|
|
ecaa7cf4d3 | ||
|
|
8447b6985b | ||
|
|
9371d6d153 | ||
|
|
20b8c1043c | ||
|
|
2d80c7a22d | ||
|
|
dc830d02a6 | ||
|
|
badf3271a1 | ||
|
|
9f9c2f3245 | ||
|
|
33dac1ba40 | ||
|
|
1cf8b8aeef | ||
|
|
22fb1c3d34 | ||
|
|
adf8157da6 | ||
|
|
03f8ad0251 | ||
|
|
101e371e96 | ||
|
|
53c9f3ad9b | ||
|
|
a69f0282fd | ||
|
|
174d183056 | ||
|
|
7bb64e7567 | ||
|
|
49a4b31d53 | ||
|
|
c29e013a33 | ||
|
|
45ecda63bb | ||
|
|
4868f430c7 | ||
|
|
ca9c6bb4f8 | ||
|
|
86f3b1a57c | ||
|
|
b22dd96a54 | ||
|
|
5aaf95849e | ||
|
|
e197eca420 | ||
|
|
73fcdbe4a6 | ||
|
|
074d0f9ff2 | ||
|
|
d9bc6301e9 | ||
|
|
a0e323e331 | ||
|
|
1ee349fa17 | ||
|
|
0f526c3cd4 | ||
|
|
021c55fed9 | ||
|
|
bb2408d17d | ||
|
|
5eb3cafd6a | ||
|
|
df0f8ba885 | ||
|
|
19a59d96f1 | ||
|
|
401461595a | ||
|
|
bd77584ade | ||
|
|
87e0dbaa7e | ||
|
|
c5494104a1 | ||
|
|
74c60a927c | ||
|
|
ecdf07c4d5 | ||
|
|
ff29c549ff | ||
|
|
fa75fc0520 | ||
|
|
0bc496456d | ||
|
|
398c543171 | ||
|
|
a54dc2a9c7 | ||
|
|
bfa42afa1f | ||
|
|
590987704e | ||
|
|
d561182076 | ||
|
|
72bd6faf35 | ||
|
|
2cbe0fcdff | ||
|
|
87e594b109 | ||
|
|
7ec9e6c84a | ||
|
|
8183d0d5fc | ||
|
|
aa27416651 | ||
|
|
b0594a85b9 | ||
|
|
e816d1b5bc | ||
|
|
6316e213d1 | ||
|
|
a1b112f4e1 | ||
|
|
1495fd888e | ||
|
|
dfc4a6d37e | ||
|
|
aaa47e535f | ||
|
|
0278e11a05 | ||
|
|
12ceae475f | ||
|
|
4892983fd1 | ||
|
|
bcf492e92b | ||
|
|
a54550e439 | ||
|
|
29dd482f49 | ||
|
|
3a7d4d1544 | ||
|
|
c14b116dea | ||
|
|
12c078938d | ||
|
|
dd3869b1a1 | ||
|
|
45cfe3abc2 | ||
|
|
fcf573111b | ||
|
|
cadabcc6a5 | ||
|
|
9dfb676083 | ||
|
|
e06a5517da | ||
|
|
fedab0de38 | ||
|
|
7d13025a35 | ||
|
|
7280e43cbf | ||
|
|
3ef0b4cd09 | ||
|
|
073f1ec5af | ||
|
|
1e0307c759 | ||
|
|
d4d75c2fbf | ||
|
|
2a6533c68a | ||
|
|
0647aea75b | ||
|
|
8c258bb1d8 | ||
|
|
58726f0bd2 | ||
|
|
bc08542ed3 | ||
|
|
bbce3f3f67 | ||
|
|
67e2c98a60 | ||
|
|
938b00be6d | ||
|
|
e6c7657155 | ||
|
|
d75e8d7838 | ||
|
|
74d6532429 | ||
|
|
8187f79475 | ||
|
|
2b6f4f0a7d | ||
|
|
3a4a99697b | ||
|
|
1abc44f0d8 | ||
|
|
3d798af827 | ||
|
|
f8f8073946 | ||
|
|
c8c7a6d1bb | ||
|
|
eac008b339 | ||
|
|
d2227a4204 | ||
|
|
ae3fe3da98 | ||
|
|
42fdaf8e7a | ||
|
|
3e2d907993 | ||
|
|
21136b6405 | ||
|
|
e8c388a3fd | ||
|
|
abc38e1bff | ||
|
|
bf4a3140fe | ||
|
|
de2dd687cb | ||
|
|
f7a9563986 | ||
|
|
a699fffe7b | ||
|
|
24e5de8934 | ||
|
|
298c1ae941 | ||
|
|
fdd0a0b7da | ||
|
|
8bab17843c | ||
|
|
34c5ab57b6 | ||
|
|
0f9c989b68 | ||
|
|
e2e85a9604 | ||
|
|
b687d3c76f | ||
|
|
dbbb415194 | ||
|
|
1a89d81ebb | ||
|
|
b39526ebe8 | ||
|
|
607303dca9 | ||
|
|
3053e634f9 | ||
|
|
4f1e56ae83 | ||
|
|
f0590a03e0 | ||
|
|
aa815625d9 | ||
|
|
8615cb75d9 | ||
|
|
b23ebb15cb | ||
|
|
dcb5b13023 | ||
|
|
71869089fa | ||
|
|
1cf228c67b | ||
|
|
b6e81a931b | ||
|
|
744597a481 | ||
|
|
389c86ee93 | ||
|
|
34db5fa463 | ||
|
|
0d62402ae9 | ||
|
|
e40d32ba87 | ||
|
|
3879b59f43 | ||
|
|
44157ecd84 | ||
|
|
bfa8d8032f | ||
|
|
b1251214f6 | ||
|
|
f1168c4946 | ||
|
|
013343a232 | ||
|
|
d460863f3b | ||
|
|
25a1e26159 | ||
|
|
b39afea117 | ||
|
|
6d11ef9baf | ||
|
|
baf128d856 | ||
|
|
79f8138328 | ||
|
|
ceed4e7870 | ||
|
|
bfce2199e8 | ||
|
|
d55bb8eabd | ||
|
|
5fb056ebcb | ||
|
|
35b9c9f946 | ||
|
|
74e0aeeff7 | ||
|
|
bbb081b0e1 | ||
|
|
c16318bb85 | ||
|
|
86d5fe86e4 | ||
|
|
b3b00fe354 | ||
|
|
a7bcfaf9b3 | ||
|
|
1d4c534728 | ||
|
|
f2e0aa154d | ||
|
|
6d5b3d254a | ||
|
|
9b9f11da95 | ||
|
|
1a55e30bcf | ||
|
|
394c40e3ff | ||
|
|
b76b1a38c9 | ||
|
|
2eb17d80c8 | ||
|
|
678a42ce34 | ||
|
|
2da59980fe | ||
|
|
8697f091f3 | ||
|
|
4d2cf65260 | ||
|
|
116a378991 | ||
|
|
450796ddb2 | ||
|
|
cb8c1fcec1 | ||
|
|
37da8d1c74 | ||
|
|
e55ebd258d | ||
|
|
6b869d1a18 | ||
|
|
dea973d614 | ||
|
|
f4199ab8bc | ||
|
|
19603ddfc1 | ||
|
|
bf09377bfd | ||
|
|
075712dd73 | ||
|
|
07dd9a3c3e | ||
|
|
63ac69ea69 | ||
|
|
3db382d2c9 | ||
|
|
9f88a0e940 | ||
|
|
c6a2c90497 | ||
|
|
54908f7d51 | ||
|
|
36bf90b008 | ||
|
|
dd9020c8b2 | ||
|
|
51009591a5 | ||
|
|
2b8c71ba78 | ||
|
|
203f7e1bf0 | ||
|
|
8179263f52 | ||
|
|
b26a34b5b6 | ||
|
|
cd7a0fb18e | ||
|
|
c1fd17e50a | ||
|
|
f98267009e | ||
|
|
7d0203196a | ||
|
|
673966bae4 | ||
|
|
9265828c4f | ||
|
|
0f68b60870 | ||
|
|
217a27ce02 | ||
|
|
fc172b0e7c | ||
|
|
b891025365 | ||
|
|
3c3f2a2e60 | ||
|
|
06b5e969db | ||
|
|
8508550ee6 | ||
|
|
5c1032c578 | ||
|
|
9febc66b98 | ||
|
|
59dc738b25 | ||
|
|
8524be7240 | ||
|
|
065a18c258 | ||
|
|
79279ccb31 | ||
|
|
7e1ef7457e | ||
|
|
af4919172a | ||
|
|
532e8f85b5 | ||
|
|
7c90501b8b | ||
|
|
5f1fb66f6f | ||
|
|
be80733cea | ||
|
|
8572a390f7 | ||
|
|
b2a41c64de | ||
|
|
11cf36d838 | ||
|
|
5d440e41da | ||
|
|
170b912d25 | ||
|
|
38a7952407 | ||
|
|
de90d92697 | ||
|
|
22ee79fcb8 | ||
|
|
03ffc8bc34 | ||
|
|
c4f2a6c5e6 | ||
|
|
ab9f7410c2 | ||
|
|
2c85a72737 | ||
|
|
3970a3a323 | ||
|
|
61d6ed42f5 | ||
|
|
bb11285c6f | ||
|
|
132f4e7192 | ||
|
|
6c596bf19b | ||
|
|
ea292aa958 | ||
|
|
33fa856b63 | ||
|
|
6065c5aa79 | ||
|
|
0771a597e6 | ||
|
|
693ffa9d28 | ||
|
|
1c39c04ac9 | ||
|
|
a27ef20cb7 | ||
|
|
5e2089eafb | ||
|
|
68fd4e245a | ||
|
|
b718809f3b | ||
|
|
26379a5589 | ||
|
|
8d37bcfa32 | ||
|
|
f168e1909b | ||
|
|
627d5c4bb6 | ||
|
|
29f3e7f430 | ||
|
|
8a7d5689e5 | ||
|
|
70ab46cd6e | ||
|
|
d8effad747 | ||
|
|
dc97765557 | ||
|
|
685371108d | ||
|
|
b6f1555176 | ||
|
|
deadf87be8 | ||
|
|
1d75661e45 | ||
|
|
6a78560d28 | ||
|
|
9c4df129c6 | ||
|
|
21c8dfbb69 | ||
|
|
8c93f05fa9 | ||
|
|
ef98a040c8 | ||
|
|
bcd8e65416 | ||
|
|
79ab71bcf9 | ||
|
|
a67c482a87 | ||
|
|
7d89cbfd07 | ||
|
|
0b73f44190 | ||
|
|
5751990e1a | ||
|
|
6d1d8c1271 | ||
|
|
81a311281e | ||
|
|
71647cee9a | ||
|
|
2487019631 | ||
|
|
885a35eebf | ||
|
|
d36c523e67 | ||
|
|
43b05fb948 | ||
|
|
6856337c57 | ||
|
|
2b603bedcd | ||
|
|
e43ebfa5bf | ||
|
|
c914acb34d | ||
|
|
982713606e | ||
|
|
63c0d0afe5 | ||
|
|
4407939ea3 | ||
|
|
ee6df13f57 | ||
|
|
97f9aca039 | ||
|
|
f30e3f89ed | ||
|
|
f220644263 | ||
|
|
9e066ebc7b | ||
|
|
855f7724be | ||
|
|
33d1e950a9 | ||
|
|
ec57c11356 | ||
|
|
f0d7f0adca | ||
|
|
9f4d31a8c4 | ||
|
|
95eafd32f9 | ||
|
|
86dbbf7254 | ||
|
|
b13ec2ddb4 | ||
|
|
0f7a876dae | ||
|
|
837ff33ee0 | ||
|
|
4735f54368 | ||
|
|
35c9128bca | ||
|
|
411bce81c0 | ||
|
|
1ac286c3b0 | ||
|
|
b496853d32 | ||
|
|
9ca49aa442 | ||
|
|
bc809cd763 | ||
|
|
046ac8a4a5 | ||
|
|
c38f357872 | ||
|
|
95be17be1d | ||
|
|
5c30dfefc7 | ||
|
|
d1829ea9ec | ||
|
|
06f2276501 | ||
|
|
13f7ec7ba1 | ||
|
|
e9d5f7965f | ||
|
|
6596ed08de | ||
|
|
4c0dfaef0e | ||
|
|
36e5ceaee2 | ||
|
|
5281c2d9a8 | ||
|
|
7411da595c | ||
|
|
44f8ae96eb | ||
|
|
0cab9bf6b2 | ||
|
|
7111121165 | ||
|
|
9299a2d1f3 | ||
|
|
8d90770909 | ||
|
|
16a9f6f84c | ||
|
|
6f4447fb8b | ||
|
|
70e31587bb | ||
|
|
6dca3b2743 | ||
|
|
5cd072243d | ||
|
|
fbf20b8ac1 | ||
|
|
5833d41e85 | ||
|
|
a77b43479a | ||
|
|
3b884b02c9 | ||
|
|
1a56086320 | ||
|
|
692df9e5b7 | ||
|
|
103929b14a | ||
|
|
d3865f9247 | ||
|
|
3507958932 | ||
|
|
a8b8bad0e4 | ||
|
|
26a630c0b4 | ||
|
|
76c18c588f | ||
|
|
df5ece51ef | ||
|
|
f7d1c5639c | ||
|
|
20a136a73c | ||
|
|
f43f9b2eb6 | ||
|
|
9a46ed3182 | ||
|
|
82b7007c5d | ||
|
|
806f0dbe82 | ||
|
|
936018e5bb | ||
|
|
1b4131b5ad | ||
|
|
b98a9dcc1a | ||
|
|
8860e57362 | ||
|
|
f1ecea6b53 | ||
|
|
ebc6493990 | ||
|
|
a2f9216fe4 | ||
|
|
27436ed538 | ||
|
|
c103a50423 | ||
|
|
5ac16f0f98 | ||
|
|
b4138fdb4d | ||
|
|
a2e6fd0ef1 | ||
|
|
c2aaf7a962 | ||
|
|
a066ff5385 | ||
|
|
113360052b | ||
|
|
a24e3e539c | ||
|
|
ed8a14d4d9 | ||
|
|
d2798e1a24 | ||
|
|
369014455c | ||
|
|
db1b8a7acd | ||
|
|
cc9231ae10 | ||
|
|
03ba47a0be | ||
|
|
ab953493ee | ||
|
|
c04ee365e6 | ||
|
|
26e8935520 | ||
|
|
dd027359e6 | ||
|
|
cf26a9cefc | ||
|
|
026b40876c | ||
|
|
fd1814052a | ||
|
|
98c2853ec3 | ||
|
|
b2ca15b8af | ||
|
|
55e7178dad | ||
|
|
ea55d3facf | ||
|
|
a72aa7a184 | ||
|
|
b4248cae1e | ||
|
|
7d2bc4905a | ||
|
|
f75f6e9fbc | ||
|
|
713d1094a2 | ||
|
|
3197ad3e45 | ||
|
|
92f415d633 | ||
|
|
0352a3c822 | ||
|
|
5ba5808722 | ||
|
|
1d416a8513 | ||
|
|
95028a0fb0 | ||
|
|
b45cc75329 | ||
|
|
79bbf76ece | ||
|
|
a8c7300174 | ||
|
|
a60f28ac2f | ||
|
|
adba061f77 | ||
|
|
8f15e4e00a | ||
|
|
07db5a6583 | ||
|
|
3e6d61e77e | ||
|
|
c7c7d699c9 | ||
|
|
067751c67d | ||
|
|
73b658d711 | ||
|
|
e5516b38cb | ||
|
|
39130004d5 | ||
|
|
d4b615e3a2 | ||
|
|
98e133a7be | ||
|
|
7674b76dab | ||
|
|
8fa39d90be | ||
|
|
638bdc8e83 | ||
|
|
b565a67dec | ||
|
|
65d077291b | ||
|
|
e9d11c247e | ||
|
|
126ac55801 | ||
|
|
306aac3e65 | ||
|
|
55318b0c20 | ||
|
|
1865faf7ce | ||
|
|
9edd7abbe8 | ||
|
|
1c4acc0b33 | ||
|
|
6274f16b9b | ||
|
|
93e338a964 | ||
|
|
73b03b77fc | ||
|
|
0135757fbd | ||
|
|
ea1fe87d49 | ||
|
|
363a6a8fe6 | ||
|
|
8491738c8a | ||
|
|
361179fad9 | ||
|
|
13eb7c42cd | ||
|
|
e4ecd98b83 | ||
|
|
5e747d3e08 | ||
|
|
c6425ac1f8 | ||
|
|
7f5b8817ca | ||
|
|
fb999f828f | ||
|
|
ba12154f68 | ||
|
|
73e0ee798f | ||
|
|
2c7029cf35 | ||
|
|
50c35833dc | ||
|
|
7a8b7d6a5c | ||
|
|
2a36e84bf2 | ||
|
|
3802fb427a | ||
|
|
b4ea2afc19 | ||
|
|
6ba7ddc83f | ||
|
|
af6868a8de | ||
|
|
910e7139f9 | ||
|
|
fe65869b6b | ||
|
|
2a319d9d0d | ||
|
|
48402eff7e | ||
|
|
15600cc7d3 | ||
|
|
ed2a774e10 | ||
|
|
1d590c07cb | ||
|
|
948de81ed3 | ||
|
|
78658c0311 | ||
|
|
7b6f11780a | ||
|
|
d65044ff2e | ||
|
|
18c63ad7f7 | ||
|
|
a8260081d9 | ||
|
|
0ff49e5057 | ||
|
|
79cfe56484 | ||
|
|
7e36892e26 | ||
|
|
3d6d0bed69 | ||
|
|
b213e0af0a | ||
|
|
42ad3faf5a | ||
|
|
939fd5b24d | ||
|
|
36ec3ef378 | ||
|
|
287e005129 | ||
|
|
0b3e88d6de | ||
|
|
10139749da | ||
|
|
f891e0683b | ||
|
|
647b4cba04 | ||
|
|
c5df50c774 | ||
|
|
2b1d325343 | ||
|
|
319d57cb68 | ||
|
|
087da02dbb | ||
|
|
7d00f68180 | ||
|
|
87c9bb8ba2 | ||
|
|
5fb970b526 | ||
|
|
56b404bd84 | ||
|
|
a12d0a1ed7 | ||
|
|
51979787b0 | ||
|
|
8b37756118 | ||
|
|
1eb1da110b | ||
|
|
d1ed907f1e | ||
|
|
8e6eccecda | ||
|
|
f3db1adb27 | ||
|
|
7f3e11c1ce | ||
|
|
a7eb7e4995 | ||
|
|
43194bb342 | ||
|
|
c7d21968e7 | ||
|
|
214a19fb0f | ||
|
|
82ea2fa993 | ||
|
|
d84913c31e | ||
|
|
6bac5ffaa2 | ||
|
|
eacf909c4a | ||
|
|
f7c1669125 | ||
|
|
158d6e82da | ||
|
|
4d890382e5 | ||
|
|
83842e01f7 | ||
|
|
37b453fbbc | ||
|
|
53c6b472de | ||
|
|
c759f958c0 | ||
|
|
5d14183809 | ||
|
|
ab74d6ef0b | ||
|
|
fefcae34c1 | ||
|
|
ed81a06a82 | ||
|
|
633982b0e5 | ||
|
|
4154e01fdd | ||
|
|
02d7f06d35 | ||
|
|
555450868e | ||
|
|
94085d6dc6 | ||
|
|
630841d81b | ||
|
|
ea7f4fcdf7 | ||
|
|
e97c926611 | ||
|
|
2479134e78 | ||
|
|
b0bbd16a77 | ||
|
|
7564949695 | ||
|
|
d34da2ab91 | ||
|
|
182156d9b4 |
@@ -1,104 +0,0 @@
|
|||||||
version: 2.1
|
|
||||||
jobs:
|
|
||||||
e2e-kubernetes:
|
|
||||||
machine: true
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: e2e/bootstrap.sh
|
|
||||||
- run: e2e/install.sh
|
|
||||||
- run: e2e/test.sh
|
|
||||||
|
|
||||||
build-container:
|
|
||||||
docker:
|
|
||||||
- image: circleci/golang:1.12
|
|
||||||
working_directory: ~/build
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- setup_remote_docker:
|
|
||||||
docker_layer_caching: true
|
|
||||||
- run: make build-container
|
|
||||||
- run: |
|
|
||||||
if [ -z "$CIRCLE_TAG" ]; then
|
|
||||||
echo "Not a release, skipping container push";
|
|
||||||
else
|
|
||||||
echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin;
|
|
||||||
echo $QUAY_PASS | docker login -u $QUAY_USER --password-stdin quay.io;
|
|
||||||
make push-container;
|
|
||||||
fi
|
|
||||||
|
|
||||||
push-binary:
|
|
||||||
docker:
|
|
||||||
- image: circleci/golang:1.12
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: curl -sL https://git.io/goreleaser | bash
|
|
||||||
|
|
||||||
push-helm-charts:
|
|
||||||
docker:
|
|
||||||
- image: circleci/golang:1.12
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run:
|
|
||||||
name: Install kubectl
|
|
||||||
command: sudo curl -L https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl -o /usr/local/bin/kubectl && sudo chmod +x /usr/local/bin/kubectl
|
|
||||||
- run:
|
|
||||||
name: Install helm
|
|
||||||
command: sudo curl -L https://storage.googleapis.com/kubernetes-helm/helm-v2.14.2-linux-amd64.tar.gz | tar xz && sudo mv linux-amd64/helm /bin/helm && sudo rm -rf linux-amd64
|
|
||||||
- run:
|
|
||||||
name: Initialize helm
|
|
||||||
command: helm init --client-only --kubeconfig=$HOME/.kube/kubeconfig
|
|
||||||
- run:
|
|
||||||
name: Lint charts
|
|
||||||
command: |
|
|
||||||
helm lint ./charts/*
|
|
||||||
- run:
|
|
||||||
name: Package charts
|
|
||||||
command: |
|
|
||||||
mkdir $HOME/charts
|
|
||||||
helm package ./charts/* --destination $HOME/charts
|
|
||||||
- run:
|
|
||||||
name: Publish charts
|
|
||||||
command: |
|
|
||||||
if echo "${CIRCLE_TAG}" | grep -Eq "[0-9]+(\.[0-9]+)*(-[a-z]+)?$"; then
|
|
||||||
REPOSITORY="https://stefanprodan:${GITHUB_TOKEN}@github.com/stefanprodan/podinfo.git"
|
|
||||||
git config user.email stefanprodan@users.noreply.github.com
|
|
||||||
git config user.name stefanprodan
|
|
||||||
git remote set-url origin ${REPOSITORY}
|
|
||||||
git checkout gh-pages
|
|
||||||
mv -f $HOME/charts/*.tgz .
|
|
||||||
helm repo index . --url https://stefanprodan.github.io/podinfo
|
|
||||||
git add .
|
|
||||||
git commit -m "Publish Helm charts v${CIRCLE_TAG}"
|
|
||||||
git push origin gh-pages
|
|
||||||
else
|
|
||||||
echo "Not a release! Skip charts publish"
|
|
||||||
fi
|
|
||||||
|
|
||||||
workflows:
|
|
||||||
version: 2
|
|
||||||
build-test:
|
|
||||||
jobs:
|
|
||||||
- build-container
|
|
||||||
- e2e-kubernetes
|
|
||||||
release:
|
|
||||||
jobs:
|
|
||||||
- build-container:
|
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
ignore: /.*/
|
|
||||||
tags:
|
|
||||||
ignore: /^chart.*/
|
|
||||||
- push-binary:
|
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
ignore: /.*/
|
|
||||||
tags:
|
|
||||||
ignore: /^chart.*/
|
|
||||||
- push-helm-charts:
|
|
||||||
requires:
|
|
||||||
- build-container
|
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
ignore: /.*/
|
|
||||||
tags:
|
|
||||||
ignore: /^chart.*/
|
|
||||||
61
.cosign/README.md
Normal file
61
.cosign/README.md
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# Podinfo signed releases
|
||||||
|
|
||||||
|
Podinfo release assets (container image, Helm chart, Flux artifact, Timoni module)
|
||||||
|
are published to GitHub Container Registry and are signed with
|
||||||
|
[Cosign v2](https://github.com/sigstore/cosign) keyless & GitHub Actions OIDC.
|
||||||
|
|
||||||
|
## Verify podinfo with cosign
|
||||||
|
|
||||||
|
Install the [cosign](https://github.com/sigstore/cosign) CLI:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
brew install sigstore/tap/cosign
|
||||||
|
```
|
||||||
|
|
||||||
|
### Container image
|
||||||
|
|
||||||
|
Verify the podinfo container image hosted on GHCR:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cosign verify ghcr.io/stefanprodan/podinfo:6.5.0 \
|
||||||
|
--certificate-identity-regexp="^https://github.com/stefanprodan/podinfo.*$" \
|
||||||
|
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify the podinfo container image hosted on Docker Hub:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cosign verify docker.io/stefanprodan/podinfo:6.5.0 \
|
||||||
|
--certificate-identity-regexp="^https://github.com/stefanprodan/podinfo.*$" \
|
||||||
|
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### Helm chart
|
||||||
|
|
||||||
|
Verify the podinfo [Helm](https://helm.sh) chart hosted on GHCR:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cosign verify ghcr.io/stefanprodan/charts/podinfo:6.5.0 \
|
||||||
|
--certificate-identity-regexp="^https://github.com/stefanprodan/podinfo.*$" \
|
||||||
|
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### Flux artifact
|
||||||
|
|
||||||
|
Verify the podinfo [Flux](https://fluxcd.io) artifact hosted on GHCR:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cosign verify ghcr.io/stefanprodan/manifests/podinfo:6.5.0 \
|
||||||
|
--certificate-identity-regexp="^https://github.com/stefanprodan/podinfo.*$" \
|
||||||
|
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### Timoni module
|
||||||
|
|
||||||
|
Verify the podinfo [Timoni](https://timoni.sh) module hosted on GHCR:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cosign verify ghcr.io/stefanprodan/modules/podinfo:6.5.0 \
|
||||||
|
--certificate-identity-regexp="^https://github.com/stefanprodan/podinfo.*$" \
|
||||||
|
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
|
||||||
|
```
|
||||||
4
.cosign/cosign.pub
Normal file
4
.cosign/cosign.pub
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEST+BqQ1XZhhVYx0YWQjdUJYIG5Lt
|
||||||
|
iz2+UxRIqmKBqNmce2T+l45qyqOs99qfD7gLNGmkVZ4vtJ9bM7FxChFczg==
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
timoni/podinfo/cue.mod/** linguist-vendored
|
||||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
github: stefanprodan
|
||||||
38
.github/actions/kubeconform/action.yml
vendored
Normal file
38
.github/actions/kubeconform/action.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
name: Setup kubeconform
|
||||||
|
description: A GitHub Action for running kubeconform commands
|
||||||
|
author: Stefan Prodan
|
||||||
|
branding:
|
||||||
|
color: blue
|
||||||
|
icon: command
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: "kubeconform version e.g. 0.5.0 (defaults to latest stable release)"
|
||||||
|
required: false
|
||||||
|
arch:
|
||||||
|
description: "arch can be amd64 or arm64"
|
||||||
|
required: true
|
||||||
|
default: "amd64"
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: "Download binary to the GH runner cache"
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
ARCH=${{ inputs.arch }}
|
||||||
|
VERSION=${{ inputs.version }}
|
||||||
|
|
||||||
|
if [ -z $VERSION ]; then
|
||||||
|
VERSION=$(curl https://api.github.com/repos/yannh/kubeconform/releases/latest -sL | grep tag_name | sed -E 's/.*"([^"]+)".*/\1/' | cut -c 2-)
|
||||||
|
fi
|
||||||
|
|
||||||
|
BIN_URL="https://github.com/yannh/kubeconform/releases/download/v${VERSION}/kubeconform-linux-${ARCH}.tar.gz"
|
||||||
|
BIN_DIR=$RUNNER_TOOL_CACHE/kubeconform/$VERSION/$ARCH
|
||||||
|
|
||||||
|
if [[ ! -x "$BIN_DIR/kind" ]]; then
|
||||||
|
mkdir -p $BIN_DIR
|
||||||
|
cd $BIN_DIR
|
||||||
|
curl -sL $BIN_URL | tar xz
|
||||||
|
chmod +x kubeconform
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$BIN_DIR" >> "$GITHUB_PATH"
|
||||||
24
.github/actions/runner-cleanup/action.yml
vendored
Normal file
24
.github/actions/runner-cleanup/action.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
name: Runner Cleanup
|
||||||
|
description: A GitHub Action for removing bloat from Ubuntu GitHub Actions runner.
|
||||||
|
author: Stefan Prodan
|
||||||
|
branding:
|
||||||
|
color: blue
|
||||||
|
icon: command
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: "Disk Usage Before Cleanup"
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
df -h
|
||||||
|
- name: "Remove .NET, Android and Haskell"
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo rm -rf /usr/share/dotnet || true
|
||||||
|
sudo rm -rf /usr/local/lib/android || true
|
||||||
|
sudo rm -rf /opt/ghc || true
|
||||||
|
sudo rm -rf /usr/local/.ghcup || true
|
||||||
|
- name: "Disk Usage After Cleanup"
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
df -h
|
||||||
11
.github/dependabot.yaml
vendored
Normal file
11
.github/dependabot.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
version: 2
|
||||||
|
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
groups:
|
||||||
|
actions:
|
||||||
|
patterns:
|
||||||
|
- "*"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
25
.github/workflows/cve-scan.yml
vendored
Normal file
25
.github/workflows/cve-scan.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
name: cve-scan
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "master"
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- "master"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
govulncheck:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
- uses: ./.github/actions/runner-cleanup
|
||||||
|
- name: Vulnerability scan
|
||||||
|
id: govulncheck
|
||||||
|
uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # v1.0.4
|
||||||
|
with:
|
||||||
|
repo-checkout: false
|
||||||
80
.github/workflows/e2e.yml
vendored
Normal file
80
.github/workflows/e2e.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
name: e2e
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
kind-helm:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
- name: Disk Cleanup
|
||||||
|
uses: ./.github/actions/runner-cleanup
|
||||||
|
- name: Setup Kubernetes
|
||||||
|
uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0
|
||||||
|
with:
|
||||||
|
cluster_name: kind
|
||||||
|
- name: Build container image
|
||||||
|
run: |
|
||||||
|
./test/build.sh
|
||||||
|
kind load docker-image test/podinfo:latest
|
||||||
|
- name: Setup Helm
|
||||||
|
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0
|
||||||
|
with:
|
||||||
|
version: v4.1.0
|
||||||
|
- name: Deploy
|
||||||
|
run: ./test/deploy.sh
|
||||||
|
- name: Run integration tests
|
||||||
|
run: ./test/test.sh
|
||||||
|
- name: Debug failure
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
kubectl logs -l app=podinfo || true
|
||||||
|
kind-timoni:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
services:
|
||||||
|
registry:
|
||||||
|
image: registry:2
|
||||||
|
ports:
|
||||||
|
- 5000:5000
|
||||||
|
env:
|
||||||
|
PODINFO_IMAGE_URL: "test/podinfo"
|
||||||
|
PODINFO_MODULE_URL: "oci://localhost:5000/podinfo"
|
||||||
|
PODINFO_VERSION: "0.0.0-devel"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
- uses: ./.github/actions/runner-cleanup
|
||||||
|
- name: Setup Timoni
|
||||||
|
uses: stefanprodan/timoni/actions/setup@c68e33a34f17c7ca93c7fc6717d61a14819276dc # v0.26.0
|
||||||
|
- name: Setup Kubernetes
|
||||||
|
uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0
|
||||||
|
with:
|
||||||
|
cluster_name: kind
|
||||||
|
- name: Build container
|
||||||
|
run: |
|
||||||
|
docker build -t ${PODINFO_IMAGE_URL}:${PODINFO_VERSION} --build-arg "REVISION=${GITHUB_SHA}" -f Dockerfile.xx .
|
||||||
|
kind load docker-image ${PODINFO_IMAGE_URL}:${PODINFO_VERSION}
|
||||||
|
- name: Vet module
|
||||||
|
run: |
|
||||||
|
timoni mod vet ./timoni/podinfo --debug
|
||||||
|
- name: Build module
|
||||||
|
run: |
|
||||||
|
timoni mod push ./timoni/podinfo ${PODINFO_MODULE_URL} -v ${PODINFO_VERSION}
|
||||||
|
- name: Apply bundle
|
||||||
|
run: |
|
||||||
|
timoni bundle apply -f ./timoni/bundles/test.podinfo.cue --runtime-from-env
|
||||||
|
- name: Verify status
|
||||||
|
run: |
|
||||||
|
timoni -n podinfo status backend
|
||||||
|
timoni -n podinfo status frontend
|
||||||
|
- name: Debug failure
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
kubectl -n podinfo get all || true
|
||||||
171
.github/workflows/release.yml
vendored
Normal file
171
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
name: release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write # needed to write releases
|
||||||
|
id-token: write # needed for keyless signing
|
||||||
|
packages: write # needed for ghcr access
|
||||||
|
attestations: write # needed for provenance
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
- uses: ./.github/actions/runner-cleanup
|
||||||
|
- uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1
|
||||||
|
- uses: fluxcd/flux2/action@871be9b40d53627786d3a3835a3ddba1e3234bd2 # v2.8.3
|
||||||
|
- uses: stefanprodan/timoni/actions/setup@c68e33a34f17c7ca93c7fc6717d61a14819276dc # v0.26.0
|
||||||
|
- name: Setup Notation CLI
|
||||||
|
uses: notaryproject/notation-action/setup@b6fee73110795d6793253c673bd723f12bcf9bbb # v1.2.2
|
||||||
|
with:
|
||||||
|
version: "1.1.0"
|
||||||
|
- name: Setup Notation signing keys
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.config/notation/localkeys/
|
||||||
|
cp ./.notation/signingkeys.json ~/.config/notation/
|
||||||
|
cp ./.notation/notation.crt ~/.config/notation/localkeys/
|
||||||
|
echo "$NOTATION_KEY" > ~/.config/notation/localkeys/notation.key
|
||||||
|
env:
|
||||||
|
NOTATION_KEY: ${{ secrets.NOTATION_SIGNING_KEY }}
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||||
|
with:
|
||||||
|
go-version: 1.26.x
|
||||||
|
- name: Setup Helm
|
||||||
|
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0
|
||||||
|
with:
|
||||||
|
version: v4.1.1
|
||||||
|
- name: Setup QEMU
|
||||||
|
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
||||||
|
with:
|
||||||
|
platforms: all
|
||||||
|
- name: Setup Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
- name: Prepare
|
||||||
|
id: prep
|
||||||
|
run: |
|
||||||
|
VERSION=sha-${GITHUB_SHA::8}
|
||||||
|
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||||
|
VERSION=${GITHUB_REF/refs\/tags\//}
|
||||||
|
fi
|
||||||
|
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
|
||||||
|
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
|
||||||
|
echo "REVISION=${GITHUB_SHA}" >> $GITHUB_OUTPUT
|
||||||
|
- name: Generate images meta
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
docker.io/stefanprodan/podinfo
|
||||||
|
ghcr.io/stefanprodan/podinfo
|
||||||
|
tags: |
|
||||||
|
type=raw,value=${{ steps.prep.outputs.VERSION }}
|
||||||
|
type=raw,value=latest
|
||||||
|
- name: Publish multi-arch image
|
||||||
|
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
|
||||||
|
with:
|
||||||
|
sbom: true
|
||||||
|
provenance: true
|
||||||
|
push: true
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile.xx
|
||||||
|
build-args: |
|
||||||
|
REVISION=${{ steps.prep.outputs.REVISION }}
|
||||||
|
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
- name: Publish Timoni module to GHCR
|
||||||
|
run: |
|
||||||
|
timoni mod push ./timoni/podinfo oci://ghcr.io/stefanprodan/modules/podinfo \
|
||||||
|
--sign cosign \
|
||||||
|
--version ${{ steps.prep.outputs.VERSION }} \
|
||||||
|
-a 'org.opencontainers.image.source=https://github.com/stefanprodan/podinfo' \
|
||||||
|
-a 'org.opencontainers.image.licenses=Apache-2.0' \
|
||||||
|
-a 'org.opencontainers.image.description=A timoni.sh module for deploying Podinfo.' \
|
||||||
|
-a 'org.opencontainers.image.documentation=https://github.com/stefanprodan/podinfo/blob/main/timoni/podinfo/README.md'
|
||||||
|
- name: Publish Helm chart to GHCR
|
||||||
|
run: |
|
||||||
|
helm package charts/podinfo
|
||||||
|
helm push podinfo-${{ steps.prep.outputs.VERSION }}.tgz oci://ghcr.io/stefanprodan/charts
|
||||||
|
rm podinfo-${{ steps.prep.outputs.VERSION }}.tgz
|
||||||
|
- name: Publish Flux OCI artifact to GHCR
|
||||||
|
run: |
|
||||||
|
flux push artifact oci://ghcr.io/stefanprodan/manifests/podinfo:${{ steps.prep.outputs.VERSION }} \
|
||||||
|
--path="./kustomize" \
|
||||||
|
--source="${{ github.event.repository.html_url }}" \
|
||||||
|
--revision="${GITHUB_REF_NAME}/${GITHUB_SHA}"
|
||||||
|
flux tag artifact oci://ghcr.io/stefanprodan/manifests/podinfo:${{ steps.prep.outputs.VERSION }} --tag latest
|
||||||
|
- name: Sign artifacts with Cosign
|
||||||
|
env:
|
||||||
|
COSIGN_EXPERIMENTAL: 1
|
||||||
|
run: |
|
||||||
|
cosign sign docker.io/stefanprodan/podinfo:${{ steps.prep.outputs.VERSION }} --yes
|
||||||
|
cosign sign ghcr.io/stefanprodan/podinfo:${{ steps.prep.outputs.VERSION }} --yes
|
||||||
|
cosign sign ghcr.io/stefanprodan/charts/podinfo:${{ steps.prep.outputs.VERSION }} --yes
|
||||||
|
cosign sign ghcr.io/stefanprodan/manifests/podinfo:${{ steps.prep.outputs.VERSION }} --yes
|
||||||
|
- name: Publish base image
|
||||||
|
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
|
||||||
|
with:
|
||||||
|
push: true
|
||||||
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64
|
||||||
|
file: ./Dockerfile.base
|
||||||
|
tags: docker.io/stefanprodan/podinfo-base:latest
|
||||||
|
- name: Publish helm chart
|
||||||
|
uses: stefanprodan/helm-gh-pages@0ad2bb377311d61ac04ad9eb6f252fb68e207260 # v1.7.0
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Publish config artifact
|
||||||
|
run: |
|
||||||
|
flux push artifact oci://ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }} \
|
||||||
|
--path="./kustomize" \
|
||||||
|
--source="${{ github.event.repository.html_url }}" \
|
||||||
|
--revision="${GITHUB_REF_NAME}/${GITHUB_SHA}"
|
||||||
|
flux tag artifact oci://ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }} --tag latest
|
||||||
|
- name: Sign config artifact with cso
|
||||||
|
run: |
|
||||||
|
echo "$COSIGN_KEY" > /tmp/cosign.key
|
||||||
|
cosign sign -key /tmp/cosign.key ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }} --yes
|
||||||
|
cosign sign -key /tmp/cosign.key ghcr.io/stefanprodan/podinfo-deploy:latest --yes
|
||||||
|
env:
|
||||||
|
COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}}
|
||||||
|
COSIGN_KEY: ${{secrets.COSIGN_KEY}}
|
||||||
|
- name: Sign artifacts with Notation
|
||||||
|
run: |
|
||||||
|
notation sign --signature-format cose ghcr.io/stefanprodan/podinfo:${{ steps.prep.outputs.VERSION }}
|
||||||
|
notation sign --signature-format cose ghcr.io/stefanprodan/charts/podinfo:${{ steps.prep.outputs.VERSION }}
|
||||||
|
notation sign --signature-format cose ghcr.io/stefanprodan/manifests/podinfo:${{ steps.prep.outputs.VERSION }}
|
||||||
|
notation sign --signature-format cose ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }}
|
||||||
|
notation sign --signature-format cose ghcr.io/stefanprodan/podinfo-deploy:latest
|
||||||
|
- name: Publish release
|
||||||
|
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
args: release --skip=validate
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Attest release
|
||||||
|
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
|
||||||
|
with:
|
||||||
|
subject-checksums: ./dist/podinfo_${{ steps.prep.outputs.VERSION }}_checksums.txt
|
||||||
73
.github/workflows/test.yml
vendored
Normal file
73
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
name: test
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
env:
|
||||||
|
KUBERNETES_VERSION: 1.35.0
|
||||||
|
HELM_VERSION: 4.1.1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
- uses: ./.github/actions/runner-cleanup
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||||
|
with:
|
||||||
|
go-version: 1.26.x
|
||||||
|
cache-dependency-path: |
|
||||||
|
**/go.sum
|
||||||
|
**/go.mod
|
||||||
|
- name: Setup kubectl
|
||||||
|
uses: azure/setup-kubectl@15650b3ad78fff148532a140b8a4c821796b2d7b # v5.0.0
|
||||||
|
with:
|
||||||
|
version: v${{ env.KUBERNETES_VERSION }}
|
||||||
|
- name: Setup kubeconform
|
||||||
|
uses: ./.github/actions/kubeconform
|
||||||
|
- name: Setup Helm
|
||||||
|
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0
|
||||||
|
with:
|
||||||
|
version: v${{ env.HELM_VERSION }}
|
||||||
|
- name: Setup CUE
|
||||||
|
uses: cue-lang/setup-cue@a93fa358375740cd8b0078f76355512b9208acb1 # v1.0.1
|
||||||
|
- name: Setup Timoni
|
||||||
|
uses: stefanprodan/timoni/actions/setup@c68e33a34f17c7ca93c7fc6717d61a14819276dc # v0.26.0
|
||||||
|
- name: Run unit tests
|
||||||
|
run: make test
|
||||||
|
- name: Validate Helm chart
|
||||||
|
run: |
|
||||||
|
helm lint ./charts/podinfo/
|
||||||
|
helm template ./charts/podinfo/ | kubeconform -strict -summary -kubernetes-version ${{ env.KUBERNETES_VERSION }}
|
||||||
|
- name: Validate Kustomize overlay
|
||||||
|
run: |
|
||||||
|
kubectl kustomize ./kustomize/ | kubeconform -strict -summary -kubernetes-version ${{ env.KUBERNETES_VERSION }}
|
||||||
|
- name: Verify CUE formatting
|
||||||
|
working-directory: ./timoni/podinfo
|
||||||
|
run: |
|
||||||
|
cue fmt ./...
|
||||||
|
status=$(git status . --porcelain)
|
||||||
|
[[ -z "$status" ]] || {
|
||||||
|
echo "CUE files are not correctly formatted"
|
||||||
|
echo "$status"
|
||||||
|
git diff
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
- name: Validate Timoni module
|
||||||
|
working-directory: ./timoni/podinfo
|
||||||
|
run: |
|
||||||
|
timoni mod lint .
|
||||||
|
timoni build podinfo . -f test_values.cue | kubeconform -strict -summary -skip=ServiceMonitor -kubernetes-version ${{ env.KUBERNETES_VERSION }}
|
||||||
|
- name: Check if working tree is dirty
|
||||||
|
run: |
|
||||||
|
if [[ $(git diff --stat) != '' ]]; then
|
||||||
|
echo 'run make test and commit changes'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -19,4 +19,10 @@ release/
|
|||||||
build/
|
build/
|
||||||
gcloud/
|
gcloud/
|
||||||
dist/
|
dist/
|
||||||
bin/
|
bin/
|
||||||
|
cue/cue.mod/gen/
|
||||||
|
cue/go.mod
|
||||||
|
cue/go.sum
|
||||||
|
|
||||||
|
.notation/podinfo.csr
|
||||||
|
.notation/podinfo.key
|
||||||
|
|||||||
@@ -1,3 +1,18 @@
|
|||||||
|
version: 2
|
||||||
|
|
||||||
|
# xref: https://goreleaser.com/customization/project/
|
||||||
|
project_name: podinfo
|
||||||
|
|
||||||
|
# xref: https://goreleaser.com/customization/hooks/
|
||||||
|
before:
|
||||||
|
hooks:
|
||||||
|
- go mod download
|
||||||
|
|
||||||
|
# xref: https://goreleaser.com/customization/env/
|
||||||
|
env:
|
||||||
|
- CGO_ENABLED=0
|
||||||
|
|
||||||
|
# xref: https://goreleaser.com/customization/build/
|
||||||
builds:
|
builds:
|
||||||
- main: ./cmd/podcli
|
- main: ./cmd/podcli
|
||||||
binary: podcli
|
binary: podcli
|
||||||
@@ -8,9 +23,13 @@ builds:
|
|||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- amd64
|
- amd64
|
||||||
env:
|
|
||||||
- CGO_ENABLED=0
|
# xref: https://goreleaser.com/customization/archive/
|
||||||
archives:
|
archives:
|
||||||
- name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
|
- name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
|
||||||
files:
|
files:
|
||||||
- none*
|
- LICENSE
|
||||||
|
|
||||||
|
# xref: https://goreleaser.com/customization/changelog/
|
||||||
|
changelog:
|
||||||
|
use: github-native
|
||||||
|
|||||||
15
.notation/README.md
Normal file
15
.notation/README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Podinfo signed releases
|
||||||
|
|
||||||
|
Podinfo release assets such as the Helm chart and the Flux artifact
|
||||||
|
are published to GitHub Container Registry and are signed with
|
||||||
|
[Notation](https://github.com/notaryproject/notation).
|
||||||
|
|
||||||
|
## Generate signing keys
|
||||||
|
|
||||||
|
Generate a new signing key pair:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
openssl genrsa -out podinfo.key 2048
|
||||||
|
openssl req -new -key podinfo.key -out podinfo.csr -config codesign.cnf
|
||||||
|
openssl x509 -req -days 1826 -in podinfo.csr -signkey podinfo.key -out notation.crt -extensions v3_req -extfile codesign.cnf
|
||||||
|
```
|
||||||
18
.notation/codesign.cnf
Normal file
18
.notation/codesign.cnf
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[ req ]
|
||||||
|
default_bits = 2048
|
||||||
|
default_keyfile = privatekey.pem
|
||||||
|
distinguished_name = req_distinguished_name
|
||||||
|
req_extensions = v3_req
|
||||||
|
prompt = no
|
||||||
|
|
||||||
|
[ req_distinguished_name ]
|
||||||
|
C = RO
|
||||||
|
ST = BU
|
||||||
|
L = Bucharest
|
||||||
|
O = Notary
|
||||||
|
CN = stefanprodan.com
|
||||||
|
|
||||||
|
[ v3_req ]
|
||||||
|
keyUsage = critical,digitalSignature
|
||||||
|
extendedKeyUsage = critical,codeSigning
|
||||||
|
#subjectKeyIdentifier = hash
|
||||||
21
.notation/notation.crt
Normal file
21
.notation/notation.crt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDbDCCAlSgAwIBAgIUP7zhmTw5XTWLcgBGkBEsErMOkz4wDQYJKoZIhvcNAQEL
|
||||||
|
BQAwWjELMAkGA1UEBhMCUk8xCzAJBgNVBAgMAkJVMRIwEAYDVQQHDAlCdWNoYXJl
|
||||||
|
c3QxDzANBgNVBAoMBk5vdGFyeTEZMBcGA1UEAwwQc3RlZmFucHJvZGFuLmNvbTAe
|
||||||
|
Fw0yNDAyMjUxMDAyMzZaFw0yOTAyMjQxMDAyMzZaMFoxCzAJBgNVBAYTAlJPMQsw
|
||||||
|
CQYDVQQIDAJCVTESMBAGA1UEBwwJQnVjaGFyZXN0MQ8wDQYDVQQKDAZOb3Rhcnkx
|
||||||
|
GTAXBgNVBAMMEHN0ZWZhbnByb2Rhbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
||||||
|
DwAwggEKAoIBAQDtH4oPi3SyX/DGv6NdjIvmApvD9eeSgsmHdwpAly8T9D2me+fx
|
||||||
|
Z+wRNJmq4aq/A1anX+Sg28iwHzV+1WKpsHnjYzDAJSEYP2S8A5H1nGRKUoibdijw
|
||||||
|
C3QBh5C75rjF/tmZVSX/Vgbf3HJJEsF4WUxWabLxoV2QLo7UlEsQd9+bSeKNMncx
|
||||||
|
1+E6FdbRCrYo90iobvZJ8K/S2zCWq/JTeHfTnmSEDhx6nMJcaSjvMPn3zyauWcQw
|
||||||
|
dDpkcaGiJ64fEJRT2OFxXv9u+vDmIMKzo/Wjbd+IzFj6YY4VisK88aU7tmDelnk5
|
||||||
|
gQB9eu62PFoaVsYJp4VOhblFKvGJpQwbWB9BAgMBAAGjKjAoMA4GA1UdDwEB/wQE
|
||||||
|
AwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEA
|
||||||
|
6x+C6hAIbLwMvkNx4K5p7Qe/pLQR0VwQFAw10yr/5KSN+YKFpon6pQ0TebL7qll+
|
||||||
|
uBGZvtQhN6v+DlnVqB7lvJKd+89isgirkkews5KwuXg7Gv5UPIugH0dXISZU8DMJ
|
||||||
|
7J4oKREv5HzdFmfsUfNlQcfyVTjKL6UINXfKGdqNNxXxR9b4a1TY2JcmEhzBTHaq
|
||||||
|
ZqX6HK784a0dB7aHgeFrFwPCCP4M684Hs7CFbk3jo2Ef4ljnB5AyWpe8pwCLMdRt
|
||||||
|
UjSjL5xJWVQvRU+STQsPr6SvpokPCG4rLQyjgeYYk4CCj5piSxbSUZFavq8v1y7Y
|
||||||
|
m91USVqfeUX7ZzjDxPHE2A==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
10
.notation/signingkeys.json
Normal file
10
.notation/signingkeys.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"default": "stefanprodan.com",
|
||||||
|
"keys": [
|
||||||
|
{
|
||||||
|
"name": "stefanprodan.com",
|
||||||
|
"keyPath": "/home/runner/.config/notation/localkeys/notation.key",
|
||||||
|
"certPath": "/home/runner/.config/notation/localkeys/notation.crt"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
19
.notation/trustpolicy.json
Normal file
19
.notation/trustpolicy.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"version": "1.0",
|
||||||
|
"trustPolicies": [
|
||||||
|
{
|
||||||
|
"name": "stefanprodan.com",
|
||||||
|
"registryScopes": [
|
||||||
|
"ghcr.io/stefanprodan/podinfo-deploy",
|
||||||
|
"ghcr.io/stefanprodan/charts/podinfo"
|
||||||
|
],
|
||||||
|
"signatureVerification": {
|
||||||
|
"level" : "strict"
|
||||||
|
},
|
||||||
|
"trustStores": [ "ca:stefanprodan.com" ],
|
||||||
|
"trustedIdentities": [
|
||||||
|
"x509.subject: C=RO, ST=BU, L=Bucharest, O=Notary, CN=stefanprodan.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
30
Dockerfile
30
Dockerfile
@@ -1,4 +1,6 @@
|
|||||||
FROM golang:1.12 as builder
|
FROM golang:1.26-alpine AS builder
|
||||||
|
|
||||||
|
ARG REVISION
|
||||||
|
|
||||||
RUN mkdir -p /podinfo/
|
RUN mkdir -p /podinfo/
|
||||||
|
|
||||||
@@ -6,26 +8,28 @@ WORKDIR /podinfo
|
|||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN GOPROXY=https://proxy.golang.org go mod download
|
RUN go mod download
|
||||||
|
|
||||||
RUN go test -v -race ./...
|
RUN CGO_ENABLED=0 go build -ldflags "-s -w \
|
||||||
|
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \
|
||||||
RUN GIT_COMMIT=$(git rev-list -1 HEAD) && \
|
|
||||||
CGO_ENABLED=0 GOOS=linux go build -ldflags "-s -w \
|
|
||||||
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${GIT_COMMIT}" \
|
|
||||||
-a -o bin/podinfo cmd/podinfo/*
|
-a -o bin/podinfo cmd/podinfo/*
|
||||||
|
|
||||||
RUN GIT_COMMIT=$(git rev-list -1 HEAD) && \
|
RUN CGO_ENABLED=0 go build -ldflags "-s -w \
|
||||||
CGO_ENABLED=0 GOOS=linux go build -ldflags "-s -w \
|
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \
|
||||||
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${GIT_COMMIT}" \
|
|
||||||
-a -o bin/podcli cmd/podcli/*
|
-a -o bin/podcli cmd/podcli/*
|
||||||
|
|
||||||
FROM alpine:3.10
|
FROM alpine:3.23
|
||||||
|
|
||||||
|
ARG BUILD_DATE
|
||||||
|
ARG VERSION
|
||||||
|
ARG REVISION
|
||||||
|
|
||||||
|
LABEL maintainer="stefanprodan"
|
||||||
|
|
||||||
RUN addgroup -S app \
|
RUN addgroup -S app \
|
||||||
&& adduser -S -g app app \
|
&& adduser -S -G app app \
|
||||||
&& apk --no-cache add \
|
&& apk --no-cache add \
|
||||||
curl openssl netcat-openbsd
|
ca-certificates curl netcat-openbsd
|
||||||
|
|
||||||
WORKDIR /home/app
|
WORKDIR /home/app
|
||||||
|
|
||||||
|
|||||||
10
Dockerfile.base
Normal file
10
Dockerfile.base
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
FROM golang:1.26
|
||||||
|
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
# copy modules manifests
|
||||||
|
COPY go.mod go.mod
|
||||||
|
COPY go.sum go.sum
|
||||||
|
|
||||||
|
# cache modules
|
||||||
|
RUN go mod download
|
||||||
53
Dockerfile.xx
Normal file
53
Dockerfile.xx
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
ARG GO_VERSION=1.26
|
||||||
|
ARG XX_VERSION=1.9.0
|
||||||
|
|
||||||
|
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||||
|
|
||||||
|
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine as builder
|
||||||
|
|
||||||
|
# Copy the build utilities.
|
||||||
|
COPY --from=xx / /
|
||||||
|
|
||||||
|
ARG TARGETPLATFORM
|
||||||
|
ARG REVISION
|
||||||
|
|
||||||
|
RUN mkdir -p /podinfo/
|
||||||
|
|
||||||
|
WORKDIR /podinfo
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
ENV CGO_ENABLED=0
|
||||||
|
RUN xx-go build -ldflags "-s -w \
|
||||||
|
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \
|
||||||
|
-a -o bin/podinfo cmd/podinfo/*
|
||||||
|
|
||||||
|
RUN xx-go build -ldflags "-s -w \
|
||||||
|
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \
|
||||||
|
-a -o bin/podcli cmd/podcli/*
|
||||||
|
|
||||||
|
FROM alpine:3.23
|
||||||
|
|
||||||
|
ARG BUILD_DATE
|
||||||
|
ARG VERSION
|
||||||
|
ARG REVISION
|
||||||
|
|
||||||
|
LABEL maintainer="stefanprodan"
|
||||||
|
|
||||||
|
RUN addgroup -S app \
|
||||||
|
&& adduser -S -G app app \
|
||||||
|
&& apk --no-cache add \
|
||||||
|
ca-certificates curl netcat-openbsd
|
||||||
|
|
||||||
|
WORKDIR /home/app
|
||||||
|
|
||||||
|
COPY --from=builder /podinfo/bin/podinfo .
|
||||||
|
COPY --from=builder /podinfo/bin/podcli /usr/local/bin/podcli
|
||||||
|
COPY ./ui ./ui
|
||||||
|
RUN chown -R app:app ./
|
||||||
|
|
||||||
|
USER app
|
||||||
|
|
||||||
|
CMD ["./podinfo"]
|
||||||
214
LICENSE
214
LICENSE
@@ -1,21 +1,201 @@
|
|||||||
MIT License
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
Copyright (c) 2018 Stefan Prodan
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
1. Definitions.
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
copies or substantial portions of the Software.
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
the copyright owner that is granting the License.
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
other entities that control, are controlled by, or are under common
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
control with that entity. For the purposes of this definition,
|
||||||
SOFTWARE.
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2018 Stefan Prodan. All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|||||||
75
Makefile
75
Makefile
@@ -8,16 +8,29 @@ DOCKER_REPOSITORY:=stefanprodan
|
|||||||
DOCKER_IMAGE_NAME:=$(DOCKER_REPOSITORY)/$(NAME)
|
DOCKER_IMAGE_NAME:=$(DOCKER_REPOSITORY)/$(NAME)
|
||||||
GIT_COMMIT:=$(shell git describe --dirty --always)
|
GIT_COMMIT:=$(shell git describe --dirty --always)
|
||||||
VERSION:=$(shell grep 'VERSION' pkg/version/version.go | awk '{ print $$4 }' | tr -d '"')
|
VERSION:=$(shell grep 'VERSION' pkg/version/version.go | awk '{ print $$4 }' | tr -d '"')
|
||||||
|
EXTRA_RUN_ARGS?=
|
||||||
|
|
||||||
run:
|
run:
|
||||||
GO111MODULE=on go run -ldflags "-s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION=$(GIT_COMMIT)" cmd/podinfo/* --level=debug
|
go run -ldflags "-s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION=$(GIT_COMMIT)" cmd/podinfo/* \
|
||||||
|
--level=debug --grpc-port=9999 --backend-url=https://httpbin.org/status/401 --backend-url=https://httpbin.org/status/500 \
|
||||||
|
--ui-logo=https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif $(EXTRA_RUN_ARGS)
|
||||||
|
|
||||||
test:
|
.PHONY: test
|
||||||
GO111MODULE=on go test -v -race ./...
|
test: tidy fmt vet
|
||||||
|
go test ./... -coverprofile cover.out
|
||||||
|
|
||||||
build:
|
build:
|
||||||
GO111MODULE=on GIT_COMMIT=$$(git rev-list -1 HEAD) && GO111MODULE=on CGO_ENABLED=0 go build -ldflags "-s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION=$(GIT_COMMIT)" -a -o ./bin/podinfo ./cmd/podinfo/*
|
GIT_COMMIT=$$(git rev-list -1 HEAD) && CGO_ENABLED=0 go build -ldflags "-s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION=$(GIT_COMMIT)" -a -o ./bin/podinfo ./cmd/podinfo/*
|
||||||
GO111MODULE=on GIT_COMMIT=$$(git rev-list -1 HEAD) && GO111MODULE=on CGO_ENABLED=0 go build -ldflags "-s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION=$(GIT_COMMIT)" -a -o ./bin/podcli ./cmd/podcli/*
|
GIT_COMMIT=$$(git rev-list -1 HEAD) && CGO_ENABLED=0 go build -ldflags "-s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION=$(GIT_COMMIT)" -a -o ./bin/podcli ./cmd/podcli/*
|
||||||
|
|
||||||
|
tidy:
|
||||||
|
rm -f go.sum; go mod tidy -compat=1.26
|
||||||
|
|
||||||
|
vet:
|
||||||
|
go vet ./...
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
go fmt ./...
|
||||||
|
|
||||||
build-charts:
|
build-charts:
|
||||||
helm lint charts/*
|
helm lint charts/*
|
||||||
@@ -26,6 +39,19 @@ build-charts:
|
|||||||
build-container:
|
build-container:
|
||||||
docker build -t $(DOCKER_IMAGE_NAME):$(VERSION) .
|
docker build -t $(DOCKER_IMAGE_NAME):$(VERSION) .
|
||||||
|
|
||||||
|
build-xx:
|
||||||
|
docker buildx build \
|
||||||
|
--platform=linux/amd64 \
|
||||||
|
-t $(DOCKER_IMAGE_NAME):$(VERSION) \
|
||||||
|
--load \
|
||||||
|
-f Dockerfile.xx .
|
||||||
|
|
||||||
|
build-base:
|
||||||
|
docker build -f Dockerfile.base -t $(DOCKER_REPOSITORY)/podinfo-base:latest .
|
||||||
|
|
||||||
|
push-base: build-base
|
||||||
|
docker push $(DOCKER_REPOSITORY)/podinfo-base:latest
|
||||||
|
|
||||||
test-container:
|
test-container:
|
||||||
@docker rm -f podinfo || true
|
@docker rm -f podinfo || true
|
||||||
@docker run -dp 9898:9898 --name=podinfo $(DOCKER_IMAGE_NAME):$(VERSION)
|
@docker run -dp 9898:9898 --name=podinfo $(DOCKER_IMAGE_NAME):$(VERSION)
|
||||||
@@ -34,20 +60,45 @@ test-container:
|
|||||||
curl -sH "Authorization: Bearer $${TOKEN}" localhost:9898/token/validate | grep test
|
curl -sH "Authorization: Bearer $${TOKEN}" localhost:9898/token/validate | grep test
|
||||||
|
|
||||||
push-container:
|
push-container:
|
||||||
|
docker tag $(DOCKER_IMAGE_NAME):$(VERSION) $(DOCKER_IMAGE_NAME):latest
|
||||||
docker push $(DOCKER_IMAGE_NAME):$(VERSION)
|
docker push $(DOCKER_IMAGE_NAME):$(VERSION)
|
||||||
|
docker push $(DOCKER_IMAGE_NAME):latest
|
||||||
docker tag $(DOCKER_IMAGE_NAME):$(VERSION) quay.io/$(DOCKER_IMAGE_NAME):$(VERSION)
|
docker tag $(DOCKER_IMAGE_NAME):$(VERSION) quay.io/$(DOCKER_IMAGE_NAME):$(VERSION)
|
||||||
|
docker tag $(DOCKER_IMAGE_NAME):$(VERSION) quay.io/$(DOCKER_IMAGE_NAME):latest
|
||||||
docker push quay.io/$(DOCKER_IMAGE_NAME):$(VERSION)
|
docker push quay.io/$(DOCKER_IMAGE_NAME):$(VERSION)
|
||||||
|
docker push quay.io/$(DOCKER_IMAGE_NAME):latest
|
||||||
|
|
||||||
version-set:
|
version-set:
|
||||||
@next="$(TAG)" && \
|
@next="$(TAG)" && \
|
||||||
current="$(VERSION)" && \
|
current="$(VERSION)" && \
|
||||||
sed -i '' "s/$$current/$$next/g" pkg/version/version.go && \
|
/usr/bin/sed -i '' "s/$$current/$$next/g" pkg/version/version.go && \
|
||||||
sed -i '' "s/tag: $$current/tag: $$next/g" charts/podinfo/values.yaml && \
|
/usr/bin/sed -i '' "s/tag: $$current/tag: $$next/g" charts/podinfo/values.yaml && \
|
||||||
sed -i '' "s/appVersion: $$current/appVersion: $$next/g" charts/podinfo/Chart.yaml && \
|
/usr/bin/sed -i '' "s/tag: $$current/tag: $$next/g" charts/podinfo/values-prod.yaml && \
|
||||||
sed -i '' "s/version: $$current/version: $$next/g" charts/podinfo/Chart.yaml && \
|
/usr/bin/sed -i '' "s/appVersion: $$current/appVersion: $$next/g" charts/podinfo/Chart.yaml && \
|
||||||
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" kustomize/deployment.yaml && \
|
/usr/bin/sed -i '' "s/version: $$current/version: $$next/g" charts/podinfo/Chart.yaml && \
|
||||||
echo "Version $$next set in code, deployment, chart and kustomize"
|
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" kustomize/deployment.yaml && \
|
||||||
|
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/webapp/frontend/deployment.yaml && \
|
||||||
|
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/webapp/backend/deployment.yaml && \
|
||||||
|
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/frontend/deployment.yaml && \
|
||||||
|
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/backend/deployment.yaml && \
|
||||||
|
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/database/statefulset-primary.yaml && \
|
||||||
|
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/database/deployment-replica.yaml && \
|
||||||
|
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/database/cronjob-rollup-daily.yaml && \
|
||||||
|
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/database/cronjob-rollup-weekly.yaml && \
|
||||||
|
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/database/cronjob-backup-daily.yaml && \
|
||||||
|
/usr/bin/sed -i '' "s/$$current/$$next/g" timoni/podinfo/values.cue && \
|
||||||
|
echo "Version $$next set in code, deployment, module, chart and kustomize"
|
||||||
|
|
||||||
release:
|
release:
|
||||||
git tag $(VERSION)
|
git tag -s -m $(VERSION) $(VERSION)
|
||||||
git push origin $(VERSION)
|
git push origin $(VERSION)
|
||||||
|
|
||||||
|
swagger:
|
||||||
|
go install github.com/swaggo/swag/cmd/swag@latest
|
||||||
|
go get github.com/swaggo/swag/gen@latest
|
||||||
|
go get github.com/swaggo/swag/cmd/swag@latest
|
||||||
|
cd pkg/api/http && $$(go env GOPATH)/bin/swag init -g server.go
|
||||||
|
|
||||||
|
.PHONY: timoni-build
|
||||||
|
timoni-build:
|
||||||
|
@timoni build podinfo ./timoni/podinfo -f ./timoni/podinfo/debug_values.cue
|
||||||
|
|||||||
167
README.md
167
README.md
@@ -1,23 +1,31 @@
|
|||||||
# podinfo
|
# podinfo
|
||||||
|
|
||||||
[](https://circleci.com/gh/stefanprodan/podinfo)
|
[](https://github.com/stefanprodan/podinfo/blob/master/.github/workflows/e2e.yml)
|
||||||
|
[](https://github.com/stefanprodan/podinfo/blob/master/.github/workflows/test.yml)
|
||||||
|
[](https://github.com/stefanprodan/podinfo/blob/master/.github/workflows/cve-scan.yml)
|
||||||
|
[](https://goreportcard.com/report/github.com/stefanprodan/podinfo)
|
||||||
[](https://hub.docker.com/r/stefanprodan/podinfo)
|
[](https://hub.docker.com/r/stefanprodan/podinfo)
|
||||||
|
|
||||||
Podinfo is a tiny web application made with Go
|
Podinfo is a tiny web application made with Go that showcases best practices of running microservices in Kubernetes.
|
||||||
that showcases best practices of running microservices in Kubernetes.
|
Podinfo is used by CNCF projects like [Flux](https://github.com/fluxcd/flux2) and [Flagger](https://github.com/fluxcd/flagger)
|
||||||
|
for end-to-end testing and workshops.
|
||||||
|
|
||||||
Specifications:
|
Specifications:
|
||||||
|
|
||||||
* Health checks (readiness and liveness)
|
* Health checks (readiness and liveness)
|
||||||
* Graceful shutdown on interrupt signals
|
* Graceful shutdown on interrupt signals
|
||||||
* File watcher for secrets and configmaps
|
* File watcher for secrets and configmaps
|
||||||
* Instrumented with Prometheus
|
* Instrumented with Prometheus and Open Telemetry
|
||||||
* Tracing with Istio and Jaeger
|
|
||||||
* Structured logging with zap
|
* Structured logging with zap
|
||||||
* 12-factor app with viper
|
* 12-factor app with viper
|
||||||
* Fault injection (random errors and latency)
|
* Fault injection (random errors and latency)
|
||||||
* Helm and Kustomize installers
|
* Swagger docs
|
||||||
|
* Timoni, Helm and Kustomize installers
|
||||||
* End-to-End testing with Kubernetes Kind and Helm
|
* End-to-End testing with Kubernetes Kind and Helm
|
||||||
|
* Multi-arch container image with Docker buildx and GitHub Actions
|
||||||
|
* Container image signing with Sigstore cosign
|
||||||
|
* SBOMs and SLSA Provenance embedded in the container image
|
||||||
|
* CVE scanning with govulncheck
|
||||||
|
|
||||||
Web API:
|
Web API:
|
||||||
|
|
||||||
@@ -37,45 +45,168 @@ Web API:
|
|||||||
* `POST /token` issues a JWT token valid for one minute `JWT=$(curl -sd 'anon' podinfo:9898/token | jq -r .token)`
|
* `POST /token` issues a JWT token valid for one minute `JWT=$(curl -sd 'anon' podinfo:9898/token | jq -r .token)`
|
||||||
* `GET /token/validate` validates the JWT token `curl -H "Authorization: Bearer $JWT" podinfo:9898/token/validate`
|
* `GET /token/validate` validates the JWT token `curl -H "Authorization: Bearer $JWT" podinfo:9898/token/validate`
|
||||||
* `GET /configs` returns a JSON with configmaps and/or secrets mounted in the `config` volume
|
* `GET /configs` returns a JSON with configmaps and/or secrets mounted in the `config` volume
|
||||||
|
* `POST/PUT /cache/{key}` saves the posted content to Redis
|
||||||
|
* `GET /cache/{key}` returns the content from Redis if the key exists
|
||||||
|
* `DELETE /cache/{key}` deletes the key from Redis if exists
|
||||||
* `POST /store` writes the posted content to disk at /data/hash and returns the SHA1 hash of the content
|
* `POST /store` writes the posted content to disk at /data/hash and returns the SHA1 hash of the content
|
||||||
* `GET /store/{hash}` returns the content of the file /data/hash if exists
|
* `GET /store/{hash}` returns the content of the file /data/hash if exists
|
||||||
* `GET /ws/echo` echos content via websockets `podcli ws ws://localhost:9898/ws/echo`
|
* `GET /ws/echo` echos content via websockets `podcli ws ws://localhost:9898/ws/echo`
|
||||||
* `GET /chunked/{seconds}` uses `transfer-encoding` type `chunked` to give a partial response and then waits for the specified period
|
* `GET /chunked/{seconds}` uses `transfer-encoding` type `chunked` to give a partial response and then waits for the specified period
|
||||||
|
* `GET /swagger.json` returns the API Swagger docs, used for Linkerd service profiling and Gloo routes discovery
|
||||||
|
|
||||||
|
gRPC API:
|
||||||
|
|
||||||
|
* `/grpc.health.v1.Health/Check` health checking
|
||||||
|
* `/grpc.EchoService/Echo` echos the received content
|
||||||
|
* `/grpc.VersionService/Version` returns podinfo version and Git commit hash
|
||||||
|
* `/grpc.DelayService/Delay` returns a successful response after the given seconds in the body of gRPC request
|
||||||
|
* `/grpc.EnvService/Env` returns environment variables as a JSON array
|
||||||
|
* `/grpc.HeaderService/Header` returns the headers present in the gRPC request. Any custom header can also be given as a part of request and that can be returned using this API
|
||||||
|
* `/grpc.InfoService/Info` returns the runtime information
|
||||||
|
* `/grpc.PanicService/Panic` crashes the process with gRPC status code as '1 CANCELLED'
|
||||||
|
* `/grpc.StatusService/Status` returns the gRPC Status code given in the request body
|
||||||
|
* `/grpc.TokenService/TokenGenerate` issues a JWT token valid for one minute
|
||||||
|
* `/grpc.TokenService/TokenValidate` validates the JWT token
|
||||||
|
|
||||||
Web UI:
|
Web UI:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
To access the Swagger UI open `<podinfo-host>/swagger/index.html` in a browser.
|
||||||
|
|
||||||
### Guides
|
### Guides
|
||||||
|
|
||||||
* [Automated canary deployments with Flagger and Istio](https://medium.com/google-cloud/automated-canary-deployments-with-flagger-and-istio-ac747827f9d1)
|
* [Getting started with Timoni](https://timoni.sh/quickstart/)
|
||||||
* [Kubernetes autoscaling with Istio metrics](https://medium.com/google-cloud/kubernetes-autoscaling-with-istio-metrics-76442253a45a)
|
* [Getting started with Flux](https://fluxcd.io/flux/get-started/)
|
||||||
* [Managing Helm releases the GitOps way](https://medium.com/google-cloud/managing-helm-releases-the-gitops-way-207a6ac6ff0e)
|
* [Progressive Deliver with Flagger and Linkerd](https://docs.flagger.app/tutorials/linkerd-progressive-delivery)
|
||||||
* [Expose Kubernetes services over HTTPS with Ngrok](https://stefanprodan.com/2018/expose-kubernetes-services-over-http-with-ngrok/)
|
* [Automated canary deployments with Kubernetes Gateway API](https://docs.flagger.app/tutorials/gatewayapi-progressive-delivery)
|
||||||
|
|
||||||
### Install
|
### Install
|
||||||
|
|
||||||
Helm:
|
To install Podinfo on Kubernetes the minimum required version is **Kubernetes v1.23**.
|
||||||
|
|
||||||
|
#### Timoni
|
||||||
|
|
||||||
|
Install with [Timoni](https://timoni.sh):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
helm repo add sp https://stefanprodan.github.io/podinfo
|
timoni -n default apply podinfo oci://ghcr.io/stefanprodan/modules/podinfo
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Helm
|
||||||
|
|
||||||
|
Install from github.io:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm repo add podinfo https://stefanprodan.github.io/podinfo
|
||||||
|
|
||||||
helm upgrade --install --wait frontend \
|
helm upgrade --install --wait frontend \
|
||||||
--namespace test \
|
--namespace test \
|
||||||
--set replicaCount=2 \
|
--set replicaCount=2 \
|
||||||
--set backend=http://backend-podinfo:9898/echo \
|
--set backend=http://backend-podinfo:9898/echo \
|
||||||
sp/podinfo
|
podinfo/podinfo
|
||||||
|
|
||||||
helm test frontend --cleanup
|
helm test frontend --namespace test
|
||||||
|
|
||||||
helm upgrade --install --wait backend \
|
helm upgrade --install --wait backend \
|
||||||
--namespace test \
|
--namespace test \
|
||||||
--set hpa.enabled=true \
|
--set redis.enabled=true \
|
||||||
sp/podinfo
|
podinfo/podinfo
|
||||||
```
|
```
|
||||||
|
|
||||||
Kustomize:
|
Install from ghcr.io:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm upgrade --install --wait podinfo --namespace default \
|
||||||
|
oci://ghcr.io/stefanprodan/charts/podinfo
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Kustomize
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl apply -k github.com/stefanprodan/podinfo//kustomize
|
kubectl apply -k github.com/stefanprodan/podinfo//kustomize
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -dp 9898:9898 stefanprodan/podinfo
|
||||||
|
```
|
||||||
|
|
||||||
|
### Continuous Delivery
|
||||||
|
|
||||||
|
In order to install podinfo on a Kubernetes cluster and keep it up to date with the latest
|
||||||
|
release in an automated manner, you can use [Flux](https://fluxcd.io).
|
||||||
|
|
||||||
|
Install the Flux CLI on MacOS and Linux using Homebrew:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
brew install fluxcd/tap/flux
|
||||||
|
```
|
||||||
|
|
||||||
|
Install the Flux controllers needed for Helm operations:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
flux install \
|
||||||
|
--namespace=flux-system \
|
||||||
|
--network-policy=false \
|
||||||
|
--components=source-controller,helm-controller
|
||||||
|
```
|
||||||
|
|
||||||
|
Add podinfo's Helm repository to your cluster and
|
||||||
|
configure Flux to check for new chart releases every ten minutes:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
flux create source helm podinfo \
|
||||||
|
--namespace=default \
|
||||||
|
--url=https://stefanprodan.github.io/podinfo \
|
||||||
|
--interval=10m
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a `podinfo-values.yaml` file locally:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cat > podinfo-values.yaml <<EOL
|
||||||
|
replicaCount: 2
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 64Mi
|
||||||
|
EOL
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a Helm release for deploying podinfo in the default namespace:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
flux create helmrelease podinfo \
|
||||||
|
--namespace=default \
|
||||||
|
--source=HelmRepository/podinfo \
|
||||||
|
--release-name=podinfo \
|
||||||
|
--chart=podinfo \
|
||||||
|
--chart-version=">5.0.0" \
|
||||||
|
--values=podinfo-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Based on the above definition, Flux will upgrade the release automatically
|
||||||
|
when a new version of podinfo is released. If the upgrade fails, Flux
|
||||||
|
can [rollback](https://toolkit.fluxcd.io/components/helm/helmreleases/#configuring-failure-remediation)
|
||||||
|
to the previous working version.
|
||||||
|
|
||||||
|
You can check what version is currently deployed with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
flux get helmreleases -n default
|
||||||
|
```
|
||||||
|
|
||||||
|
To delete podinfo's Helm repository and release from your cluster run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
flux -n default delete source helm podinfo
|
||||||
|
flux -n default delete helmrelease podinfo
|
||||||
|
```
|
||||||
|
|
||||||
|
If you wish to manage the lifecycle of your applications in a **GitOps** manner, check out
|
||||||
|
this [workflow example](https://github.com/fluxcd/flux2-kustomize-helm-example)
|
||||||
|
for multi-env deployments with Flux, Kustomize and Helm.
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
# Patterns to ignore when building packages.
|
|
||||||
# This supports shell glob matching, relative path matching, and
|
|
||||||
# negation (prefixed with !). Only one pattern per line.
|
|
||||||
.DS_Store
|
|
||||||
# Common VCS dirs
|
|
||||||
.git/
|
|
||||||
.gitignore
|
|
||||||
.bzr/
|
|
||||||
.bzrignore
|
|
||||||
.hg/
|
|
||||||
.hgignore
|
|
||||||
.svn/
|
|
||||||
# Common backup files
|
|
||||||
*.swp
|
|
||||||
*.bak
|
|
||||||
*.tmp
|
|
||||||
*~
|
|
||||||
# Various IDEs
|
|
||||||
.project
|
|
||||||
.idea/
|
|
||||||
*.tmproj
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
appVersion: "1.0"
|
|
||||||
description: A Ngrok Helm chart for Kubernetes
|
|
||||||
name: ngrok
|
|
||||||
version: 0.2.0
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
# Ngrok
|
|
||||||
|
|
||||||
Expose Kubernetes service with [Ngrok](https://ngrok.com).
|
|
||||||
|
|
||||||
## Installing the Chart
|
|
||||||
|
|
||||||
To install the chart with the release name `my-release`:
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ helm install sp/ngrok --name my-release \
|
|
||||||
--set token=NGROK-TOKEN \
|
|
||||||
--set expose.service=podinfo:9898
|
|
||||||
```
|
|
||||||
|
|
||||||
The command deploys Ngrok on the Kubernetes cluster in the default namespace.
|
|
||||||
The [configuration](#configuration) section lists the parameters that can be configured during installation.
|
|
||||||
|
|
||||||
## Uninstalling the Chart
|
|
||||||
|
|
||||||
To uninstall/delete the `my-release` deployment:
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ helm delete --purge my-release
|
|
||||||
```
|
|
||||||
|
|
||||||
The command removes all the Kubernetes components associated with the chart and deletes the release.
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
The following tables lists the configurable parameters of the Grafana chart and their default values.
|
|
||||||
|
|
||||||
Parameter | Description | Default
|
|
||||||
--- | --- | ---
|
|
||||||
`image.repository` | Image repository | `stefanprodan/ngrok`
|
|
||||||
`image.pullPolicy` | Image pull policy | `IfNotPresent`
|
|
||||||
`image.tag` | Image tag | `latest`
|
|
||||||
`replicaCount` | desired number of pods | `1`
|
|
||||||
`tolerations` | List of node taints to tolerate | `[]`
|
|
||||||
`affinity` | node/pod affinities | `node`
|
|
||||||
`nodeSelector` | node labels for pod assignment | `{}`
|
|
||||||
`service.type` | type of service | `ClusterIP`
|
|
||||||
`token` | Ngrok auth token | `none`
|
|
||||||
`expose.service` | Service address to be exposed as in `service-name:port` | `none`
|
|
||||||
`subdomain` | Ngrok subdomain | `none`
|
|
||||||
|
|
||||||
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ helm upgrade --install --wait tunel \
|
|
||||||
--set token=NGROK-TOKEN \
|
|
||||||
--set service.type=NodePort \
|
|
||||||
--set expose.service=podinfo:9898 \
|
|
||||||
sp/ngrok
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example,
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ helm install sp/grafana --name my-release -f values.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Tip**: You can use the default [values.yaml](values.yaml)
|
|
||||||
```
|
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
1. Get the application URL by running these commands:
|
|
||||||
{{- if contains "NodePort" .Values.service.type }}
|
|
||||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "ngrok.fullname" . }})
|
|
||||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
|
||||||
echo http://$NODE_IP:$NODE_PORT
|
|
||||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
|
||||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
|
||||||
You can watch the status of by running 'kubectl get svc -w {{ template "ngrok.fullname" . }}'
|
|
||||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "ngrok.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
|
||||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
|
||||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
|
||||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "ngrok.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
|
||||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
|
||||||
kubectl port-forward $POD_NAME 8080:80
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
{{/* vim: set filetype=mustache: */}}
|
|
||||||
{{/*
|
|
||||||
Expand the name of the chart.
|
|
||||||
*/}}
|
|
||||||
{{- define "ngrok.name" -}}
|
|
||||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Create a default fully qualified app name.
|
|
||||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
|
||||||
If release name contains chart name it will be used as a full name.
|
|
||||||
*/}}
|
|
||||||
{{- define "ngrok.fullname" -}}
|
|
||||||
{{- if .Values.fullnameOverride -}}
|
|
||||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
|
||||||
{{- if contains $name .Release.Name -}}
|
|
||||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/*
|
|
||||||
Create chart name and version as used by the chart label.
|
|
||||||
*/}}
|
|
||||||
{{- define "ngrok.chart" -}}
|
|
||||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- end -}}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: {{ template "ngrok.fullname" . }}
|
|
||||||
data:
|
|
||||||
ngrok.yml: |-
|
|
||||||
web_addr: 0.0.0.0:4040
|
|
||||||
update: false
|
|
||||||
log: stdout
|
|
||||||
{{- if .Values.token }}
|
|
||||||
authtoken: {{ .Values.token }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
apiVersion: apps/v1beta2
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: {{ template "ngrok.fullname" . }}
|
|
||||||
labels:
|
|
||||||
app: {{ template "ngrok.name" . }}
|
|
||||||
chart: {{ template "ngrok.chart" . }}
|
|
||||||
release: {{ .Release.Name }}
|
|
||||||
heritage: {{ .Release.Service }}
|
|
||||||
spec:
|
|
||||||
replicas: {{ .Values.replicaCount }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: {{ template "ngrok.name" . }}
|
|
||||||
release: {{ .Release.Name }}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: {{ template "ngrok.name" . }}
|
|
||||||
release: {{ .Release.Name }}
|
|
||||||
annotations:
|
|
||||||
prometheus.io/scrape: 'false'
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: {{ .Chart.Name }}
|
|
||||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
|
||||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
|
||||||
command:
|
|
||||||
- ./ngrok
|
|
||||||
- http
|
|
||||||
{{- if .Values.subdomain }}
|
|
||||||
- --subdomain={{ .Values.subdomain }}
|
|
||||||
{{- end }}
|
|
||||||
- {{ .Values.expose.service }}
|
|
||||||
volumeMounts:
|
|
||||||
- name: config
|
|
||||||
mountPath: /home/ngrok/.ngrok2
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
containerPort: 4040
|
|
||||||
protocol: TCP
|
|
||||||
livenessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /api/tunnels
|
|
||||||
port: http
|
|
||||||
initialDelaySeconds: 10
|
|
||||||
periodSeconds: 30
|
|
||||||
resources:
|
|
||||||
{{ toYaml .Values.resources | indent 12 }}
|
|
||||||
{{- with .Values.nodeSelector }}
|
|
||||||
nodeSelector:
|
|
||||||
{{ toYaml . | indent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.affinity }}
|
|
||||||
affinity:
|
|
||||||
{{ toYaml . | indent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.tolerations }}
|
|
||||||
tolerations:
|
|
||||||
{{ toYaml . | indent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
volumes:
|
|
||||||
- name: config
|
|
||||||
configMap:
|
|
||||||
name: {{ template "ngrok.fullname" . }}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ template "ngrok.fullname" . }}
|
|
||||||
labels:
|
|
||||||
app: {{ template "ngrok.name" . }}
|
|
||||||
chart: {{ template "ngrok.chart" . }}
|
|
||||||
release: {{ .Release.Name }}
|
|
||||||
heritage: {{ .Release.Service }}
|
|
||||||
spec:
|
|
||||||
type: {{ .Values.service.type }}
|
|
||||||
ports:
|
|
||||||
- port: {{ .Values.service.port }}
|
|
||||||
targetPort: http
|
|
||||||
protocol: TCP
|
|
||||||
name: http
|
|
||||||
selector:
|
|
||||||
app: {{ template "ngrok.name" . }}
|
|
||||||
release: {{ .Release.Name }}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# Default values for ngrok.
|
|
||||||
# This is a YAML-formatted file.
|
|
||||||
# Declare variables to be passed into your templates.
|
|
||||||
|
|
||||||
replicaCount: 1
|
|
||||||
|
|
||||||
image:
|
|
||||||
repository: stefanprodan/ngrok
|
|
||||||
tag: latest
|
|
||||||
pullPolicy: IfNotPresent
|
|
||||||
|
|
||||||
service:
|
|
||||||
type: ClusterIP
|
|
||||||
port: 4040
|
|
||||||
|
|
||||||
expose:
|
|
||||||
service: ga-podinfo:9898
|
|
||||||
|
|
||||||
token: 4i3rDinhLqMHtvez71N9S_38rkS7onwv77VFNZTaUR6
|
|
||||||
|
|
||||||
nodeSelector: {}
|
|
||||||
|
|
||||||
tolerations: []
|
|
||||||
|
|
||||||
affinity: {}
|
|
||||||
|
|
||||||
subdomain:
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
version: 2.0.1
|
version: 6.11.2
|
||||||
appVersion: 2.0.1
|
appVersion: 6.11.2
|
||||||
name: podinfo
|
name: podinfo
|
||||||
engine: gotpl
|
engine: gotpl
|
||||||
description: Podinfo Helm chart for Kubernetes
|
description: Podinfo Helm chart for Kubernetes
|
||||||
@@ -10,3 +10,4 @@ maintainers:
|
|||||||
name: stefanprodan
|
name: stefanprodan
|
||||||
sources:
|
sources:
|
||||||
- https://github.com/stefanprodan/podinfo
|
- https://github.com/stefanprodan/podinfo
|
||||||
|
kubeVersion: ">=1.23.0-0"
|
||||||
|
|||||||
201
charts/podinfo/LICENSE
Normal file
201
charts/podinfo/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2018 Stefan Prodan. All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@@ -1,15 +1,38 @@
|
|||||||
# Podinfo
|
# Podinfo
|
||||||
|
|
||||||
Podinfo is a tiny web application made with Go
|
Podinfo is a tiny web application made with Go
|
||||||
that showcases best practices of running microservices in Kubernetes.
|
that showcases best practices of running microservices in Kubernetes.
|
||||||
|
|
||||||
|
Podinfo is used by CNCF projects like [Flux](https://github.com/fluxcd/flux2)
|
||||||
|
and [Flagger](https://github.com/fluxcd/flagger)
|
||||||
|
for end-to-end testing and workshops.
|
||||||
|
|
||||||
## Installing the Chart
|
## Installing the Chart
|
||||||
|
|
||||||
To install the chart with the release name `my-release`:
|
The Podinfo charts are published to
|
||||||
|
[GitHub Container Registry](https://github.com/stefanprodan/podinfo/pkgs/container/charts%2Fpodinfo)
|
||||||
|
and signed with [Cosign](https://github.com/sigstore/cosign) & GitHub Actions OIDC.
|
||||||
|
|
||||||
|
To install the chart with the release name `podinfo` from GHCR:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ helm repo add sp https://stefanprodan.github.io/k8s-podinfo
|
$ helm upgrade -i podinfo oci://ghcr.io/stefanprodan/charts/podinfo
|
||||||
$ helm upgrade my-release --install sp/podinfo
|
```
|
||||||
|
|
||||||
|
To verify a chart version with Cosign:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ cosign verify ghcr.io/stefanprodan/charts/podinfo:<VERSION> \
|
||||||
|
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
|
||||||
|
--certificate-identity-regexp=^https://github\\.com/stefanprodan/podinfo/.*$
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can install the chart from GitHub pages:
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ helm repo add stefanprodan https://stefanprodan.github.io/podinfo
|
||||||
|
|
||||||
|
$ helm upgrade -i podinfo stefanprodan/podinfo
|
||||||
```
|
```
|
||||||
|
|
||||||
The command deploys podinfo on the Kubernetes cluster in the default namespace.
|
The command deploys podinfo on the Kubernetes cluster in the default namespace.
|
||||||
@@ -17,10 +40,10 @@ The [configuration](#configuration) section lists the parameters that can be con
|
|||||||
|
|
||||||
## Uninstalling the Chart
|
## Uninstalling the Chart
|
||||||
|
|
||||||
To uninstall/delete the `my-release` deployment:
|
To uninstall the `podinfo` release:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ helm delete --purge my-release
|
$ helm uninstall podinfo
|
||||||
```
|
```
|
||||||
|
|
||||||
The command removes all the Kubernetes components associated with the chart and deletes the release.
|
The command removes all the Kubernetes components associated with the chart and deletes the release.
|
||||||
@@ -29,53 +52,101 @@ The command removes all the Kubernetes components associated with the chart and
|
|||||||
|
|
||||||
The following tables lists the configurable parameters of the podinfo chart and their default values.
|
The following tables lists the configurable parameters of the podinfo chart and their default values.
|
||||||
|
|
||||||
Parameter | Description | Default
|
| Parameter | Default | Description |
|
||||||
--- | --- | ---
|
|--------------------------------------------------|--------------------------------|---------------------------------------------------------------------------------------------------|
|
||||||
`affinity` | node/pod affinities | None
|
| `replicaCount` | `1` | Desired number of pods |
|
||||||
`color` | UI color | blue
|
| `logLevel` | `info` | Log level: `debug`, `info`, `warn`, `error` |
|
||||||
`backend` | echo backend URL | None
|
| `backend` | `None` | Echo backend URL |
|
||||||
`faults.delay` | random HTTP response delays between 0 and 5 seconds | `false`
|
| `backends` | `[]` | Array of echo backend URLs |
|
||||||
`faults.error` | 1/3 chances of a random HTTP response error | `false`
|
| `cache` | `None` | Redis address in the format `tcp://<host>:<port>` |
|
||||||
`hpa.enabled` | enables HPA | `false`
|
| `redis.enabled` | `false` | Create Redis deployment for caching purposes |
|
||||||
`hpa.cpu` | target CPU usage per pod | None
|
| `redis.repository` | `docker.io/redis` | Redis image repository |
|
||||||
`hpa.memory` | target memory usage per pod | None
|
| `redis.tag` | `<VERSION>` | Redis image tag |
|
||||||
`hpa.requests` | target requests per second per pod | None
|
| `redis.imagePullSecrets` | `[]` | Redis image pull secrets |
|
||||||
`hpa.maxReplicas` | maximum pod replicas | `10`
|
| `ui.color` | `#34577c` | UI color |
|
||||||
`ingress.hosts` | ingress accepted hostnames | None
|
| `ui.message` | `None` | UI greetings message |
|
||||||
`ingress.tls` | ingress TLS configuration | None:
|
| `ui.logo` | `None` | UI logo |
|
||||||
`image.pullPolicy` | image pull policy | `IfNotPresent`
|
| `faults.delay` | `false` | Random HTTP response delays between 0 and 5 seconds |
|
||||||
`image.repository` | image repository | `stefanprodan/podinfo`
|
| `faults.error` | `false` | 1/3 chances of a random HTTP response error |
|
||||||
`image.tag` | image tag | `0.0.1`
|
| `faults.unhealthy` | `false` | When set, the healthy state is never reached |
|
||||||
`ingress.enabled` | enables ingress | `false`
|
| `faults.unready` | `false` | When set, the ready state is never reached |
|
||||||
`ingress.annotations` | ingress annotations | None
|
| `faults.testFail` | `false` | When set, a helm test is included which always fails |
|
||||||
`ingress.hosts` | ingress accepted hostnames | None
|
| `faults.testTimeout` | `false` | When set, a helm test is included which always times out |
|
||||||
`ingress.tls` | ingress TLS configuration | None
|
| `image.repository` | `ghcr.io/stefanprodan/podinfo` | Image repository |
|
||||||
`message` | UI greetings message | None
|
| `image.tag` | `<VERSION>` | Image tag |
|
||||||
`nodeSelector` | node labels for pod assignment | `{}`
|
| `image.pullPolicy` | `IfNotPresent` | Image pull policy |
|
||||||
`replicaCount` | desired number of pods | `2`
|
| `image.pullSecrets` | `[]` | Image pull secrets |
|
||||||
`resources.requests/cpu` | pod CPU request | `1m`
|
| `service.enabled` | `true` | Create a Kubernetes Service, should be disabled when using [Flagger](https://flagger.app) |
|
||||||
`resources.requests/memory` | pod memory request | `16Mi`
|
| `service.type` | `ClusterIP` | Type of the Kubernetes Service |
|
||||||
`resources.limits/cpu` | pod CPU limit | None
|
| `service.metricsPort` | `9797` | Prometheus metrics endpoint port |
|
||||||
`resources.limits/memory` | pod memory limit | None
|
| `service.httpPort` | `9898` | Container HTTP port |
|
||||||
`service.externalPort` | external port for the service | `9898`
|
| `service.externalPort` | `9898` | ClusterIP HTTP port |
|
||||||
`service.internalPort` | internal port for the service | `9898`
|
| `service.grpcPort` | `9999` | ClusterIP gPRC port |
|
||||||
`service.nodePort` | node port for the service | `31198`
|
| `service.grpcService` | `podinfo` | gPRC service name |
|
||||||
`service.type` | type of service | `ClusterIP`
|
| `service.nodePort` | `31198` | NodePort for the HTTP endpoint |
|
||||||
`tolerations` | list of node taints to tolerate | `[]`
|
| `service.trafficDistribution` | `""` | Traffic distribution strategy |
|
||||||
|
| `service.additionalLabels` | `{}` | Additional labels to add to the service |
|
||||||
|
| `service.externalTrafficPolicy` | `None` | External traffic policy for LoadBalance service |
|
||||||
|
| `h2c.enabled` | `false` | Allow upgrading to h2c (non-TLS version of HTTP/2) |
|
||||||
|
| `extraArgs` | `[]` | Additional command line arguments to pass to podinfo container |
|
||||||
|
| `extraEnvs` | `[]` | Extra environment variables for the podinfo container |
|
||||||
|
| `config.path` | `""` | config file path |
|
||||||
|
| `config.name` | `""` | config file name |
|
||||||
|
| `hpa.enabled` | `false` | Enables the Kubernetes HPA |
|
||||||
|
| `hpa.maxReplicas` | `10` | Maximum amount of pods |
|
||||||
|
| `hpa.cpu` | `None` | Target CPU usage per pod |
|
||||||
|
| `hpa.memory` | `None` | Target memory usage per pod |
|
||||||
|
| `hpa.requests` | `None` | Target HTTP requests per second per pod |
|
||||||
|
| `serviceAccount.enabled` | `false` | Whether a service account should be created |
|
||||||
|
| `serviceAccount.name` | `None` | The name of the service account to use, if not set a name is generated using the fullname template|
|
||||||
|
| `serviceAccount.imagePullSecrets` | `[]` | List of image pull secrets if pulling from private registries |
|
||||||
|
| `securityContext` | `{}` | The security context to be set on the podinfo container |
|
||||||
|
| `podSecurityContext` | `{}` | The security context to be set on the pod |
|
||||||
|
| `podAnnotations` | `{}` | Pod annotations |
|
||||||
|
| `serviceMonitor.enabled` | `false` | Whether a Prometheus Operator service monitor should be created |
|
||||||
|
| `serviceMonitor.interval` | `15s` | Prometheus scraping interval |
|
||||||
|
| `serviceMonitor.additionalLabels` | `{}` | Add additional labels to the service monitor |
|
||||||
|
| `ingress.enabled` | `false` | Enables Ingress |
|
||||||
|
| `ingress.className` | `""` | Use ingressClassName |
|
||||||
|
| `ingress.additionalLabels` | `{}` | Add additional labels to the ingress |
|
||||||
|
| `ingress.annotations` | `{}` | Ingress annotations |
|
||||||
|
| `ingress.hosts` | `[]` | Ingress accepted hosts |
|
||||||
|
| `ingress.tls` | `[]` | Ingress TLS configuration |
|
||||||
|
| `httpRoute.enabled` | `false` | Enables Gateway API HTTPRoute |
|
||||||
|
| `httpRoute.additionalLabels` | `{}` | Add additional labels to the HTTPRoute |
|
||||||
|
| `httpRoute.annotations` | `{}` | HTTPRoute annotations |
|
||||||
|
| `httpRoute.parentRefs` | `[]` | Gateways that this route is attached to |
|
||||||
|
| `httpRoute.hostnames` | `["podinfo.local"]` | Hostnames matching HTTP header |
|
||||||
|
| `httpRoute.rules` | `[]` | List of rules and filters applied |
|
||||||
|
| `hooks.<hookType>.job.enabled` | `false` | Create a Helm hook job for testing (hookType: see values.yaml for available hooks) |
|
||||||
|
| `hooks.<hookType>.job.hookDeletePolicy` | `hook-succeeded,hook-failed` | Helm hook delete policy |
|
||||||
|
| `hooks.<hookType>.job.ttlSecondsAfterFinished` | `None` | Job TTL after finished |
|
||||||
|
| `hooks.<hookType>.job.sleepSeconds` | `None` | Sleep duration before job exits |
|
||||||
|
| `hooks.<hookType>.job.exitCode` | `0` | Job exit code |
|
||||||
|
| `resources.requests.cpu` | `1m` | Pod CPU request |
|
||||||
|
| `resources.requests.memory` | `16Mi` | Pod memory request |
|
||||||
|
| `resources.limits.cpu` | `None` | Pod CPU limit |
|
||||||
|
| `resources.limits.memory` | `None` | Pod memory limit |
|
||||||
|
| `nodeSelector` | `{}` | Node labels for pod assignment |
|
||||||
|
| `tolerations` | `[]` | List of node taints to tolerate |
|
||||||
|
| `affinity` | `None` | Node/pod affinities |
|
||||||
|
|
||||||
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
|
Specify each parameter using the `--set key=value[,key=value]` argument:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ helm install stable/podinfo --name my-release \
|
$ helm upgrade -i podinfo oci://ghcr.io/stefanprodan/charts/podinfo \
|
||||||
--set=image.tag=0.0.2,service.type=NodePort
|
--set=serviceMonitor.enabled=true,serviceMonitor.interval=5s
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example,
|
To add custom annotations you need to escape the annotation key string:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ helm install stable/podinfo --name my-release -f values.yaml
|
$ helm upgrade -i podinfo oci://ghcr.io/stefanprodan/charts/podinfo \
|
||||||
|
--set podAnnotations."toolkit\.fluxcd\.io\/tenant"=dev-team
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Tip**: You can use the default [values.yaml](values.yaml)
|
Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart:
|
||||||
```
|
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ helm upgrade -i my-release oci://ghcr.io/stefanprodan/charts/podinfo -f values.yaml
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
1. Get the application URL by running these commands:
|
1. Get the application URL by running these commands:
|
||||||
{{- if .Values.ingress.enabled }}
|
{{- if .Values.ingress.enabled }}
|
||||||
{{- range .Values.ingress.hosts }}
|
{{- range $host := .Values.ingress.hosts }}
|
||||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
{{- range .paths }}
|
||||||
|
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- else if contains "NodePort" .Values.service.type }}
|
{{- else if contains "NodePort" .Values.service.type }}
|
||||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "podinfo.fullname" . }})
|
export NODE_PORT=$(kubectl get --namespace {{ include "podinfo.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "podinfo.fullname" . }})
|
||||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
export NODE_IP=$(kubectl get nodes --namespace {{ include "podinfo.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||||
echo http://$NODE_IP:$NODE_PORT
|
echo http://$NODE_IP:$NODE_PORT
|
||||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||||
You can watch the status of by running 'kubectl get svc -w {{ template "podinfo.fullname" . }}'
|
You can watch the status of by running 'kubectl get svc -w {{ template "podinfo.fullname" . }}'
|
||||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "podinfo.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
export SERVICE_IP=$(kubectl get svc --namespace {{ include "podinfo.namespace" . }} {{ template "podinfo.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
echo http://$SERVICE_IP:{{ .Values.service.externalPort }}
|
||||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "podinfo.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
|
||||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||||
kubectl port-forward $POD_NAME 8080:{{ .Values.service.externalPort }}
|
kubectl -n {{ include "podinfo.namespace" . }} port-forward deploy/{{ template "podinfo.fullname" . }} 8080:{{ .Values.service.externalPort }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
{{/* vim: set filetype=mustache: */}}
|
|
||||||
{{/*
|
{{/*
|
||||||
Expand the name of the chart.
|
Expand the name of the chart.
|
||||||
*/}}
|
*/}}
|
||||||
{{- define "podinfo.name" -}}
|
{{- define "podinfo.name" -}}
|
||||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
{{- end -}}
|
{{- end }}
|
||||||
|
|
||||||
{{/*
|
{{/*
|
||||||
Create a default fully qualified app name.
|
Create a default fully qualified app name.
|
||||||
@@ -12,21 +11,66 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this
|
|||||||
If release name contains chart name it will be used as a full name.
|
If release name contains chart name it will be used as a full name.
|
||||||
*/}}
|
*/}}
|
||||||
{{- define "podinfo.fullname" -}}
|
{{- define "podinfo.fullname" -}}
|
||||||
{{- if .Values.fullnameOverride -}}
|
{{- if .Values.fullnameOverride }}
|
||||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
{{- else -}}
|
{{- else }}
|
||||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||||
{{- if contains $name .Release.Name -}}
|
{{- if contains $name .Release.Name }}
|
||||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||||
{{- else -}}
|
{{- else }}
|
||||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||||
{{- end -}}
|
{{- end }}
|
||||||
{{- end -}}
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Allow the release namespace to be overridden for multi-namespace deployments in combined charts.
|
||||||
|
*/}}
|
||||||
|
{{- define "podinfo.namespace" -}}
|
||||||
|
{{- default .Release.Namespace .Values.namespaceOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/*
|
{{/*
|
||||||
Create chart name and version as used by the chart label.
|
Create chart name and version as used by the chart label.
|
||||||
*/}}
|
*/}}
|
||||||
{{- define "podinfo.chart" -}}
|
{{- define "podinfo.chart" -}}
|
||||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
{{- end -}}
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "podinfo.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "podinfo.chart" . }}
|
||||||
|
{{ include "podinfo.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "podinfo.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "podinfo.fullname" . }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the service account to use
|
||||||
|
*/}}
|
||||||
|
{{- define "podinfo.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.enabled }}
|
||||||
|
{{- default (include "podinfo.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the tls secret for secure port
|
||||||
|
*/}}
|
||||||
|
{{- define "podinfo.tlsSecretName" -}}
|
||||||
|
{{- $fullname := include "podinfo.fullname" . -}}
|
||||||
|
{{- default (printf "%s-tls" $fullname) .Values.tls.secretName }}
|
||||||
|
{{- end }}
|
||||||
17
charts/podinfo/templates/certificate.yaml
Normal file
17
charts/podinfo/templates/certificate.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{{- if .Values.certificate.create -}}
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: {{ template "podinfo.fullname" . }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
dnsNames:
|
||||||
|
{{- range .Values.certificate.dnsNames }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ template "podinfo.tlsSecretName" . }}
|
||||||
|
issuerRef:
|
||||||
|
{{- .Values.certificate.issuerRef | toYaml | trimSuffix "\n" | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
@@ -2,78 +2,207 @@ apiVersion: apps/v1
|
|||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ template "podinfo.fullname" . }}
|
name: {{ template "podinfo.fullname" . }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
labels:
|
labels:
|
||||||
app: {{ template "podinfo.name" . }}
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
chart: {{ template "podinfo.chart" . }}
|
|
||||||
release: {{ .Release.Name }}
|
|
||||||
heritage: {{ .Release.Service }}
|
|
||||||
spec:
|
spec:
|
||||||
|
{{- if not .Values.hpa.enabled }}
|
||||||
replicas: {{ .Values.replicaCount }}
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
{{- end }}
|
||||||
strategy:
|
strategy:
|
||||||
type: RollingUpdate
|
type: RollingUpdate
|
||||||
rollingUpdate:
|
rollingUpdate:
|
||||||
maxUnavailable: 1
|
maxUnavailable: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: {{ template "podinfo.name" . }}
|
{{- include "podinfo.selectorLabels" . | nindent 6 }}
|
||||||
release: {{ .Release.Name }}
|
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: {{ template "podinfo.name" . }}
|
{{- include "podinfo.selectorLabels" . | nindent 8 }}
|
||||||
release: {{ .Release.Name }}
|
|
||||||
annotations:
|
annotations:
|
||||||
prometheus.io/scrape: 'true'
|
prometheus.io/scrape: "true"
|
||||||
|
prometheus.io/port: "{{ .Values.service.httpPort }}"
|
||||||
|
{{- range $key, $value := .Values.podAnnotations }}
|
||||||
|
{{ $key }}: {{ $value | quote }}
|
||||||
|
{{- end }}
|
||||||
spec:
|
spec:
|
||||||
terminationGracePeriodSeconds: 30
|
terminationGracePeriodSeconds: 30
|
||||||
|
{{- if .Values.serviceAccount.enabled }}
|
||||||
|
serviceAccountName: {{ template "podinfo.serviceAccountName" . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.image.pullSecrets }}
|
||||||
|
imagePullSecrets: {{ toYaml .Values.image.pullSecrets | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
containers:
|
containers:
|
||||||
- name: {{ .Chart.Name }}
|
- name: {{ .Chart.Name }}
|
||||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
{{- if .Values.securityContext }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
{{- else if (or .Values.service.hostPort .Values.tls.hostPort) }}
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: true
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
add:
|
||||||
|
- NET_BIND_SERVICE
|
||||||
|
{{- end }}
|
||||||
command:
|
command:
|
||||||
- ./podinfo
|
- ./podinfo
|
||||||
- --port={{ .Values.service.containerPort }}
|
- --port={{ .Values.service.httpPort | default 9898 }}
|
||||||
|
{{- if .Values.host }}
|
||||||
|
- --host={{ .Values.host }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.tls.enabled }}
|
||||||
|
- --secure-port={{ .Values.tls.port }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.tls.certPath }}
|
||||||
|
- --cert-path={{ .Values.tls.certPath }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.service.metricsPort }}
|
||||||
|
- --port-metrics={{ .Values.service.metricsPort }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.service.grpcPort }}
|
||||||
|
- --grpc-port={{ .Values.service.grpcPort }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.service.grpcService }}
|
||||||
|
- --grpc-service-name={{ .Values.service.grpcService }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range .Values.backends }}
|
||||||
|
- --backend-url={{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.cache }}
|
||||||
|
- --cache-server={{ .Values.cache }}
|
||||||
|
{{- else if .Values.redis.enabled }}
|
||||||
|
- --cache-server=tcp://{{ template "podinfo.fullname" . }}-redis:6379
|
||||||
|
{{- end }}
|
||||||
- --level={{ .Values.logLevel }}
|
- --level={{ .Values.logLevel }}
|
||||||
- --random-delay={{ .Values.faults.delay }}
|
- --random-delay={{ .Values.faults.delay }}
|
||||||
- --random-error={{ .Values.faults.error }}
|
- --random-error={{ .Values.faults.error }}
|
||||||
|
{{- if .Values.faults.unhealthy }}
|
||||||
|
- --unhealthy
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.faults.unready }}
|
||||||
|
- --unready
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.h2c.enabled }}
|
||||||
|
- --h2c
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.config.path }}
|
||||||
|
- --config-path={{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.config.name }}
|
||||||
|
- --config={{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.extraArgs }}
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
env:
|
env:
|
||||||
- name: PODINFO_UI_COLOR
|
{{- if .Values.ui.message }}
|
||||||
value: {{ .Values.color }}
|
|
||||||
{{- if .Values.message }}
|
|
||||||
- name: PODINFO_UI_MESSAGE
|
- name: PODINFO_UI_MESSAGE
|
||||||
value: {{ .Values.message }}
|
value: {{ quote .Values.ui.message }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.ui.logo }}
|
||||||
|
- name: PODINFO_UI_LOGO
|
||||||
|
value: {{ .Values.ui.logo }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.ui.color }}
|
||||||
|
- name: PODINFO_UI_COLOR
|
||||||
|
value: {{ quote .Values.ui.color }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if .Values.backend }}
|
{{- if .Values.backend }}
|
||||||
- name: PODINFO_BACKEND_URL
|
- name: PODINFO_BACKEND_URL
|
||||||
value: {{ .Values.backend }}
|
value: {{ .Values.backend }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.extraEnvs }}
|
||||||
|
{{ toYaml .Values.extraEnvs | indent 10 }}
|
||||||
|
{{- end }}
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
containerPort: {{ .Values.service.containerPort }}
|
containerPort: {{ .Values.service.httpPort | default 9898 }}
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
|
{{- if .Values.service.hostPort }}
|
||||||
|
hostPort: {{ .Values.service.hostPort }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.tls.enabled }}
|
||||||
|
- name: https
|
||||||
|
containerPort: {{ .Values.tls.port | default 9899 }}
|
||||||
|
protocol: TCP
|
||||||
|
{{- if .Values.tls.hostPort }}
|
||||||
|
hostPort: {{ .Values.tls.hostPort }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.service.metricsPort }}
|
||||||
|
- name: http-metrics
|
||||||
|
containerPort: {{ .Values.service.metricsPort }}
|
||||||
|
protocol: TCP
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.service.grpcPort }}
|
||||||
|
- name: grpc
|
||||||
|
containerPort: {{ .Values.service.grpcPort }}
|
||||||
|
protocol: TCP
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.probes.startup.enable }}
|
||||||
|
startupProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- podcli
|
||||||
|
- check
|
||||||
|
- http
|
||||||
|
- localhost:{{ .Values.service.httpPort | default 9898 }}/healthz
|
||||||
|
{{- with .Values.probes.startup }}
|
||||||
|
initialDelaySeconds: {{ .initialDelaySeconds | default 1 }}
|
||||||
|
timeoutSeconds: {{ .timeoutSeconds | default 5 }}
|
||||||
|
failureThreshold: {{ .failureThreshold | default 3 }}
|
||||||
|
successThreshold: {{ .successThreshold | default 1 }}
|
||||||
|
periodSeconds: {{ .periodSeconds | default 10 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
exec:
|
exec:
|
||||||
command:
|
command:
|
||||||
- podcli
|
- podcli
|
||||||
- check
|
- check
|
||||||
- http
|
- http
|
||||||
- localhost:{{ .Values.service.containerPort }}/healthz
|
- localhost:{{ .Values.service.httpPort | default 9898 }}/healthz
|
||||||
initialDelaySeconds: 1
|
{{- with .Values.probes.liveness }}
|
||||||
timeoutSeconds: 5
|
initialDelaySeconds: {{ .initialDelaySeconds | default 1 }}
|
||||||
|
timeoutSeconds: {{ .timeoutSeconds | default 5 }}
|
||||||
|
failureThreshold: {{ .failureThreshold | default 3 }}
|
||||||
|
successThreshold: {{ .successThreshold | default 1 }}
|
||||||
|
periodSeconds: {{ .periodSeconds | default 10 }}
|
||||||
|
{{- end }}
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
exec:
|
exec:
|
||||||
command:
|
command:
|
||||||
- podcli
|
- podcli
|
||||||
- check
|
- check
|
||||||
- http
|
- http
|
||||||
- localhost:{{ .Values.service.containerPort }}/readyz
|
- localhost:{{ .Values.service.httpPort | default 9898 }}/readyz
|
||||||
initialDelaySeconds: 1
|
{{- with .Values.probes.readiness }}
|
||||||
timeoutSeconds: 5
|
initialDelaySeconds: {{ .initialDelaySeconds | default 1 }}
|
||||||
|
timeoutSeconds: {{ .timeoutSeconds | default 5 }}
|
||||||
|
failureThreshold: {{ .failureThreshold | default 3 }}
|
||||||
|
successThreshold: {{ .successThreshold | default 1 }}
|
||||||
|
periodSeconds: {{ .periodSeconds | default 10 }}
|
||||||
|
{{- end }}
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: data
|
- name: data
|
||||||
mountPath: /data
|
mountPath: /data
|
||||||
|
{{- if .Values.tls.enabled }}
|
||||||
|
- name: tls
|
||||||
|
mountPath: {{ .Values.tls.certPath | default "/data/cert" }}
|
||||||
|
readOnly: true
|
||||||
|
{{- end }}
|
||||||
resources:
|
resources:
|
||||||
{{ toYaml .Values.resources | indent 12 }}
|
{{ toYaml .Values.resources | indent 12 }}
|
||||||
|
{{- with .Values.podSecurityContext }}
|
||||||
|
securityContext:
|
||||||
|
{{ toYaml . | indent 8 }}
|
||||||
|
{{- end }}
|
||||||
{{- with .Values.nodeSelector }}
|
{{- with .Values.nodeSelector }}
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
{{ toYaml . | indent 8 }}
|
{{ toYaml . | indent 8 }}
|
||||||
@@ -89,3 +218,12 @@ spec:
|
|||||||
volumes:
|
volumes:
|
||||||
- name: data
|
- name: data
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
|
{{- if .Values.tls.enabled }}
|
||||||
|
- name: tls
|
||||||
|
secret:
|
||||||
|
secretName: {{ template "podinfo.tlsSecretName" . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.topologySpreadConstraints }}
|
||||||
|
topologySpreadConstraints:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
|||||||
42
charts/podinfo/templates/grpcroute.yaml
Normal file
42
charts/podinfo/templates/grpcroute.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{{- if .Values.grpcRoute.enabled -}}
|
||||||
|
{{- $fullName := include "podinfo.fullname" . -}}
|
||||||
|
{{- $grpcPort := .Values.service.grpcPort -}}
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: GRPCRoute
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.grpcRoute.additionalLabels }}
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.grpcRoute.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
{{- with .Values.grpcRoute.parentRefs }}
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.grpcRoute.hostnames }}
|
||||||
|
hostnames:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.grpcRoute.rules }}
|
||||||
|
- backendRefs:
|
||||||
|
- name: {{ $fullName }}
|
||||||
|
port: {{ $grpcPort }}
|
||||||
|
weight: 1
|
||||||
|
{{- with .matches }}
|
||||||
|
matches:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .filters }}
|
||||||
|
filters:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
37
charts/podinfo/templates/hooks/job.yaml
Normal file
37
charts/podinfo/templates/hooks/job.yaml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{{- $hooks := dict "preInstall" "pre-install" "postInstall" "post-install" "preDelete" "pre-delete" "postDelete" "post-delete" "preUpgrade" "pre-upgrade" "postUpgrade" "post-upgrade" "preRollback" "pre-rollback" "postRollback" "post-rollback" }}
|
||||||
|
{{- range $hookName, $hookType := $hooks }}
|
||||||
|
{{- $hookConfig := index $.Values.hooks $hookName }}
|
||||||
|
{{- if and $hookConfig $hookConfig.job $hookConfig.job.enabled }}
|
||||||
|
---
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: {{ template "podinfo.fullname" $ }}-{{ $hookType }}
|
||||||
|
namespace: {{ include "podinfo.namespace" $ }}
|
||||||
|
labels:
|
||||||
|
{{- include "podinfo.labels" $ | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
"helm.sh/hook": {{ $hookType }}
|
||||||
|
"helm.sh/hook-delete-policy": {{ $hookConfig.job.hookDeletePolicy }}
|
||||||
|
spec:
|
||||||
|
{{- if kindIs "float64" $hookConfig.job.ttlSecondsAfterFinished }}
|
||||||
|
ttlSecondsAfterFinished: {{ $hookConfig.job.ttlSecondsAfterFinished | int }}
|
||||||
|
{{- end }}
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: job
|
||||||
|
image: "{{ $.Values.image.repository }}:{{ $.Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ $.Values.image.pullPolicy }}
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
{{- if kindIs "float64" $hookConfig.job.sleepSeconds }}
|
||||||
|
sleep {{ $hookConfig.job.sleepSeconds | int }}
|
||||||
|
{{- end }}
|
||||||
|
exit {{ $hookConfig.job.exitCode | default 0 }}
|
||||||
|
restartPolicy: Never
|
||||||
|
backoffLimit: 1
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
{{- if .Values.hpa.enabled -}}
|
{{- if .Values.hpa.enabled -}}
|
||||||
apiVersion: autoscaling/v2beta1
|
apiVersion: autoscaling/v2
|
||||||
kind: HorizontalPodAutoscaler
|
kind: HorizontalPodAutoscaler
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ template "podinfo.fullname" . }}
|
name: {{ template "podinfo.fullname" . }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
spec:
|
spec:
|
||||||
scaleTargetRef:
|
scaleTargetRef:
|
||||||
apiVersion: apps/v1beta2
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
name: {{ template "podinfo.fullname" . }}
|
name: {{ template "podinfo.fullname" . }}
|
||||||
minReplicas: {{ .Values.replicaCount }}
|
minReplicas: {{ .Values.replicaCount }}
|
||||||
@@ -15,18 +18,25 @@ spec:
|
|||||||
- type: Resource
|
- type: Resource
|
||||||
resource:
|
resource:
|
||||||
name: cpu
|
name: cpu
|
||||||
targetAverageUtilization: {{ .Values.hpa.cpu }}
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: {{ .Values.hpa.cpu }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if .Values.hpa.memory }}
|
{{- if .Values.hpa.memory }}
|
||||||
- type: Resource
|
- type: Resource
|
||||||
resource:
|
resource:
|
||||||
name: memory
|
name: memory
|
||||||
targetAverageValue: {{ .Values.hpa.memory }}
|
target:
|
||||||
|
type: AverageValue
|
||||||
|
averageValue: {{ .Values.hpa.memory }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if .Values.hpa.requests }}
|
{{- if .Values.hpa.requests }}
|
||||||
- type: Pod
|
- type: Pods
|
||||||
pods:
|
pods:
|
||||||
metricName: http_requests
|
metric:
|
||||||
targetAverageValue: {{ .Values.hpa.requests }}
|
name: http_requests
|
||||||
|
target:
|
||||||
|
type: AverageValue
|
||||||
|
averageValue: {{ .Values.hpa.requests }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
42
charts/podinfo/templates/httproute.yaml
Normal file
42
charts/podinfo/templates/httproute.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{{- if .Values.httpRoute.enabled -}}
|
||||||
|
{{- $fullName := include "podinfo.fullname" . -}}
|
||||||
|
{{- $svcPort := .Values.service.externalPort -}}
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.httpRoute.additionalLabels }}
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.httpRoute.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
{{- with .Values.httpRoute.parentRefs }}
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.httpRoute.hostnames }}
|
||||||
|
hostnames:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.httpRoute.rules }}
|
||||||
|
{{- with .matches }}
|
||||||
|
- matches:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .filters }}
|
||||||
|
filters:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
backendRefs:
|
||||||
|
- name: {{ $fullName }}
|
||||||
|
port: {{ $svcPort }}
|
||||||
|
weight: 1
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -1,39 +1,45 @@
|
|||||||
{{- if .Values.ingress.enabled -}}
|
{{- if .Values.ingress.enabled -}}
|
||||||
{{- $fullName := include "podinfo.fullname" . -}}
|
{{- $fullName := include "podinfo.fullname" . -}}
|
||||||
{{- $servicePort := .Values.service.port -}}
|
{{- $svcPort := .Values.service.externalPort -}}
|
||||||
{{- $ingressPath := .Values.ingress.path -}}
|
apiVersion: networking.k8s.io/v1
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Ingress
|
kind: Ingress
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ $fullName }}
|
name: {{ $fullName }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
labels:
|
labels:
|
||||||
app: {{ template "podinfo.name" . }}
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
chart: {{ template "podinfo.chart" . }}
|
{{- with .Values.ingress.additionalLabels }}
|
||||||
release: {{ .Release.Name }}
|
{{- toYaml . | nindent 4 }}
|
||||||
heritage: {{ .Release.Service }}
|
{{- end }}
|
||||||
{{- with .Values.ingress.annotations }}
|
{{- with .Values.ingress.annotations }}
|
||||||
annotations:
|
annotations:
|
||||||
{{ toYaml . | indent 4 }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
spec:
|
spec:
|
||||||
{{- if .Values.ingress.tls }}
|
ingressClassName: {{ .Values.ingress.className }}
|
||||||
tls:
|
{{- if .Values.ingress.tls }}
|
||||||
{{- range .Values.ingress.tls }}
|
tls:
|
||||||
- hosts:
|
{{- range .Values.ingress.tls }}
|
||||||
{{- range .hosts }}
|
- hosts:
|
||||||
- {{ . }}
|
{{- range .hosts }}
|
||||||
{{- end }}
|
- {{ . | quote }}
|
||||||
secretName: {{ .secretName }}
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
|
||||||
rules:
|
rules:
|
||||||
{{- range .Values.ingress.hosts }}
|
{{- range .Values.ingress.hosts }}
|
||||||
- host: {{ . }}
|
- host: {{ .host | quote }}
|
||||||
http:
|
http:
|
||||||
paths:
|
paths:
|
||||||
- path: {{ $ingressPath }}
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
pathType: {{ .pathType }}
|
||||||
backend:
|
backend:
|
||||||
serviceName: {{ $fullName }}
|
service:
|
||||||
servicePort: http
|
name: {{ $fullName }}
|
||||||
{{- end }}
|
port:
|
||||||
|
number: {{ $svcPort }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
14
charts/podinfo/templates/pdb.yaml
Normal file
14
charts/podinfo/templates/pdb.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{{- if and .Values.podDisruptionBudget (gt (int .Values.replicaCount) 1) }}
|
||||||
|
apiVersion: policy/v1
|
||||||
|
kind: PodDisruptionBudget
|
||||||
|
metadata:
|
||||||
|
name: {{ include "podinfo.fullname" . }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "podinfo.selectorLabels" . | nindent 6 }}
|
||||||
|
{{- toYaml .Values.podDisruptionBudget | nindent 2 }}
|
||||||
|
{{- end }}
|
||||||
12
charts/podinfo/templates/redis/config.yaml
Normal file
12
charts/podinfo/templates/redis/config.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{{- if .Values.redis.enabled -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ template "podinfo.fullname" . }}-redis
|
||||||
|
data:
|
||||||
|
redis.conf: |
|
||||||
|
maxmemory 64mb
|
||||||
|
maxmemory-policy allkeys-lru
|
||||||
|
save ""
|
||||||
|
appendonly no
|
||||||
|
{{- end }}
|
||||||
71
charts/podinfo/templates/redis/deployment.yaml
Normal file
71
charts/podinfo/templates/redis/deployment.yaml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
{{- if .Values.redis.enabled -}}
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ template "podinfo.fullname" . }}-redis
|
||||||
|
labels:
|
||||||
|
app: {{ template "podinfo.fullname" . }}-redis
|
||||||
|
spec:
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ template "podinfo.fullname" . }}-redis
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{ template "podinfo.fullname" . }}-redis
|
||||||
|
annotations:
|
||||||
|
checksum/config: {{ include (print $.Template.BasePath "/redis/config.yaml") . | sha256sum | quote }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.serviceAccount.enabled }}
|
||||||
|
serviceAccountName: {{ template "podinfo.serviceAccountName" . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.redis.imagePullSecrets }}
|
||||||
|
imagePullSecrets: {{ toYaml .Values.redis.imagePullSecrets | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
containers:
|
||||||
|
- name: redis
|
||||||
|
image: "{{ .Values.redis.repository }}:{{ .Values.redis.tag }}"
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command:
|
||||||
|
- redis-server
|
||||||
|
- "/redis-master/redis.conf"
|
||||||
|
ports:
|
||||||
|
- name: redis
|
||||||
|
containerPort: 6379
|
||||||
|
protocol: TCP
|
||||||
|
livenessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: redis
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- redis-cli
|
||||||
|
- ping
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 1000m
|
||||||
|
memory: 128Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 32Mi
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /var/lib/redis
|
||||||
|
name: data
|
||||||
|
- mountPath: /redis-master
|
||||||
|
name: config
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
emptyDir: {}
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: {{ template "podinfo.fullname" . }}-redis
|
||||||
|
items:
|
||||||
|
- key: redis.conf
|
||||||
|
path: redis.conf
|
||||||
|
{{- end }}
|
||||||
18
charts/podinfo/templates/redis/service.yaml
Normal file
18
charts/podinfo/templates/redis/service.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{{- if .Values.redis.enabled -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ template "podinfo.fullname" . }}-redis
|
||||||
|
labels:
|
||||||
|
app: {{ template "podinfo.fullname" . }}-redis
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: {{ template "podinfo.fullname" . }}-redis
|
||||||
|
ports:
|
||||||
|
- name: redis
|
||||||
|
port: 6379
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: redis
|
||||||
|
appProtocol: redis
|
||||||
|
{{- end }}
|
||||||
@@ -1,12 +1,18 @@
|
|||||||
|
{{- if .Values.service.enabled -}}
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ template "podinfo.fullname" . }}
|
name: {{ template "podinfo.fullname" . }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
labels:
|
labels:
|
||||||
app: {{ template "podinfo.name" . }}
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
chart: {{ template "podinfo.chart" . }}
|
{{- with .Values.service.additionalLabels }}
|
||||||
release: {{ .Release.Name }}
|
{{- toYaml . | nindent 4 }}
|
||||||
heritage: {{ .Release.Service }}
|
{{- end }}
|
||||||
|
{{- with .Values.service.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{ toYaml . | indent 4 }}
|
||||||
|
{{- end }}
|
||||||
spec:
|
spec:
|
||||||
type: {{ .Values.service.type }}
|
type: {{ .Values.service.type }}
|
||||||
ports:
|
ports:
|
||||||
@@ -17,6 +23,24 @@ spec:
|
|||||||
{{- if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort))) }}
|
{{- if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort))) }}
|
||||||
nodePort: {{ .Values.service.nodePort }}
|
nodePort: {{ .Values.service.nodePort }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.tls.enabled }}
|
||||||
|
- port: {{ .Values.tls.port | default 9899 }}
|
||||||
|
targetPort: https
|
||||||
|
protocol: TCP
|
||||||
|
name: https
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.service.grpcPort }}
|
||||||
|
- port: {{ .Values.service.grpcPort }}
|
||||||
|
targetPort: grpc
|
||||||
|
protocol: TCP
|
||||||
|
name: grpc
|
||||||
|
{{- end }}
|
||||||
selector:
|
selector:
|
||||||
app: {{ template "podinfo.name" . }}
|
{{- include "podinfo.selectorLabels" . | nindent 4 }}
|
||||||
release: {{ .Release.Name }}
|
{{- if .Values.service.trafficDistribution }}
|
||||||
|
trafficDistribution: {{ .Values.service.trafficDistribution }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if ( and (.Values.service.externalTrafficPolicy) (eq .Values.service.type "LoadBalancer") ) }}
|
||||||
|
externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|||||||
12
charts/podinfo/templates/serviceaccount.yaml
Normal file
12
charts/podinfo/templates/serviceaccount.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{{- if .Values.serviceAccount.enabled -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ template "podinfo.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceAccount.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 2 }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
23
charts/podinfo/templates/servicemonitor.yaml
Normal file
23
charts/podinfo/templates/servicemonitor.yaml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{{- if .Values.serviceMonitor.enabled -}}
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: ServiceMonitor
|
||||||
|
metadata:
|
||||||
|
name: {{ template "podinfo.fullname" . }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceMonitor.additionalLabels }}
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
endpoints:
|
||||||
|
- path: /metrics
|
||||||
|
port: http
|
||||||
|
interval: {{ .Values.serviceMonitor.interval }}
|
||||||
|
namespaceSelector:
|
||||||
|
matchNames:
|
||||||
|
- {{ include "podinfo.namespace" . }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "podinfo.selectorLabels" . | nindent 6 }}
|
||||||
|
{{- end }}
|
||||||
30
charts/podinfo/templates/tests/cache.yaml
Normal file
30
charts/podinfo/templates/tests/cache.yaml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{{- if .Values.cache }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: {{ template "podinfo.fullname" . }}-cache-test-{{ randAlphaNum 5 | lower }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
"helm.sh/hook": test
|
||||||
|
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||||
|
sidecar.istio.io/inject: "false"
|
||||||
|
linkerd.io/inject: disabled
|
||||||
|
appmesh.k8s.aws/sidecarInjectorWebhook: disabled
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: curl
|
||||||
|
image: curlimages/curl:7.69.0
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
curl -sd 'data' ${PODINFO_SVC}/cache/test &&
|
||||||
|
curl -s ${PODINFO_SVC}/cache/test | grep data &&
|
||||||
|
curl -s -XDELETE ${PODINFO_SVC}/cache/test
|
||||||
|
env:
|
||||||
|
- name: PODINFO_SVC
|
||||||
|
value: "{{ template "podinfo.fullname" . }}.{{ include "podinfo.namespace" . }}:{{ .Values.service.externalPort }}"
|
||||||
|
restartPolicy: Never
|
||||||
|
{{- end }}
|
||||||
22
charts/podinfo/templates/tests/fail.yaml
Normal file
22
charts/podinfo/templates/tests/fail.yaml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{{- if .Values.faults.testFail }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: {{ template "podinfo.fullname" . }}-fault-test-{{ randAlphaNum 5 | lower }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
"helm.sh/hook": test-success
|
||||||
|
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||||
|
sidecar.istio.io/inject: "false"
|
||||||
|
linkerd.io/inject: disabled
|
||||||
|
appmesh.k8s.aws/sidecarInjectorWebhook: disabled
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: fault
|
||||||
|
image: alpine:3.11
|
||||||
|
command: ['/bin/sh']
|
||||||
|
args: ['-c', 'exit 1']
|
||||||
|
restartPolicy: Never
|
||||||
|
{{- end }}
|
||||||
20
charts/podinfo/templates/tests/grpc.yaml
Normal file
20
charts/podinfo/templates/tests/grpc.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: {{ template "podinfo.fullname" . }}-grpc-test-{{ randAlphaNum 5 | lower }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
"helm.sh/hook": test-success
|
||||||
|
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||||
|
sidecar.istio.io/inject: "false"
|
||||||
|
linkerd.io/inject: disabled
|
||||||
|
appmesh.k8s.aws/sidecarInjectorWebhook: disabled
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: grpc-health-probe
|
||||||
|
image: stefanprodan/grpc_health_probe:v0.3.0
|
||||||
|
command: ['grpc_health_probe']
|
||||||
|
args: ['-addr={{ template "podinfo.fullname" . }}.{{ include "podinfo.namespace" . }}:{{ .Values.service.grpcPort }}']
|
||||||
|
restartPolicy: Never
|
||||||
@@ -2,42 +2,26 @@ apiVersion: v1
|
|||||||
kind: Pod
|
kind: Pod
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ template "podinfo.fullname" . }}-jwt-test-{{ randAlphaNum 5 | lower }}
|
name: {{ template "podinfo.fullname" . }}-jwt-test-{{ randAlphaNum 5 | lower }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
labels:
|
labels:
|
||||||
heritage: {{ .Release.Service }}
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
release: {{ .Release.Name }}
|
|
||||||
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
|
||||||
app: {{ template "podinfo.name" . }}
|
|
||||||
annotations:
|
annotations:
|
||||||
"helm.sh/hook": test-success
|
"helm.sh/hook": test-success
|
||||||
|
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||||
|
sidecar.istio.io/inject: "false"
|
||||||
|
linkerd.io/inject: disabled
|
||||||
|
appmesh.k8s.aws/sidecarInjectorWebhook: disabled
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: tools
|
- name: tools
|
||||||
image: giantswarm/tiny-tools
|
image: giantswarm/tiny-tools
|
||||||
command: ["/bin/sh", "/scripts/test.sh"]
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
TOKEN=$(curl -sd 'test' ${PODINFO_SVC}/token | jq -r .token) &&
|
||||||
|
curl -sH "Authorization: Bearer ${TOKEN}" ${PODINFO_SVC}/token/validate | grep test
|
||||||
env:
|
env:
|
||||||
- name: PODINFO_SVC
|
- name: PODINFO_SVC
|
||||||
value: {{ template "podinfo.fullname" . }}:{{ .Values.service.externalPort }}
|
value: "{{ template "podinfo.fullname" . }}.{{ include "podinfo.namespace" . }}:{{ .Values.service.externalPort }}"
|
||||||
volumeMounts:
|
|
||||||
- name: scripts
|
|
||||||
mountPath: /scripts
|
|
||||||
restartPolicy: Never
|
restartPolicy: Never
|
||||||
volumes:
|
|
||||||
- name: scripts
|
|
||||||
configMap:
|
|
||||||
name: {{ template "podinfo.fullname" . }}-storage-cfg
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: {{ template "podinfo.fullname" . }}-storage-cfg
|
|
||||||
labels:
|
|
||||||
heritage: {{ .Release.Service }}
|
|
||||||
release: {{ .Release.Name }}
|
|
||||||
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
|
||||||
app: {{ template "podinfo.name" . }}
|
|
||||||
data:
|
|
||||||
test.sh: |
|
|
||||||
#!/bin/sh
|
|
||||||
echo "testing ${PODINFO_SVC}/token"
|
|
||||||
TOKEN=$(curl -sd 'test' ${PODINFO_SVC}/token | jq -r .token) && \
|
|
||||||
curl -H "Authorization: Bearer ${TOKEN}" ${PODINFO_SVC}/token/validate | grep test
|
|
||||||
|
|||||||
@@ -2,17 +2,25 @@ apiVersion: v1
|
|||||||
kind: Pod
|
kind: Pod
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ template "podinfo.fullname" . }}-service-test-{{ randAlphaNum 5 | lower }}
|
name: {{ template "podinfo.fullname" . }}-service-test-{{ randAlphaNum 5 | lower }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
labels:
|
labels:
|
||||||
heritage: {{ .Release.Service }}
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
release: {{ .Release.Name }}
|
|
||||||
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
|
||||||
app: {{ template "podinfo.name" . }}
|
|
||||||
annotations:
|
annotations:
|
||||||
"helm.sh/hook": test-success
|
"helm.sh/hook": test-success
|
||||||
|
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||||
|
sidecar.istio.io/inject: "false"
|
||||||
|
linkerd.io/inject: disabled
|
||||||
|
appmesh.k8s.aws/sidecarInjectorWebhook: disabled
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: curl
|
- name: curl
|
||||||
image: radial/busyboxplus:curl
|
image: curlimages/curl:7.69.0
|
||||||
command: ['curl']
|
command:
|
||||||
args: ['{{ template "podinfo.fullname" . }}:{{ .Values.service.externalPort }}']
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
curl -s ${PODINFO_SVC}/api/info | grep version
|
||||||
|
env:
|
||||||
|
- name: PODINFO_SVC
|
||||||
|
value: "{{ template "podinfo.fullname" . }}.{{ include "podinfo.namespace" . }}:{{ .Values.service.externalPort }}"
|
||||||
restartPolicy: Never
|
restartPolicy: Never
|
||||||
|
|||||||
22
charts/podinfo/templates/tests/timeout.yaml
Normal file
22
charts/podinfo/templates/tests/timeout.yaml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{{- if .Values.faults.testTimeout }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: {{ template "podinfo.fullname" . }}-fault-test-{{ randAlphaNum 5 | lower }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
"helm.sh/hook": test-success
|
||||||
|
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||||
|
sidecar.istio.io/inject: "false"
|
||||||
|
linkerd.io/inject: disabled
|
||||||
|
appmesh.k8s.aws/sidecarInjectorWebhook: disabled
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: fault
|
||||||
|
image: alpine:3.11
|
||||||
|
command: ['/bin/sh']
|
||||||
|
args: ['-c', 'while sleep 3600; do :; done']
|
||||||
|
restartPolicy: Never
|
||||||
|
{{- end }}
|
||||||
28
charts/podinfo/templates/tests/tls.yaml
Normal file
28
charts/podinfo/templates/tests/tls.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{{- if .Values.tls.enabled -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: {{ template "podinfo.fullname" . }}-tls-test-{{ randAlphaNum 5 | lower }}
|
||||||
|
namespace: {{ include "podinfo.namespace" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "podinfo.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
"helm.sh/hook": test-success
|
||||||
|
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||||
|
sidecar.istio.io/inject: "false"
|
||||||
|
linkerd.io/inject: disabled
|
||||||
|
appmesh.k8s.aws/sidecarInjectorWebhook: disabled
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: curl
|
||||||
|
image: curlimages/curl:7.69.0
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
curl -sk ${PODINFO_SVC}/api/info | grep version
|
||||||
|
env:
|
||||||
|
- name: PODINFO_SVC
|
||||||
|
value: "https://{{ template "podinfo.fullname" . }}.{{ include "podinfo.namespace" . }}:{{ .Values.tls.port }}"
|
||||||
|
restartPolicy: Never
|
||||||
|
{{- end }}
|
||||||
210
charts/podinfo/values-prod.yaml
Normal file
210
charts/podinfo/values-prod.yaml
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
# Production values for podinfo.
|
||||||
|
# Includes Redis deployment and memory limits.
|
||||||
|
|
||||||
|
replicaCount: 1
|
||||||
|
logLevel: info
|
||||||
|
backend: #http://backend-podinfo:9898/echo
|
||||||
|
backends: []
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/stefanprodan/podinfo
|
||||||
|
tag: 6.11.2
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
ui:
|
||||||
|
color: "#34577c"
|
||||||
|
message: ""
|
||||||
|
logo: ""
|
||||||
|
|
||||||
|
# failure conditions
|
||||||
|
faults:
|
||||||
|
delay: false
|
||||||
|
error: false
|
||||||
|
unhealthy: false
|
||||||
|
unready: false
|
||||||
|
testFail: false
|
||||||
|
testTimeout: false
|
||||||
|
|
||||||
|
# Kubernetes Service settings
|
||||||
|
service:
|
||||||
|
enabled: true
|
||||||
|
annotations: {}
|
||||||
|
additionalLabels: { }
|
||||||
|
type: ClusterIP
|
||||||
|
metricsPort: 9797
|
||||||
|
httpPort: 9898
|
||||||
|
externalPort: 9898
|
||||||
|
grpcPort: 9999
|
||||||
|
grpcService: podinfo
|
||||||
|
nodePort: 31198
|
||||||
|
trafficDistribution: ""
|
||||||
|
externalTrafficPolicy: ""
|
||||||
|
|
||||||
|
# enable h2c protocol (non-TLS version of HTTP/2)
|
||||||
|
h2c:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# config file settings
|
||||||
|
config:
|
||||||
|
# config file path
|
||||||
|
path: ""
|
||||||
|
# config file name
|
||||||
|
name: ""
|
||||||
|
|
||||||
|
# Additional command line arguments to pass to podinfo container
|
||||||
|
extraArgs: []
|
||||||
|
|
||||||
|
# enable tls on the podinfo service
|
||||||
|
tls:
|
||||||
|
enabled: false
|
||||||
|
# the name of the secret used to mount the certificate key pair
|
||||||
|
secretName:
|
||||||
|
# the path where the certificate key pair will be mounted
|
||||||
|
certPath: /data/cert
|
||||||
|
# the port used to host the tls endpoint on the service
|
||||||
|
port: 9899
|
||||||
|
# the port used to bind the tls port to the host
|
||||||
|
# NOTE: requires privileged container with NET_BIND_SERVICE capability -- this is useful for testing
|
||||||
|
# in local clusters such as kind without port forwarding
|
||||||
|
hostPort:
|
||||||
|
|
||||||
|
# create a certificate manager certificate (cert-manager required)
|
||||||
|
certificate:
|
||||||
|
create: false
|
||||||
|
# the issuer used to issue the certificate
|
||||||
|
issuerRef:
|
||||||
|
kind: ClusterIssuer
|
||||||
|
name: self-signed
|
||||||
|
# the hostname / subject alternative names for the certificate
|
||||||
|
dnsNames:
|
||||||
|
- podinfo
|
||||||
|
|
||||||
|
# metrics-server add-on required
|
||||||
|
hpa:
|
||||||
|
enabled: true
|
||||||
|
maxReplicas: 5
|
||||||
|
# average total CPU usage per pod (1-100)
|
||||||
|
cpu: 99
|
||||||
|
# average memory usage per pod (100Mi-1Gi)
|
||||||
|
memory:
|
||||||
|
# average http requests per second per pod (k8s-prometheus-adapter)
|
||||||
|
requests:
|
||||||
|
|
||||||
|
# Redis address in the format tcp://<host>:<port>
|
||||||
|
cache: ""
|
||||||
|
# Redis deployment
|
||||||
|
redis:
|
||||||
|
enabled: true
|
||||||
|
repository: redis
|
||||||
|
tag: 8.6.1
|
||||||
|
|
||||||
|
serviceAccount:
|
||||||
|
# Specifies whether a service account should be created
|
||||||
|
enabled: false
|
||||||
|
# The name of the service account to use.
|
||||||
|
# If not set and create is true, a name is generated using the fullname template
|
||||||
|
name:
|
||||||
|
# List of image pull secrets if pulling from private registries
|
||||||
|
imagePullSecrets: []
|
||||||
|
|
||||||
|
# set container security context
|
||||||
|
securityContext: {}
|
||||||
|
|
||||||
|
# set pod security context
|
||||||
|
podSecurityContext: {}
|
||||||
|
|
||||||
|
# -- Expose the service via Kubernetes Ingress
|
||||||
|
# Requires an Ingress controller
|
||||||
|
# Docs https://kubernetes.io/docs/concepts/services-networking/ingress/
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
className: ""
|
||||||
|
additionalLabels: {}
|
||||||
|
annotations: {}
|
||||||
|
# kubernetes.io/ingress.class: nginx
|
||||||
|
# kubernetes.io/tls-acme: "true"
|
||||||
|
hosts:
|
||||||
|
- host: podinfo.local
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: ImplementationSpecific
|
||||||
|
tls: []
|
||||||
|
# - secretName: chart-example-tls
|
||||||
|
# hosts:
|
||||||
|
# - chart-example.local
|
||||||
|
|
||||||
|
# -- Expose the service via Gateway HTTPRoute
|
||||||
|
# Requires a Gateway controller
|
||||||
|
# Docs https://gateway-api.sigs.k8s.io/guides/
|
||||||
|
httpRoute:
|
||||||
|
# HTTPRoute enabled.
|
||||||
|
enabled: false
|
||||||
|
# Add additional labels to the HTTPRoute.
|
||||||
|
additionalLabels: {}
|
||||||
|
# HTTPRoute annotations.
|
||||||
|
annotations: {}
|
||||||
|
# Which Gateways this Route is attached to.
|
||||||
|
parentRefs:
|
||||||
|
- name: gateway
|
||||||
|
sectionName: http
|
||||||
|
# namespace: default
|
||||||
|
# Hostnames matching HTTP header.
|
||||||
|
hostnames:
|
||||||
|
- podinfo.local
|
||||||
|
# List of rules and filters applied.
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
|
||||||
|
# create Prometheus Operator monitor
|
||||||
|
serviceMonitor:
|
||||||
|
enabled: false
|
||||||
|
interval: 15s
|
||||||
|
additionalLabels: {}
|
||||||
|
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 64Mi
|
||||||
|
|
||||||
|
# Extra environment variables for the podinfo container
|
||||||
|
extraEnvs: []
|
||||||
|
# Example on how to configure extraEnvs
|
||||||
|
# - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
|
||||||
|
# value: "http://otel:4317"
|
||||||
|
# - name: MULTIPLE_VALUES
|
||||||
|
# value: TEST
|
||||||
|
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
podAnnotations: {}
|
||||||
|
|
||||||
|
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes
|
||||||
|
probes:
|
||||||
|
readiness:
|
||||||
|
initialDelaySeconds: 1
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
successThreshold: 1
|
||||||
|
periodSeconds: 10
|
||||||
|
liveness:
|
||||||
|
initialDelaySeconds: 1
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
successThreshold: 1
|
||||||
|
periodSeconds: 10
|
||||||
|
startup:
|
||||||
|
enable: false
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 20
|
||||||
|
successThreshold: 1
|
||||||
|
periodSeconds: 10
|
||||||
@@ -2,24 +2,155 @@
|
|||||||
|
|
||||||
replicaCount: 1
|
replicaCount: 1
|
||||||
logLevel: info
|
logLevel: info
|
||||||
color: blue
|
host: #0.0.0.0
|
||||||
backend: #http://backend-podinfo:9898/echo
|
backend: #http://backend-podinfo:9898/echo
|
||||||
message: #UI greetings
|
backends: []
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/stefanprodan/podinfo
|
||||||
|
tag: 6.11.2
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
pullSecrets: []
|
||||||
|
|
||||||
|
ui:
|
||||||
|
color: "#34577c"
|
||||||
|
message: ""
|
||||||
|
logo: ""
|
||||||
|
|
||||||
|
# failure conditions
|
||||||
faults:
|
faults:
|
||||||
delay: false
|
delay: false
|
||||||
error: false
|
error: false
|
||||||
|
unhealthy: false
|
||||||
|
unready: false
|
||||||
|
testFail: false
|
||||||
|
testTimeout: false
|
||||||
|
|
||||||
image:
|
# Kubernetes Service settings
|
||||||
repository: quay.io/stefanprodan/podinfo
|
|
||||||
tag: 2.0.1
|
|
||||||
pullPolicy: IfNotPresent
|
|
||||||
|
|
||||||
service:
|
service:
|
||||||
|
enabled: true
|
||||||
|
annotations: {}
|
||||||
|
additionalLabels: { }
|
||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
|
metricsPort: 9797
|
||||||
|
httpPort: 9898
|
||||||
externalPort: 9898
|
externalPort: 9898
|
||||||
containerPort: 9898
|
grpcPort: 9999
|
||||||
|
grpcService: podinfo
|
||||||
nodePort: 31198
|
nodePort: 31198
|
||||||
|
# the port used to bind the http port to the host
|
||||||
|
# NOTE: requires privileged container with NET_BIND_SERVICE capability -- this is useful for testing
|
||||||
|
# in local clusters such as kind without port forwarding
|
||||||
|
hostPort:
|
||||||
|
# Stable from Kubernetes v1.33+ with a value of PreferClose. Additional values are PreferSameZone and PreferSameNode from v1.34+. Empty string means it's disabled.
|
||||||
|
trafficDistribution: ""
|
||||||
|
externalTrafficPolicy: ""
|
||||||
|
|
||||||
|
# enable h2c protocol (non-TLS version of HTTP/2)
|
||||||
|
h2c:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# config file settings
|
||||||
|
config:
|
||||||
|
# config file path
|
||||||
|
path: ""
|
||||||
|
# config file name
|
||||||
|
name: ""
|
||||||
|
|
||||||
|
# Additional command line arguments to pass to podinfo container
|
||||||
|
extraArgs: []
|
||||||
|
|
||||||
|
# Extra environment variables for the podinfo container
|
||||||
|
extraEnvs: []
|
||||||
|
# Example on how to configure extraEnvs
|
||||||
|
# - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
|
||||||
|
# value: "http://otel:4317"
|
||||||
|
# - name: MULTIPLE_VALUES
|
||||||
|
# value: TEST
|
||||||
|
|
||||||
|
# enable tls on the podinfo service
|
||||||
|
tls:
|
||||||
|
enabled: false
|
||||||
|
# the name of the secret used to mount the certificate key pair
|
||||||
|
secretName:
|
||||||
|
# the path where the certificate key pair will be mounted
|
||||||
|
certPath: /data/cert
|
||||||
|
# the port used to host the tls endpoint on the service
|
||||||
|
port: 9899
|
||||||
|
# the port used to bind the tls port to the host
|
||||||
|
# NOTE: requires privileged container with NET_BIND_SERVICE capability -- this is useful for testing
|
||||||
|
# in local clusters such as kind without port forwarding
|
||||||
|
hostPort:
|
||||||
|
|
||||||
|
# create a certificate manager certificate (cert-manager required)
|
||||||
|
certificate:
|
||||||
|
create: false
|
||||||
|
# the issuer used to issue the certificate
|
||||||
|
issuerRef:
|
||||||
|
kind: ClusterIssuer
|
||||||
|
name: self-signed
|
||||||
|
# the hostname / subject alternative names for the certificate
|
||||||
|
dnsNames:
|
||||||
|
- podinfo
|
||||||
|
|
||||||
|
# Helm hooks (for testing purposes)
|
||||||
|
hooks:
|
||||||
|
preInstall:
|
||||||
|
job:
|
||||||
|
enabled: false
|
||||||
|
hookDeletePolicy: hook-succeeded,hook-failed
|
||||||
|
ttlSecondsAfterFinished:
|
||||||
|
sleepSeconds:
|
||||||
|
exitCode: 0
|
||||||
|
postInstall:
|
||||||
|
job:
|
||||||
|
enabled: false
|
||||||
|
hookDeletePolicy: hook-succeeded,hook-failed
|
||||||
|
ttlSecondsAfterFinished:
|
||||||
|
sleepSeconds:
|
||||||
|
exitCode: 0
|
||||||
|
preDelete:
|
||||||
|
job:
|
||||||
|
enabled: false
|
||||||
|
hookDeletePolicy: hook-succeeded,hook-failed
|
||||||
|
ttlSecondsAfterFinished:
|
||||||
|
sleepSeconds:
|
||||||
|
exitCode: 0
|
||||||
|
postDelete:
|
||||||
|
job:
|
||||||
|
enabled: false
|
||||||
|
hookDeletePolicy: hook-succeeded,hook-failed
|
||||||
|
ttlSecondsAfterFinished:
|
||||||
|
sleepSeconds:
|
||||||
|
exitCode: 0
|
||||||
|
preUpgrade:
|
||||||
|
job:
|
||||||
|
enabled: false
|
||||||
|
hookDeletePolicy: hook-succeeded,hook-failed
|
||||||
|
ttlSecondsAfterFinished:
|
||||||
|
sleepSeconds:
|
||||||
|
exitCode: 0
|
||||||
|
postUpgrade:
|
||||||
|
job:
|
||||||
|
enabled: false
|
||||||
|
hookDeletePolicy: hook-succeeded,hook-failed
|
||||||
|
ttlSecondsAfterFinished:
|
||||||
|
sleepSeconds:
|
||||||
|
exitCode: 0
|
||||||
|
preRollback:
|
||||||
|
job:
|
||||||
|
enabled: false
|
||||||
|
hookDeletePolicy: hook-succeeded,hook-failed
|
||||||
|
ttlSecondsAfterFinished:
|
||||||
|
sleepSeconds:
|
||||||
|
exitCode: 0
|
||||||
|
postRollback:
|
||||||
|
job:
|
||||||
|
enabled: false
|
||||||
|
hookDeletePolicy: hook-succeeded,hook-failed
|
||||||
|
ttlSecondsAfterFinished:
|
||||||
|
sleepSeconds:
|
||||||
|
exitCode: 0
|
||||||
|
|
||||||
# metrics-server add-on required
|
# metrics-server add-on required
|
||||||
hpa:
|
hpa:
|
||||||
@@ -32,19 +163,103 @@ hpa:
|
|||||||
# average http requests per second per pod (k8s-prometheus-adapter)
|
# average http requests per second per pod (k8s-prometheus-adapter)
|
||||||
requests:
|
requests:
|
||||||
|
|
||||||
|
# Redis address in the format tcp://<host>:<port>
|
||||||
|
cache: ""
|
||||||
|
# Redis deployment
|
||||||
|
redis:
|
||||||
|
enabled: false
|
||||||
|
repository: docker.io/redis
|
||||||
|
tag: 8.6.1
|
||||||
|
imagePullSecrets: []
|
||||||
|
|
||||||
|
serviceAccount:
|
||||||
|
# Specifies whether a service account should be created
|
||||||
|
enabled: false
|
||||||
|
# The name of the service account to use.
|
||||||
|
# If not set and create is true, a name is generated using the fullname template
|
||||||
|
name:
|
||||||
|
# List of image pull secrets if pulling from private registries
|
||||||
|
imagePullSecrets: []
|
||||||
|
|
||||||
|
# set container security context
|
||||||
|
securityContext: {}
|
||||||
|
|
||||||
|
# set pod security context
|
||||||
|
podSecurityContext: {}
|
||||||
|
|
||||||
|
# -- Expose the service via Kubernetes Ingress
|
||||||
|
# Requires an Ingress controller
|
||||||
|
# Docs https://kubernetes.io/docs/concepts/services-networking/ingress/
|
||||||
ingress:
|
ingress:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
className: ""
|
||||||
|
additionalLabels: {}
|
||||||
annotations: {}
|
annotations: {}
|
||||||
# kubernetes.io/ingress.class: nginx
|
# kubernetes.io/ingress.class: nginx
|
||||||
# kubernetes.io/tls-acme: "true"
|
# kubernetes.io/tls-acme: "true"
|
||||||
path: /
|
|
||||||
hosts:
|
hosts:
|
||||||
- podinfo.local
|
- host: podinfo.local
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: ImplementationSpecific
|
||||||
tls: []
|
tls: []
|
||||||
# - secretName: chart-example-tls
|
# - secretName: chart-example-tls
|
||||||
# hosts:
|
# hosts:
|
||||||
# - chart-example.local
|
# - chart-example.local
|
||||||
|
|
||||||
|
# -- Expose the service via Gateway HTTPRoute
|
||||||
|
# Requires a Gateway controller
|
||||||
|
# Docs https://gateway-api.sigs.k8s.io/guides/
|
||||||
|
httpRoute:
|
||||||
|
# HTTPRoute enabled.
|
||||||
|
enabled: false
|
||||||
|
# Add additional labels to the HTTPRoute.
|
||||||
|
additionalLabels: {}
|
||||||
|
# HTTPRoute annotations.
|
||||||
|
annotations: {}
|
||||||
|
# Which Gateways this Route is attached to.
|
||||||
|
parentRefs:
|
||||||
|
- name: gateway
|
||||||
|
sectionName: http
|
||||||
|
# namespace: default
|
||||||
|
# Hostnames matching HTTP header.
|
||||||
|
hostnames:
|
||||||
|
- podinfo.local
|
||||||
|
# List of rules and filters applied.
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
|
||||||
|
# -- Expose the gRPC service via Gateway GRPCRoute
|
||||||
|
# Requires a Gateway controller with GRPCRoute support
|
||||||
|
# Docs https://gateway-api.sigs.k8s.io/guides/grpc-routing/
|
||||||
|
grpcRoute:
|
||||||
|
# GRPCRoute enabled.
|
||||||
|
enabled: false
|
||||||
|
# Add additional labels to the GRPCRoute.
|
||||||
|
additionalLabels: {}
|
||||||
|
# GRPCRoute annotations.
|
||||||
|
annotations: {}
|
||||||
|
# Which Gateways this Route is attached to.
|
||||||
|
parentRefs:
|
||||||
|
- name: gateway
|
||||||
|
sectionName: http
|
||||||
|
# namespace: default
|
||||||
|
# Hostnames matching HTTP header.
|
||||||
|
hostnames:
|
||||||
|
- podinfo.local
|
||||||
|
# List of rules applied.
|
||||||
|
rules:
|
||||||
|
- {}
|
||||||
|
|
||||||
|
# create Prometheus Operator monitor
|
||||||
|
serviceMonitor:
|
||||||
|
enabled: false
|
||||||
|
interval: 15s
|
||||||
|
additionalLabels: {}
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
requests:
|
requests:
|
||||||
@@ -57,3 +272,33 @@ tolerations: []
|
|||||||
|
|
||||||
affinity: {}
|
affinity: {}
|
||||||
|
|
||||||
|
podAnnotations: {}
|
||||||
|
|
||||||
|
# https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
|
||||||
|
topologySpreadConstraints: []
|
||||||
|
|
||||||
|
# Disruption budget will be configured only when the replicaCount is greater than 1
|
||||||
|
podDisruptionBudget: {}
|
||||||
|
# maxUnavailable: 1
|
||||||
|
|
||||||
|
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes
|
||||||
|
probes:
|
||||||
|
readiness:
|
||||||
|
initialDelaySeconds: 1
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
successThreshold: 1
|
||||||
|
periodSeconds: 10
|
||||||
|
liveness:
|
||||||
|
initialDelaySeconds: 1
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
successThreshold: 1
|
||||||
|
periodSeconds: 10
|
||||||
|
startup:
|
||||||
|
enable: false
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 20
|
||||||
|
successThreshold: 1
|
||||||
|
periodSeconds: 10
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
steps:
|
|
||||||
- name: 'gcr.io/cloud-builders/docker'
|
|
||||||
args: ['build','-f' , 'Dockerfile', '-t', 'gcr.io/$PROJECT_ID/podinfo:$BRANCH_NAME-$SHORT_SHA', '.']
|
|
||||||
images: ['gcr.io/$PROJECT_ID/podinfo:$BRANCH_NAME-$SHORT_SHA']
|
|
||||||
@@ -12,16 +12,25 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/credentials"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
|
"google.golang.org/grpc/health/grpc_health_v1"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
retryCount int
|
retryCount int
|
||||||
retryDelay time.Duration
|
retryDelay time.Duration
|
||||||
method string
|
method string
|
||||||
body string
|
body string
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
|
grpcServiceName string
|
||||||
|
grpcTLS bool
|
||||||
)
|
)
|
||||||
|
|
||||||
var checkCmd = &cobra.Command{
|
var checkCmd = &cobra.Command{
|
||||||
@@ -51,6 +60,20 @@ var checkCertCmd = &cobra.Command{
|
|||||||
RunE: runCheckCert,
|
RunE: runCheckCert,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var checkgRPCCmd = &cobra.Command{
|
||||||
|
Use: `grpc [address]`,
|
||||||
|
Short: "gRPC health check",
|
||||||
|
Example: ` check grpc localhost:8080 --service=podinfo --retry=1 --delay=2s --timeout=2s`,
|
||||||
|
RunE: runCheckgPRC,
|
||||||
|
}
|
||||||
|
|
||||||
|
var checkWsCmd = &cobra.Command{
|
||||||
|
Use: `ws [address]`,
|
||||||
|
Short: "WebSocket round-trip health check",
|
||||||
|
Example: ` check ws ws://localhost:9898/ws/echo --retry=1 --delay=2s --timeout=5s`,
|
||||||
|
RunE: runCheckWs,
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
checkUrlCmd.Flags().StringVar(&method, "method", "GET", "HTTP method")
|
checkUrlCmd.Flags().StringVar(&method, "method", "GET", "HTTP method")
|
||||||
checkUrlCmd.Flags().StringVar(&body, "body", "", "HTTP POST/PUT content")
|
checkUrlCmd.Flags().StringVar(&body, "body", "", "HTTP POST/PUT content")
|
||||||
@@ -64,8 +87,20 @@ func init() {
|
|||||||
checkTcpCmd.Flags().DurationVar(&timeout, "timeout", 5*time.Second, "timeout")
|
checkTcpCmd.Flags().DurationVar(&timeout, "timeout", 5*time.Second, "timeout")
|
||||||
checkCmd.AddCommand(checkTcpCmd)
|
checkCmd.AddCommand(checkTcpCmd)
|
||||||
|
|
||||||
|
checkgRPCCmd.Flags().IntVar(&retryCount, "retry", 0, "times to retry the TCP check")
|
||||||
|
checkgRPCCmd.Flags().DurationVar(&retryDelay, "delay", 1*time.Second, "wait duration between retries")
|
||||||
|
checkgRPCCmd.Flags().DurationVar(&timeout, "timeout", 5*time.Second, "timeout")
|
||||||
|
checkgRPCCmd.Flags().StringVar(&grpcServiceName, "service", "", "gRPC service name")
|
||||||
|
checkgRPCCmd.Flags().BoolVar(&grpcTLS, "tls", false, "use TLS for gRPC connection")
|
||||||
|
checkCmd.AddCommand(checkgRPCCmd)
|
||||||
|
|
||||||
checkCmd.AddCommand(checkCertCmd)
|
checkCmd.AddCommand(checkCertCmd)
|
||||||
|
|
||||||
|
checkWsCmd.Flags().IntVar(&retryCount, "retry", 0, "times to retry the WebSocket check")
|
||||||
|
checkWsCmd.Flags().DurationVar(&retryDelay, "delay", 1*time.Second, "wait duration between retries")
|
||||||
|
checkWsCmd.Flags().DurationVar(&timeout, "timeout", 5*time.Second, "timeout")
|
||||||
|
checkCmd.AddCommand(checkWsCmd)
|
||||||
|
|
||||||
rootCmd.AddCommand(checkCmd)
|
rootCmd.AddCommand(checkCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,3 +278,126 @@ func fmtContentLength(b int64) string {
|
|||||||
}
|
}
|
||||||
return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp])
|
return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runCheckWs(cmd *cobra.Command, args []string) error {
|
||||||
|
if retryCount < 0 {
|
||||||
|
return fmt.Errorf("--retry is required")
|
||||||
|
}
|
||||||
|
if len(args) < 1 {
|
||||||
|
return fmt.Errorf("address is required! example: check ws wss://localhost:9898/ws/echo")
|
||||||
|
}
|
||||||
|
|
||||||
|
address := args[0]
|
||||||
|
if !strings.HasPrefix(address, "ws://") && !strings.HasPrefix(address, "wss://") {
|
||||||
|
return fmt.Errorf("address must start with ws:// or wss://")
|
||||||
|
}
|
||||||
|
|
||||||
|
for n := 0; n <= retryCount; n++ {
|
||||||
|
if n != 0 {
|
||||||
|
time.Sleep(retryDelay)
|
||||||
|
}
|
||||||
|
|
||||||
|
dialer := websocket.Dialer{
|
||||||
|
HandshakeTimeout: timeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, _, err := dialer.Dial(address, nil)
|
||||||
|
if err != nil {
|
||||||
|
logger.Info("check failed",
|
||||||
|
zap.String("address", address),
|
||||||
|
zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := "podinfo-check"
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
conn.SetWriteDeadline(start.Add(timeout))
|
||||||
|
if err := conn.WriteMessage(websocket.TextMessage, []byte(msg)); err != nil {
|
||||||
|
conn.Close()
|
||||||
|
logger.Info("check failed",
|
||||||
|
zap.String("address", address),
|
||||||
|
zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
_, resp, err := conn.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
logger.Info("check failed",
|
||||||
|
zap.String("address", address),
|
||||||
|
zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
rtt := time.Since(start)
|
||||||
|
conn.Close()
|
||||||
|
|
||||||
|
logger.Info("check succeed",
|
||||||
|
zap.String("address", address),
|
||||||
|
zap.Duration("round-trip", rtt),
|
||||||
|
zap.Int("response size", len(resp)))
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(1)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCheckgPRC(cmd *cobra.Command, args []string) error {
|
||||||
|
if retryCount < 0 {
|
||||||
|
return fmt.Errorf("--retry is required")
|
||||||
|
}
|
||||||
|
if len(args) < 1 {
|
||||||
|
return fmt.Errorf("address is required! example: check grpc localhost:8080")
|
||||||
|
}
|
||||||
|
address := args[0]
|
||||||
|
|
||||||
|
var creds grpc.DialOption
|
||||||
|
if grpcTLS {
|
||||||
|
creds = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))
|
||||||
|
} else {
|
||||||
|
creds = grpc.WithTransportCredentials(insecure.NewCredentials())
|
||||||
|
}
|
||||||
|
|
||||||
|
for n := 0; n <= retryCount; n++ {
|
||||||
|
if n != 0 {
|
||||||
|
time.Sleep(retryDelay)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := grpc.NewClient(address, creds)
|
||||||
|
if err != nil {
|
||||||
|
logger.Info("check failed",
|
||||||
|
zap.String("address", address),
|
||||||
|
zap.Error(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
resp, err := grpc_health_v1.NewHealthClient(conn).Check(ctx, &grpc_health_v1.HealthCheckRequest{
|
||||||
|
Service: grpcServiceName,
|
||||||
|
})
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if stat, ok := status.FromError(err); ok && stat.Code() == codes.Unimplemented {
|
||||||
|
logger.Info("gRPC health protocol not implemented")
|
||||||
|
os.Exit(1)
|
||||||
|
} else {
|
||||||
|
logger.Info("check failed",
|
||||||
|
zap.String("address", address),
|
||||||
|
zap.Error(err))
|
||||||
|
}
|
||||||
|
conn.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.Close()
|
||||||
|
logger.Info("check succeed",
|
||||||
|
zap.String("status", resp.GetStatus().String()))
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(1)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,365 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/hashicorp/go-getter"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
codeProjectName string
|
|
||||||
codeGitUser string
|
|
||||||
codeVersion string
|
|
||||||
codeProjectPath string
|
|
||||||
)
|
|
||||||
|
|
||||||
var codeCmd = &cobra.Command{
|
|
||||||
Use: `code`,
|
|
||||||
Short: "Code commands",
|
|
||||||
}
|
|
||||||
|
|
||||||
var codeInitCmd = &cobra.Command{
|
|
||||||
Use: `init [name]`,
|
|
||||||
Short: "initialize podinfo code repo",
|
|
||||||
Example: ` code init demo-app --version=v1.2.0 --git-user=stefanprodan`,
|
|
||||||
RunE: runCodeInit,
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
codeInitCmd.Flags().StringVar(&codeGitUser, "git-user", "", "GitHub user or org")
|
|
||||||
codeInitCmd.Flags().StringVar(&codeVersion, "version", "master", "podinfo repo tag or branch name")
|
|
||||||
codeInitCmd.Flags().StringVar(&codeProjectPath, "path", ".", "destination repo")
|
|
||||||
|
|
||||||
codeCmd.AddCommand(codeInitCmd)
|
|
||||||
|
|
||||||
rootCmd.AddCommand(codeCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func runCodeInit(cmd *cobra.Command, args []string) error {
|
|
||||||
|
|
||||||
if len(codeGitUser) < 0 {
|
|
||||||
return fmt.Errorf("--git-user is required")
|
|
||||||
}
|
|
||||||
if len(args) < 1 {
|
|
||||||
return fmt.Errorf("project name is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
codeProjectName = args[0]
|
|
||||||
|
|
||||||
pwd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error getting pwd: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpPath := "/tmp/k8s-podinfo"
|
|
||||||
versionName := fmt.Sprintf("k8s-podinfo-%s", codeVersion)
|
|
||||||
|
|
||||||
downloadURL := fmt.Sprintf("https://github.com/stefanprodan/podinfo/archive/%s.zip", codeVersion)
|
|
||||||
client := &getter.Client{
|
|
||||||
Src: downloadURL,
|
|
||||||
Dst: tmpPath,
|
|
||||||
Pwd: pwd,
|
|
||||||
Mode: getter.ClientModeAny,
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Downloading %s\n", downloadURL)
|
|
||||||
|
|
||||||
if err := client.Get(); err != nil {
|
|
||||||
log.Fatalf("Error downloading: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
pkgFrom := "github.com/stefanprodan/podinfo"
|
|
||||||
pkgTo := fmt.Sprintf("github.com/%s/%s", codeGitUser, codeProjectName)
|
|
||||||
|
|
||||||
if err := replaceImports(tmpPath, pkgFrom, pkgTo); err != nil {
|
|
||||||
log.Fatalf("Error parsing imports: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
dirs := []string{"pkg", "cmd", "ui", "vendor", ".github"}
|
|
||||||
for _, dir := range dirs {
|
|
||||||
|
|
||||||
err = os.MkdirAll(path.Join(codeProjectPath, dir), os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if err := copyDir(path.Join(tmpPath, versionName, dir), path.Join(codeProjectPath, dir)); err != nil {
|
|
||||||
log.Fatalf("Error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
files := []string{"Gopkg.toml", "Gopkg.lock"}
|
|
||||||
for _, file := range files {
|
|
||||||
if err := copyFile(path.Join(tmpPath, versionName, file), path.Join(codeProjectPath, file)); err != nil {
|
|
||||||
log.Fatalf("Error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fileContent, err := ioutil.ReadFile(path.Join(codeProjectPath, file))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
newContent := strings.Replace(string(fileContent), pkgFrom, pkgTo, -1)
|
|
||||||
err = ioutil.WriteFile(path.Join(codeProjectPath, file), []byte(newContent), os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
projFrom := "stefanprodan/podinfo"
|
|
||||||
projTo := fmt.Sprintf("%s/%s", codeGitUser, codeProjectName)
|
|
||||||
|
|
||||||
makeFiles := []string{"Makefile.gh", "Dockerfile.gh"}
|
|
||||||
for _, file := range makeFiles {
|
|
||||||
fileContent, err := ioutil.ReadFile(path.Join(tmpPath, versionName, file))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
destFile := strings.Replace(file, ".gh", "", -1)
|
|
||||||
newContent := strings.Replace(string(fileContent), projFrom, projTo, -1)
|
|
||||||
err = ioutil.WriteFile(path.Join(codeProjectPath, destFile), []byte(newContent), os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
workflows := []string{".github/main.workflow"}
|
|
||||||
for _, file := range workflows {
|
|
||||||
fileContent, err := ioutil.ReadFile(path.Join(codeProjectPath, file))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
newContent := strings.Replace(string(fileContent), "Dockerfile.gh", "Dockerfile", -1)
|
|
||||||
err = ioutil.WriteFile(path.Join(codeProjectPath, file), []byte(newContent), os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dockerFiles := []string{"Dockerfile.ci"}
|
|
||||||
for _, file := range dockerFiles {
|
|
||||||
fileContent, err := ioutil.ReadFile(path.Join(tmpPath, versionName, file))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
newContent := strings.Replace(string(fileContent), projFrom, projTo, -1)
|
|
||||||
err = ioutil.WriteFile(path.Join(codeProjectPath, file), []byte(newContent), os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
travisFiles := []string{"travis.lite.yml"}
|
|
||||||
for _, file := range travisFiles {
|
|
||||||
fileContent, err := ioutil.ReadFile(path.Join(tmpPath, versionName, file))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
destFile := strings.Replace(file, "travis.lite.yml", ".travis.yml", -1)
|
|
||||||
newContent := strings.Replace(string(fileContent), projFrom, projTo, -1)
|
|
||||||
err = ioutil.WriteFile(path.Join(codeProjectPath, destFile), []byte(newContent), os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = gitPush()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("git push error: %s", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Initialization finished")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitPush() error {
|
|
||||||
cmdPush := fmt.Sprintf("git add . && git commit -m \"sync %s\" && git push", codeVersion)
|
|
||||||
cmd := exec.Command("sh", "-c", cmdPush)
|
|
||||||
output, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println(string(output))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func replaceImports(projectPath string, pkgFrom string, pkgTo string) error {
|
|
||||||
regexImport, err := regexp.Compile(`(?s)(import(.*?)\)|import.*$)`)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
regexImportedPackage, err := regexp.Compile(`"(.*?)"`)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
found := []string{}
|
|
||||||
|
|
||||||
err = filepath.Walk(projectPath, func(path string, info os.FileInfo, err error) error {
|
|
||||||
if filepath.Ext(path) == ".go" {
|
|
||||||
bts, err := ioutil.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
content := string(bts)
|
|
||||||
matches := regexImport.FindAllString(content, -1)
|
|
||||||
isExists := false
|
|
||||||
|
|
||||||
isReplaceable:
|
|
||||||
for _, each := range matches {
|
|
||||||
for _, eachLine := range strings.Split(each, "\n") {
|
|
||||||
matchesInline := regexImportedPackage.FindAllString(eachLine, -1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, eachSubline := range matchesInline {
|
|
||||||
if strings.Contains(eachSubline, pkgFrom) {
|
|
||||||
isExists = true
|
|
||||||
break isReplaceable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if isExists {
|
|
||||||
content = strings.Replace(content, `"`+pkgFrom+`"`, `"`+pkgTo+`"`, -1)
|
|
||||||
content = strings.Replace(content, `"`+pkgFrom+`/`, `"`+pkgTo+`/`, -1)
|
|
||||||
found = append(found, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ioutil.WriteFile(path, []byte(content), info.Mode())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("ERROR", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(found) == 0 {
|
|
||||||
fmt.Println("Nothing replaced")
|
|
||||||
} else {
|
|
||||||
fmt.Printf("Go imports total %d file replaced\n", len(found))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyDir(src string, dst string) error {
|
|
||||||
si, err := os.Stat(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !si.IsDir() {
|
|
||||||
return fmt.Errorf("source is not a directory")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.MkdirAll(dst, si.Mode())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
entries, err := ioutil.ReadDir(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, entry := range entries {
|
|
||||||
srcPath := filepath.Join(src, entry.Name())
|
|
||||||
dstPath := filepath.Join(dst, entry.Name())
|
|
||||||
|
|
||||||
if entry.IsDir() {
|
|
||||||
err = copyDir(srcPath, dstPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Skip symlinks.
|
|
||||||
if entry.Mode()&os.ModeSymlink != 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
err = copyFile(srcPath, dstPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyFile(src, dst string) (err error) {
|
|
||||||
in, err := os.Open(src)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer in.Close()
|
|
||||||
|
|
||||||
out, err := os.Create(dst)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if e := out.Close(); e != nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, err = io.Copy(out, in)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = out.Sync()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
si, err := os.Stat(src)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = os.Chmod(dst, si.Mode())
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -2,11 +2,12 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/stefanprodan/podinfo/pkg/version"
|
"github.com/stefanprodan/podinfo/pkg/version"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,42 +1,65 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/spf13/pflag"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"github.com/stefanprodan/podinfo/pkg/api"
|
|
||||||
"github.com/stefanprodan/podinfo/pkg/signals"
|
|
||||||
"github.com/stefanprodan/podinfo/pkg/version"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"go.uber.org/zap/zapcore"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"go.opentelemetry.io/contrib/bridges/otelzap"
|
||||||
|
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc"
|
||||||
|
sdklog "go.opentelemetry.io/otel/sdk/log"
|
||||||
|
"go.opentelemetry.io/otel/sdk/resource"
|
||||||
|
semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
|
||||||
|
"github.com/stefanprodan/podinfo/pkg/api/grpc"
|
||||||
|
"github.com/stefanprodan/podinfo/pkg/api/http"
|
||||||
|
"github.com/stefanprodan/podinfo/pkg/signals"
|
||||||
|
"github.com/stefanprodan/podinfo/pkg/version"
|
||||||
|
go_grpc "google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// flags definition
|
// flags definition
|
||||||
fs := pflag.NewFlagSet("default", pflag.ContinueOnError)
|
fs := pflag.NewFlagSet("default", pflag.ContinueOnError)
|
||||||
fs.Int("port", 9898, "port")
|
fs.String("host", "", "Host to bind service to")
|
||||||
|
fs.Int("port", 9898, "HTTP port to bind service to")
|
||||||
|
fs.Int("secure-port", 0, "HTTPS port")
|
||||||
fs.Int("port-metrics", 0, "metrics port")
|
fs.Int("port-metrics", 0, "metrics port")
|
||||||
fs.String("level", "info", "log level debug, info, warn, error, flat or panic")
|
fs.Int("grpc-port", 0, "gRPC port")
|
||||||
fs.String("backend-url", "", "backend service URL")
|
fs.String("grpc-service-name", "podinfo", "gPRC service name")
|
||||||
|
fs.String("level", "info", "log level debug, info, warn, error, fatal or panic")
|
||||||
|
fs.StringSlice("backend-url", []string{}, "backend service URL")
|
||||||
fs.Duration("http-client-timeout", 2*time.Minute, "client timeout duration")
|
fs.Duration("http-client-timeout", 2*time.Minute, "client timeout duration")
|
||||||
fs.Duration("http-server-timeout", 30*time.Second, "server read and write timeout duration")
|
fs.Duration("http-server-timeout", 30*time.Second, "server read and write timeout duration")
|
||||||
fs.Duration("http-server-shutdown-timeout", 5*time.Second, "server graceful shutdown timeout duration")
|
fs.Duration("server-shutdown-timeout", 5*time.Second, "server graceful shutdown timeout duration")
|
||||||
fs.String("data-path", "/data", "data local path")
|
fs.String("data-path", "/data", "data local path")
|
||||||
fs.String("config-path", "", "config dir path")
|
fs.String("config-path", "", "config dir path")
|
||||||
|
fs.String("cert-path", "/data/cert", "certificate path for HTTPS port")
|
||||||
fs.String("config", "config.yaml", "config file name")
|
fs.String("config", "config.yaml", "config file name")
|
||||||
fs.String("ui-path", "./ui", "UI local path")
|
fs.String("ui-path", "./ui", "UI local path")
|
||||||
fs.String("ui-color", "blue", "UI color")
|
fs.String("ui-logo", "", "UI logo")
|
||||||
|
fs.String("ui-color", "#34577c", "UI color")
|
||||||
fs.String("ui-message", fmt.Sprintf("greetings from podinfo v%v", version.VERSION), "UI message")
|
fs.String("ui-message", fmt.Sprintf("greetings from podinfo v%v", version.VERSION), "UI message")
|
||||||
fs.Bool("random-delay", false, "between 0 and 5 seconds random delay")
|
fs.Bool("h2c", false, "allow upgrading to H2C")
|
||||||
|
fs.Bool("random-delay", false, "between 0 and 5 seconds random delay by default")
|
||||||
|
fs.String("random-delay-unit", "s", "either s(seconds) or ms(milliseconds")
|
||||||
|
fs.Int("random-delay-min", 0, "min for random delay: 0 by default")
|
||||||
|
fs.Int("random-delay-max", 5, "max for random delay: 5 by default")
|
||||||
fs.Bool("random-error", false, "1/3 chances of a random response error")
|
fs.Bool("random-error", false, "1/3 chances of a random response error")
|
||||||
fs.Int("stress-cpu", 0, "Number of CPU cores with 100 load")
|
fs.Bool("unhealthy", false, "when set, healthy state is never reached")
|
||||||
|
fs.Bool("unready", false, "when set, ready state is never reached")
|
||||||
|
fs.Int("stress-cpu", 0, "number of CPU cores with 100 load")
|
||||||
fs.Int("stress-memory", 0, "MB of data to load into memory")
|
fs.Int("stress-memory", 0, "MB of data to load into memory")
|
||||||
|
fs.String("cache-server", "", "Redis address in the format 'tcp://<host>:<port>'")
|
||||||
|
fs.String("otel-service-name", "", "service name for OpenTelemetry, when not set tracing and log export are disabled")
|
||||||
|
|
||||||
versionFlag := fs.BoolP("version", "v", false, "get version number")
|
versionFlag := fs.BoolP("version", "v", false, "get version number")
|
||||||
|
|
||||||
@@ -59,6 +82,7 @@ func main() {
|
|||||||
viper.RegisterAlias("backendUrl", "backend-url")
|
viper.RegisterAlias("backendUrl", "backend-url")
|
||||||
hostname, _ := os.Hostname()
|
hostname, _ := os.Hostname()
|
||||||
viper.SetDefault("jwt-secret", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9")
|
viper.SetDefault("jwt-secret", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9")
|
||||||
|
viper.SetDefault("ui-logo", "https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif")
|
||||||
viper.Set("hostname", hostname)
|
viper.Set("hostname", hostname)
|
||||||
viper.Set("version", version.VERSION)
|
viper.Set("version", version.VERSION)
|
||||||
viper.Set("revision", version.REVISION)
|
viper.Set("revision", version.REVISION)
|
||||||
@@ -67,16 +91,26 @@ func main() {
|
|||||||
viper.AutomaticEnv()
|
viper.AutomaticEnv()
|
||||||
|
|
||||||
// load config from file
|
// load config from file
|
||||||
if _, err := os.Stat(filepath.Join(viper.GetString("config-path"), viper.GetString("config"))); err == nil {
|
if _, fileErr := os.Stat(filepath.Join(viper.GetString("config-path"), viper.GetString("config"))); fileErr == nil {
|
||||||
viper.SetConfigName(strings.Split(viper.GetString("config"), ".")[0])
|
viper.SetConfigName(strings.Split(viper.GetString("config"), ".")[0])
|
||||||
viper.AddConfigPath(viper.GetString("config-path"))
|
viper.AddConfigPath(viper.GetString("config-path"))
|
||||||
if err := viper.ReadInConfig(); err != nil {
|
if readErr := viper.ReadInConfig(); readErr != nil {
|
||||||
fmt.Printf("Error reading config file, %v\n", err)
|
fmt.Printf("Error reading config file, %v\n", readErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize OTel log provider if service name is set
|
||||||
|
var loggerProvider *sdklog.LoggerProvider
|
||||||
|
if otelServiceName := viper.GetString("otel-service-name"); otelServiceName != "" {
|
||||||
|
var err error
|
||||||
|
loggerProvider, err = initLoggerProvider(context.Background(), otelServiceName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error initializing OTel log provider: %s\n", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure logging
|
// configure logging
|
||||||
logger, _ := initZap(viper.GetString("level"))
|
logger, _ := initZap(viper.GetString("level"), loggerProvider)
|
||||||
defer logger.Sync()
|
defer logger.Sync()
|
||||||
stdLog := zap.RedirectStdLog(logger)
|
stdLog := zap.RedirectStdLog(logger)
|
||||||
defer stdLog()
|
defer stdLog()
|
||||||
@@ -90,8 +124,43 @@ func main() {
|
|||||||
viper.Set("port", strconv.Itoa(port))
|
viper.Set("port", strconv.Itoa(port))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validate secure port
|
||||||
|
if _, err := strconv.Atoi(viper.GetString("secure-port")); err != nil {
|
||||||
|
securePort, _ := fs.GetInt("secure-port")
|
||||||
|
viper.Set("secure-port", strconv.Itoa(securePort))
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate random delay options
|
||||||
|
if viper.GetInt("random-delay-max") < viper.GetInt("random-delay-min") {
|
||||||
|
logger.Panic("`--random-delay-max` should be greater than `--random-delay-min`")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch delayUnit := viper.GetString("random-delay-unit"); delayUnit {
|
||||||
|
case
|
||||||
|
"s",
|
||||||
|
"ms":
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
logger.Panic("`random-delay-unit` accepted values are: s|ms")
|
||||||
|
}
|
||||||
|
|
||||||
|
// load gRPC server config
|
||||||
|
var grpcCfg grpc.Config
|
||||||
|
if err := viper.Unmarshal(&grpcCfg); err != nil {
|
||||||
|
logger.Panic("config unmarshal failed", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// start gRPC server
|
||||||
|
var grpcServer *go_grpc.Server
|
||||||
|
if grpcCfg.Port > 0 {
|
||||||
|
grpcSrv, _ := grpc.NewServer(&grpcCfg, logger)
|
||||||
|
//grpcinfoSrv, _ := grpc.NewInfoServer(&grpcCfg)
|
||||||
|
|
||||||
|
grpcServer = grpcSrv.ListenAndServe()
|
||||||
|
}
|
||||||
|
|
||||||
// load HTTP server config
|
// load HTTP server config
|
||||||
var srvCfg api.Config
|
var srvCfg http.Config
|
||||||
if err := viper.Unmarshal(&srvCfg); err != nil {
|
if err := viper.Unmarshal(&srvCfg); err != nil {
|
||||||
logger.Panic("config unmarshal failed", zap.Error(err))
|
logger.Panic("config unmarshal failed", zap.Error(err))
|
||||||
}
|
}
|
||||||
@@ -104,12 +173,35 @@ func main() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// start HTTP server
|
// start HTTP server
|
||||||
srv, _ := api.NewServer(&srvCfg, logger)
|
srv, _ := http.NewServer(&srvCfg, logger)
|
||||||
|
httpServer, httpsServer, healthy, ready := srv.ListenAndServe()
|
||||||
|
|
||||||
|
// graceful shutdown
|
||||||
stopCh := signals.SetupSignalHandler()
|
stopCh := signals.SetupSignalHandler()
|
||||||
srv.ListenAndServe(stopCh)
|
sd, _ := signals.NewShutdown(srvCfg.ServerShutdownTimeout, logger)
|
||||||
|
sd.SetLoggerProvider(loggerProvider)
|
||||||
|
sd.Graceful(stopCh, httpServer, httpsServer, grpcServer, healthy, ready)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initZap(logLevel string) (*zap.Logger, error) {
|
func initLoggerProvider(ctx context.Context, serviceName string) (*sdklog.LoggerProvider, error) {
|
||||||
|
exporter, err := otlploggrpc.New(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("creating OTLP log exporter: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := sdklog.NewLoggerProvider(
|
||||||
|
sdklog.WithProcessor(sdklog.NewBatchProcessor(exporter)),
|
||||||
|
sdklog.WithResource(resource.NewWithAttributes(
|
||||||
|
semconv.SchemaURL,
|
||||||
|
semconv.ServiceNameKey.String(serviceName),
|
||||||
|
semconv.ServiceVersionKey.String(version.VERSION),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initZap(logLevel string, loggerProvider *sdklog.LoggerProvider) (*zap.Logger, error) {
|
||||||
level := zap.NewAtomicLevelAt(zapcore.InfoLevel)
|
level := zap.NewAtomicLevelAt(zapcore.InfoLevel)
|
||||||
switch logLevel {
|
switch logLevel {
|
||||||
case "debug":
|
case "debug":
|
||||||
@@ -153,7 +245,21 @@ func initZap(logLevel string) (*zap.Logger, error) {
|
|||||||
ErrorOutputPaths: []string{"stderr"},
|
ErrorOutputPaths: []string{"stderr"},
|
||||||
}
|
}
|
||||||
|
|
||||||
return zapConfig.Build()
|
logger, err := zapConfig.Build()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if loggerProvider != nil {
|
||||||
|
otelCore := otelzap.NewCore("github.com/stefanprodan/podinfo",
|
||||||
|
otelzap.WithLoggerProvider(loggerProvider),
|
||||||
|
)
|
||||||
|
logger = logger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core {
|
||||||
|
return zapcore.NewTee(core, otelCore)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
return logger, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var stressMemoryPayload []byte
|
var stressMemoryPayload []byte
|
||||||
@@ -188,12 +294,12 @@ func beginStressTest(cpus int, mem int, logger *zap.Logger) {
|
|||||||
logger.Error("memory stress failed", zap.Error(err))
|
logger.Error("memory stress failed", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
stressMemoryPayload, err = ioutil.ReadFile(path)
|
stressMemoryPayload, err = os.ReadFile(path)
|
||||||
f.Close()
|
f.Close()
|
||||||
os.Remove(path)
|
os.Remove(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("memory stress failed", zap.Error(err))
|
logger.Error("memory stress failed", zap.Error(err))
|
||||||
}
|
}
|
||||||
logger.Info("starting CPU stress", zap.Int("memory", len(stressMemoryPayload)))
|
logger.Info("starting MEMORY stress", zap.Int("memory", len(stressMemoryPayload)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
45
deploy/README.md
Normal file
45
deploy/README.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Deploy demo webapp
|
||||||
|
|
||||||
|
Demo webapp manifests:
|
||||||
|
|
||||||
|
- [common](webapp/common)
|
||||||
|
- [frontend](webapp/frontend)
|
||||||
|
- [backend](webapp/backend)
|
||||||
|
|
||||||
|
Deploy the demo in `webapp` namespace:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -f ./webapp/common
|
||||||
|
kubectl apply -f ./webapp/backend
|
||||||
|
kubectl apply -f ./webapp/frontend
|
||||||
|
```
|
||||||
|
|
||||||
|
Deploy the demo in the `dev` namespace:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kustomize build ./overlays/dev | kubectl apply -f-
|
||||||
|
```
|
||||||
|
|
||||||
|
Deploy the demo in the `staging` namespace:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kustomize build ./overlays/staging | kubectl apply -f-
|
||||||
|
```
|
||||||
|
|
||||||
|
Deploy the demo in the `production` namespace:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kustomize build ./overlays/production | kubectl apply -f-
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing Locally Using Kind
|
||||||
|
|
||||||
|
> NOTE: You can install [kind from here](https://kind.sigs.k8s.io/docs/user/quick-start/#installation)
|
||||||
|
|
||||||
|
The following will create a new cluster called "podinfo" and configure host ports on 80 and 443. You can access the
|
||||||
|
endpoints on localhost. The example also deploys cert-manager within the cluster along with a self-signed cluster issuer
|
||||||
|
used to generate the certificate to validate the secure port.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./kind.sh
|
||||||
|
```
|
||||||
73
deploy/bases/backend/deployment.yaml
Normal file
73
deploy/bases/backend/deployment.yaml
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: backend
|
||||||
|
spec:
|
||||||
|
minReadySeconds: 3
|
||||||
|
revisionHistoryLimit: 5
|
||||||
|
progressDeadlineSeconds: 60
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 0
|
||||||
|
type: RollingUpdate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: backend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
prometheus.io/scrape: "true"
|
||||||
|
prometheus.io/port: "9797"
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: backend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: backend
|
||||||
|
image: ghcr.io/stefanprodan/podinfo:6.11.2
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 9898
|
||||||
|
protocol: TCP
|
||||||
|
- name: http-metrics
|
||||||
|
containerPort: 9797
|
||||||
|
protocol: TCP
|
||||||
|
- name: grpc
|
||||||
|
containerPort: 9999
|
||||||
|
protocol: TCP
|
||||||
|
command:
|
||||||
|
- ./podinfo
|
||||||
|
- --port=9898
|
||||||
|
- --port-metrics=9797
|
||||||
|
- --grpc-port=9999
|
||||||
|
- --grpc-service-name=backend
|
||||||
|
- --level=info
|
||||||
|
- --cache-server=tcp://cache:6379
|
||||||
|
env:
|
||||||
|
- name: PODINFO_UI_COLOR
|
||||||
|
value: "#34577c"
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- podcli
|
||||||
|
- check
|
||||||
|
- http
|
||||||
|
- localhost:9898/healthz
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- podcli
|
||||||
|
- check
|
||||||
|
- http
|
||||||
|
- localhost:9898/readyz
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 2000m
|
||||||
|
memory: 512Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 32Mi
|
||||||
18
deploy/bases/backend/hpa.yaml
Normal file
18
deploy/bases/backend/hpa.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
apiVersion: autoscaling/v2
|
||||||
|
kind: HorizontalPodAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: backend
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
name: backend
|
||||||
|
minReplicas: 1
|
||||||
|
maxReplicas: 2
|
||||||
|
metrics:
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: cpu
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: 99
|
||||||
7
deploy/bases/backend/kustomization.yaml
Normal file
7
deploy/bases/backend/kustomization.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- service.yaml
|
||||||
|
- deployment.yaml
|
||||||
|
- hpa.yaml
|
||||||
|
|
||||||
17
deploy/bases/backend/service.yaml
Normal file
17
deploy/bases/backend/service.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: backend
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: backend
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 9898
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: http
|
||||||
|
- port: 9999
|
||||||
|
targetPort: grpc
|
||||||
|
protocol: TCP
|
||||||
|
name: grpc
|
||||||
57
deploy/bases/cache/deployment.yaml
vendored
Normal file
57
deploy/bases/cache/deployment.yaml
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: cache
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: cache
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: cache
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: redis
|
||||||
|
image: docker.io/redis:8.6.1
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command:
|
||||||
|
- redis-server
|
||||||
|
- "/redis-master/redis.conf"
|
||||||
|
ports:
|
||||||
|
- name: redis
|
||||||
|
containerPort: 6379
|
||||||
|
protocol: TCP
|
||||||
|
livenessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: redis
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- redis-cli
|
||||||
|
- ping
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 1000m
|
||||||
|
memory: 128Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 32Mi
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /var/lib/redis
|
||||||
|
name: data
|
||||||
|
- mountPath: /redis-master
|
||||||
|
name: config
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
emptyDir: {}
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: redis-config
|
||||||
|
items:
|
||||||
|
- key: redis.conf
|
||||||
|
path: redis.conf
|
||||||
9
deploy/bases/cache/kustomization.yaml
vendored
Normal file
9
deploy/bases/cache/kustomization.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- service.yaml
|
||||||
|
- deployment.yaml
|
||||||
|
configMapGenerator:
|
||||||
|
- name: redis-config
|
||||||
|
files:
|
||||||
|
- redis.conf
|
||||||
4
deploy/bases/cache/redis.conf
vendored
Normal file
4
deploy/bases/cache/redis.conf
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
maxmemory 64mb
|
||||||
|
maxmemory-policy allkeys-lru
|
||||||
|
save ""
|
||||||
|
appendonly no
|
||||||
13
deploy/bases/cache/service.yaml
vendored
Normal file
13
deploy/bases/cache/service.yaml
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: cache
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: cache
|
||||||
|
ports:
|
||||||
|
- name: redis
|
||||||
|
port: 6379
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: redis
|
||||||
76
deploy/bases/database/README.md
Normal file
76
deploy/bases/database/README.md
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# Database Setup
|
||||||
|
|
||||||
|
This directory contains the Kubernetes manifests to simulate a database setup
|
||||||
|
with a primary database, read replicas, and scheduled maintenance tasks using CronJobs.
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
### Core Resources
|
||||||
|
|
||||||
|
| Resource | File | Description |
|
||||||
|
|----------|------|-------------|
|
||||||
|
| ServiceAccount | `serviceaccount.yaml` | Shared service account for all database workloads |
|
||||||
|
| PVC | `pvc-primary.yaml` | 1Gi persistent storage for primary database |
|
||||||
|
| StatefulSet | `statefulset-primary.yaml` | Primary database with persistent storage at `/data` |
|
||||||
|
| Deployment | `deployment-replica.yaml` | Read replica deployment |
|
||||||
|
| Service (Headless) | `service-primary.yaml` | Headless service for StatefulSet |
|
||||||
|
| Service | `service-replica.yaml` | ClusterIP service for replicas |
|
||||||
|
| HPA | `hpa-replica.yaml` | Autoscaler for replicas (2-3 pods, 99% CPU) |
|
||||||
|
|
||||||
|
### CronJobs
|
||||||
|
|
||||||
|
| CronJob | Schedule | Duration | TTL Cleanup | Description |
|
||||||
|
|---------|----------|----------|-------------|-------------|
|
||||||
|
| `rollup-daily` | Every 10 min | ~1 min | 1 hour | Daily rollup simulation (6 iterations) |
|
||||||
|
| `rollup-weekly` | Every 30 min | ~2 min | 1 day | Weekly rollup simulation (12 iterations) |
|
||||||
|
| `backup-daily` | Daily at midnight | ~1 min | 1 day | Backup simulation (configured to fail) |
|
||||||
|
|
||||||
|
### Scripts
|
||||||
|
|
||||||
|
Located in `scripts/` directory:
|
||||||
|
|
||||||
|
- `rollup.sh` - Rollup simulation script with configurable steps via `ROLLUP_STEPS` env var
|
||||||
|
- `backup.sh` - Backup simulation script with configurable exit code via `BACKUP_EXIT` env var
|
||||||
|
|
||||||
|
## Labels
|
||||||
|
|
||||||
|
All resources use Kubernetes recommended labels:
|
||||||
|
|
||||||
|
- `app.kubernetes.io/name` - Component name
|
||||||
|
- `app.kubernetes.io/part-of: database` - Part of database application
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Primary Database
|
||||||
|
- **Port**: 3306 (MySQL standard)
|
||||||
|
- **Storage**: 1Gi PersistentVolumeClaim mounted at `/data`
|
||||||
|
- **Service**: Headless (`clusterIP: None`) for StatefulSet
|
||||||
|
|
||||||
|
### Replica Database
|
||||||
|
- **Port**: 3306
|
||||||
|
- **Scaling**: HPA with 2-3 replicas at 99% CPU utilization
|
||||||
|
- **Service**: ClusterIP
|
||||||
|
|
||||||
|
### CronJob Scripts
|
||||||
|
|
||||||
|
The scripts check database-replica health before running:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
podcli check http database-replica:3306/readyz
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Deploy with Kustomize:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -k deploy/bases/database
|
||||||
|
```
|
||||||
|
|
||||||
|
Or include in an overlay:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# kustomization.yaml
|
||||||
|
resources:
|
||||||
|
- ../../bases/database
|
||||||
|
```
|
||||||
48
deploy/bases/database/cronjob-backup-daily.yaml
Normal file
48
deploy/bases/database/cronjob-backup-daily.yaml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: backup-daily
|
||||||
|
spec:
|
||||||
|
# Runs every day at midnight for 1 minute
|
||||||
|
schedule: "0 0 * * *"
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
successfulJobsHistoryLimit: 1
|
||||||
|
failedJobsHistoryLimit: 1
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
# Cleanup after 1 day
|
||||||
|
ttlSecondsAfterFinished: 86400
|
||||||
|
backoffLimit: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: backup-daily
|
||||||
|
app.kubernetes.io/part-of: database
|
||||||
|
spec:
|
||||||
|
serviceAccountName: database
|
||||||
|
restartPolicy: Never
|
||||||
|
containers:
|
||||||
|
- name: backup
|
||||||
|
image: ghcr.io/stefanprodan/podinfo:6.11.2
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- /scripts/backup.sh
|
||||||
|
env:
|
||||||
|
- name: BACKUP_EXIT
|
||||||
|
value: "1"
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 32Mi
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 16Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: scripts
|
||||||
|
mountPath: /scripts
|
||||||
|
volumes:
|
||||||
|
- name: scripts
|
||||||
|
configMap:
|
||||||
|
name: backup-script
|
||||||
|
defaultMode: 0755
|
||||||
48
deploy/bases/database/cronjob-rollup-daily.yaml
Normal file
48
deploy/bases/database/cronjob-rollup-daily.yaml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: rollup-daily
|
||||||
|
spec:
|
||||||
|
# Runs every 10 minutes for 1 minute
|
||||||
|
schedule: "*/10 * * * *"
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
successfulJobsHistoryLimit: 1
|
||||||
|
failedJobsHistoryLimit: 1
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
# Cleanup after 1 hour
|
||||||
|
ttlSecondsAfterFinished: 3600
|
||||||
|
backoffLimit: 3
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: rollup-daily
|
||||||
|
app.kubernetes.io/part-of: database
|
||||||
|
spec:
|
||||||
|
serviceAccountName: database
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: healthcheck
|
||||||
|
image: ghcr.io/stefanprodan/podinfo:6.11.2
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- /scripts/rollup.sh
|
||||||
|
env:
|
||||||
|
- name: ROLLUP_STEPS
|
||||||
|
value: "6"
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 32Mi
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 16Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: scripts
|
||||||
|
mountPath: /scripts
|
||||||
|
volumes:
|
||||||
|
- name: scripts
|
||||||
|
configMap:
|
||||||
|
name: rollup-script
|
||||||
|
defaultMode: 0755
|
||||||
48
deploy/bases/database/cronjob-rollup-weekly.yaml
Normal file
48
deploy/bases/database/cronjob-rollup-weekly.yaml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: rollup-weekly
|
||||||
|
spec:
|
||||||
|
# Runs every 30 minutes for 2 minutes
|
||||||
|
schedule: "*/30 * * * *"
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
successfulJobsHistoryLimit: 1
|
||||||
|
failedJobsHistoryLimit: 1
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
# Cleanup after 1 day
|
||||||
|
ttlSecondsAfterFinished: 86400
|
||||||
|
backoffLimit: 3
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: rollup-weekly
|
||||||
|
app.kubernetes.io/part-of: database
|
||||||
|
spec:
|
||||||
|
serviceAccountName: database
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: healthcheck
|
||||||
|
image: ghcr.io/stefanprodan/podinfo:6.11.2
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- /scripts/rollup.sh
|
||||||
|
env:
|
||||||
|
- name: ROLLUP_STEPS
|
||||||
|
value: "12"
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 32Mi
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 16Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: scripts
|
||||||
|
mountPath: /scripts
|
||||||
|
volumes:
|
||||||
|
- name: scripts
|
||||||
|
configMap:
|
||||||
|
name: rollup-script
|
||||||
|
defaultMode: 0755
|
||||||
66
deploy/bases/database/deployment-replica.yaml
Normal file
66
deploy/bases/database/deployment-replica.yaml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: database-replica
|
||||||
|
spec:
|
||||||
|
minReadySeconds: 3
|
||||||
|
revisionHistoryLimit: 5
|
||||||
|
progressDeadlineSeconds: 60
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 0
|
||||||
|
type: RollingUpdate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: database-replica
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
prometheus.io/scrape: "true"
|
||||||
|
prometheus.io/port: "9797"
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: database-replica
|
||||||
|
app.kubernetes.io/part-of: database
|
||||||
|
spec:
|
||||||
|
serviceAccountName: database
|
||||||
|
containers:
|
||||||
|
- name: database
|
||||||
|
image: ghcr.io/stefanprodan/podinfo:6.11.2
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- name: db
|
||||||
|
containerPort: 3306
|
||||||
|
protocol: TCP
|
||||||
|
- name: http-metrics
|
||||||
|
containerPort: 9797
|
||||||
|
protocol: TCP
|
||||||
|
command:
|
||||||
|
- ./podinfo
|
||||||
|
- --port=3306
|
||||||
|
- --port-metrics=9797
|
||||||
|
- --level=info
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- podcli
|
||||||
|
- check
|
||||||
|
- http
|
||||||
|
- localhost:3306/healthz
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- podcli
|
||||||
|
- check
|
||||||
|
- http
|
||||||
|
- localhost:3306/readyz
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 2000m
|
||||||
|
memory: 512Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 32Mi
|
||||||
18
deploy/bases/database/hpa-replica.yaml
Normal file
18
deploy/bases/database/hpa-replica.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
apiVersion: autoscaling/v2
|
||||||
|
kind: HorizontalPodAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: database-replica
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
name: database-replica
|
||||||
|
minReplicas: 2
|
||||||
|
maxReplicas: 3
|
||||||
|
metrics:
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: cpu
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: 99
|
||||||
24
deploy/bases/database/kustomization.yaml
Normal file
24
deploy/bases/database/kustomization.yaml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- serviceaccount.yaml
|
||||||
|
- pvc-primary.yaml
|
||||||
|
- statefulset-primary.yaml
|
||||||
|
- deployment-replica.yaml
|
||||||
|
- service-primary.yaml
|
||||||
|
- service-replica.yaml
|
||||||
|
- hpa-replica.yaml
|
||||||
|
- cronjob-rollup-daily.yaml
|
||||||
|
- cronjob-rollup-weekly.yaml
|
||||||
|
- cronjob-backup-daily.yaml
|
||||||
|
configMapGenerator:
|
||||||
|
- name: rollup-script
|
||||||
|
files:
|
||||||
|
- scripts/rollup.sh
|
||||||
|
options:
|
||||||
|
disableNameSuffixHash: true
|
||||||
|
- name: backup-script
|
||||||
|
files:
|
||||||
|
- scripts/backup.sh
|
||||||
|
options:
|
||||||
|
disableNameSuffixHash: true
|
||||||
10
deploy/bases/database/pvc-primary.yaml
Normal file
10
deploy/bases/database/pvc-primary.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: database-primary
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
12
deploy/bases/database/scripts/backup.sh
Normal file
12
deploy/bases/database/scripts/backup.sh
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# This is a simulation of a backup process.
|
||||||
|
|
||||||
|
EXIT_CODE=${BACKUP_EXIT:-0}
|
||||||
|
|
||||||
|
echo "Starting backup (estimated run time: 60s)"
|
||||||
|
podcli check http database-replica:3306/readyz
|
||||||
|
sleep 60
|
||||||
|
echo "Backup finished"
|
||||||
|
exit $EXIT_CODE
|
||||||
15
deploy/bases/database/scripts/rollup.sh
Normal file
15
deploy/bases/database/scripts/rollup.sh
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# This is a simulation of a rollup process.
|
||||||
|
|
||||||
|
STEPS=${ROLLUP_STEPS:-6}
|
||||||
|
echo "Starting rollup with $STEPS steps (estimated run time: $((STEPS * 10))s)"
|
||||||
|
podcli check http database-replica:3306/readyz
|
||||||
|
i=1
|
||||||
|
while [ $i -le $STEPS ]; do
|
||||||
|
echo "Running rollup iteration $i of $STEPS"
|
||||||
|
sleep 10
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
echo "Rollup finished"
|
||||||
14
deploy/bases/database/service-primary.yaml
Normal file
14
deploy/bases/database/service-primary.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: database-primary
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
clusterIP: None
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: database-primary
|
||||||
|
ports:
|
||||||
|
- name: db
|
||||||
|
port: 3306
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: db
|
||||||
13
deploy/bases/database/service-replica.yaml
Normal file
13
deploy/bases/database/service-replica.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: database-replica
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: database-replica
|
||||||
|
ports:
|
||||||
|
- name: db
|
||||||
|
port: 3306
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: db
|
||||||
4
deploy/bases/database/serviceaccount.yaml
Normal file
4
deploy/bases/database/serviceaccount.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: database
|
||||||
70
deploy/bases/database/statefulset-primary.yaml
Normal file
70
deploy/bases/database/statefulset-primary.yaml
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: database-primary
|
||||||
|
spec:
|
||||||
|
serviceName: database-primary
|
||||||
|
replicas: 1
|
||||||
|
minReadySeconds: 3
|
||||||
|
revisionHistoryLimit: 5
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: database-primary
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
prometheus.io/scrape: "true"
|
||||||
|
prometheus.io/port: "9797"
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: database-primary
|
||||||
|
app.kubernetes.io/part-of: database
|
||||||
|
spec:
|
||||||
|
serviceAccountName: database
|
||||||
|
containers:
|
||||||
|
- name: database
|
||||||
|
image: ghcr.io/stefanprodan/podinfo:6.11.2
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- name: db
|
||||||
|
containerPort: 3306
|
||||||
|
protocol: TCP
|
||||||
|
- name: http-metrics
|
||||||
|
containerPort: 9797
|
||||||
|
protocol: TCP
|
||||||
|
command:
|
||||||
|
- ./podinfo
|
||||||
|
- --port=3306
|
||||||
|
- --port-metrics=9797
|
||||||
|
- --level=info
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- podcli
|
||||||
|
- check
|
||||||
|
- http
|
||||||
|
- localhost:3306/healthz
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- podcli
|
||||||
|
- check
|
||||||
|
- http
|
||||||
|
- localhost:3306/readyz
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 2000m
|
||||||
|
memory: 512Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 32Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: database-primary
|
||||||
72
deploy/bases/frontend/deployment.yaml
Normal file
72
deploy/bases/frontend/deployment.yaml
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: frontend
|
||||||
|
spec:
|
||||||
|
minReadySeconds: 3
|
||||||
|
revisionHistoryLimit: 5
|
||||||
|
progressDeadlineSeconds: 60
|
||||||
|
strategy:
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 0
|
||||||
|
type: RollingUpdate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: frontend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
prometheus.io/scrape: "true"
|
||||||
|
prometheus.io/port: "9797"
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: frontend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: frontend
|
||||||
|
image: ghcr.io/stefanprodan/podinfo:6.11.2
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 9898
|
||||||
|
protocol: TCP
|
||||||
|
- name: http-metrics
|
||||||
|
containerPort: 9797
|
||||||
|
protocol: TCP
|
||||||
|
- name: grpc
|
||||||
|
containerPort: 9999
|
||||||
|
protocol: TCP
|
||||||
|
command:
|
||||||
|
- ./podinfo
|
||||||
|
- --port=9898
|
||||||
|
- --port-metrics=9797
|
||||||
|
- --level=info
|
||||||
|
- --backend-url=http://backend:9898/echo
|
||||||
|
- --cache-server=tcp://cache:6379
|
||||||
|
env:
|
||||||
|
- name: PODINFO_UI_COLOR
|
||||||
|
value: "#34577c"
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- podcli
|
||||||
|
- check
|
||||||
|
- http
|
||||||
|
- localhost:9898/healthz
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- podcli
|
||||||
|
- check
|
||||||
|
- http
|
||||||
|
- localhost:9898/readyz
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 1000m
|
||||||
|
memory: 128Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 32Mi
|
||||||
18
deploy/bases/frontend/hpa.yaml
Normal file
18
deploy/bases/frontend/hpa.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
apiVersion: autoscaling/v2
|
||||||
|
kind: HorizontalPodAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: frontend
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
name: frontend
|
||||||
|
minReplicas: 1
|
||||||
|
maxReplicas: 4
|
||||||
|
metrics:
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: cpu
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: 99
|
||||||
7
deploy/bases/frontend/kustomization.yaml
Normal file
7
deploy/bases/frontend/kustomization.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- service.yaml
|
||||||
|
- deployment.yaml
|
||||||
|
- hpa.yaml
|
||||||
|
|
||||||
13
deploy/bases/frontend/service.yaml
Normal file
13
deploy/bases/frontend/service.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: frontend
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: frontend
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: http
|
||||||
48
deploy/kind.sh
Executable file
48
deploy/kind.sh
Executable file
@@ -0,0 +1,48 @@
|
|||||||
|
#! /usr/bin/env sh
|
||||||
|
|
||||||
|
mkdir -p bin
|
||||||
|
cat > ./bin/kind.yaml <<EOF
|
||||||
|
apiVersion: kind.x-k8s.io/v1alpha4
|
||||||
|
kind: Cluster
|
||||||
|
nodes:
|
||||||
|
- role: control-plane
|
||||||
|
extraPortMappings:
|
||||||
|
- containerPort: 80
|
||||||
|
hostPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
- containerPort: 443
|
||||||
|
hostPort: 443
|
||||||
|
protocol: TCP
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# create the kind cluster
|
||||||
|
kind create cluster --config=kind.yaml
|
||||||
|
|
||||||
|
# add certificate manager
|
||||||
|
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.0.4/cert-manager.yaml
|
||||||
|
|
||||||
|
# wait for cert manager
|
||||||
|
kubectl rollout status --namespace cert-manager deployment/cert-manager --timeout=2m
|
||||||
|
kubectl rollout status --namespace cert-manager deployment/cert-manager-webhook --timeout=2m
|
||||||
|
kubectl rollout status --namespace cert-manager deployment/cert-manager-cainjector --timeout=2m
|
||||||
|
|
||||||
|
# # apply the secure webapp
|
||||||
|
kubectl apply -f ./secure/common
|
||||||
|
kubectl apply -f ./secure/backend
|
||||||
|
kubectl apply -f ./secure/frontend
|
||||||
|
|
||||||
|
# # wait for the podinfo frontend to come up
|
||||||
|
kubectl rollout status --namespace secure deployment/frontend --timeout=1m
|
||||||
|
|
||||||
|
# curl the endpoints (responds with info due to header regexp on route handler)
|
||||||
|
echo
|
||||||
|
echo "http enpdoint:"
|
||||||
|
echo "curl http://localhost"
|
||||||
|
echo
|
||||||
|
curl http://localhost
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "https (secure) enpdoint:"
|
||||||
|
echo "curl --insecure https://localhost"
|
||||||
|
echo
|
||||||
|
curl --insecure https://localhost
|
||||||
11
deploy/overlays/dev/kustomization.yaml
Normal file
11
deploy/overlays/dev/kustomization.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
namespace: dev
|
||||||
|
resources:
|
||||||
|
- ../../bases/backend
|
||||||
|
- ../../bases/frontend
|
||||||
|
- ../../bases/cache
|
||||||
|
- ../../bases/database
|
||||||
|
- namespace.yaml
|
||||||
|
transformers:
|
||||||
|
- labels.yaml
|
||||||
10
deploy/overlays/dev/labels.yaml
Normal file
10
deploy/overlays/dev/labels.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
apiVersion: builtin
|
||||||
|
kind: LabelTransformer
|
||||||
|
metadata:
|
||||||
|
name: labels
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/environment: dev
|
||||||
|
app.kubernetes.io/instance: webapp
|
||||||
|
fieldSpecs:
|
||||||
|
- path: metadata/labels
|
||||||
|
create: true
|
||||||
4
deploy/overlays/dev/namespace.yaml
Normal file
4
deploy/overlays/dev/namespace.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: dev
|
||||||
11
deploy/overlays/production/kustomization.yaml
Normal file
11
deploy/overlays/production/kustomization.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
namespace: production
|
||||||
|
resources:
|
||||||
|
- ../../bases/backend
|
||||||
|
- ../../bases/frontend
|
||||||
|
- ../../bases/cache
|
||||||
|
- ../../bases/database
|
||||||
|
- namespace.yaml
|
||||||
|
transformers:
|
||||||
|
- labels.yaml
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user