services: add local services
- portainer - home
This commit is contained in:
parent
cac19b4716
commit
df60f57708
3
services/homepage/.env
Normal file
3
services/homepage/.env
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Dot Env for service homepage created at Sat May 10 09:14:42 PM EEST 2025
|
||||||
|
HOMEPAGE_CONFIG='./config'
|
||||||
|
ALLOWED_HOSTS='192.168.100.16:${SVC_PORT_1},home.davydovcloud.com'
|
||||||
1
services/homepage/.gitignore
vendored
Normal file
1
services/homepage/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
config/logs
|
||||||
4
services/homepage/config/bookmarks.yaml
Executable file
4
services/homepage/config/bookmarks.yaml
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
# For configuration options and examples, please see:
|
||||||
|
# https://gethomepage.dev/configs/bookmarks
|
||||||
|
|
||||||
0
services/homepage/config/custom.css
Executable file
0
services/homepage/config/custom.css
Executable file
0
services/homepage/config/custom.js
Executable file
0
services/homepage/config/custom.js
Executable file
24
services/homepage/config/docker.yaml
Executable file
24
services/homepage/config/docker.yaml
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
# For configuration options and examples, please see:
|
||||||
|
# https://gethomepage.dev/configs/docker/
|
||||||
|
vm-personal-100-16:
|
||||||
|
host: 192.168.100.16
|
||||||
|
port: 2375
|
||||||
|
|
||||||
|
vm-network-100-75:
|
||||||
|
host: 192.168.100.75
|
||||||
|
port: 2375
|
||||||
|
|
||||||
|
vm-tools-100-65:
|
||||||
|
host: 192.168.100.65
|
||||||
|
port: 2375
|
||||||
|
|
||||||
|
vm-media-100-55:
|
||||||
|
host: 192.168.100.55
|
||||||
|
port: 2375
|
||||||
|
# my-docker:
|
||||||
|
# host: 127.0.0.1
|
||||||
|
# port: 2375
|
||||||
|
|
||||||
|
# my-docker:
|
||||||
|
# socket: /var/run/docker.sock
|
||||||
2
services/homepage/config/kubernetes.yaml
Executable file
2
services/homepage/config/kubernetes.yaml
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
# sample kubernetes config
|
||||||
136
services/homepage/config/services.yaml
Executable file
136
services/homepage/config/services.yaml
Executable file
@ -0,0 +1,136 @@
|
|||||||
|
---
|
||||||
|
# For configuration options and examples, please see:
|
||||||
|
# https://gethomepage.dev/configs/services/
|
||||||
|
- node-100-99:
|
||||||
|
- vm-network-100-75:
|
||||||
|
- QBitTorrent:
|
||||||
|
href: https://torrent.davydovcloud.com
|
||||||
|
description: Peer-to-peer freedom 💽
|
||||||
|
ping: https://torrent.davydovcloud.com
|
||||||
|
icon: qbittorrent.png
|
||||||
|
server: vm-network-100-75
|
||||||
|
container: qbittorrent
|
||||||
|
siteMonitor: https://torrent.davydovcloud.com
|
||||||
|
showStats: true
|
||||||
|
- Wireguard:
|
||||||
|
href: https://wireguard.davydovcloud.com
|
||||||
|
description: VPN
|
||||||
|
ping: https://wireguard.davydovcloud.com
|
||||||
|
icon: wireguard.png
|
||||||
|
server: vm-network-100-75
|
||||||
|
container: wg-easy
|
||||||
|
siteMonitor: https://wireguard.davydovcloud.com
|
||||||
|
- vm-tools-100-65:
|
||||||
|
- Gitea:
|
||||||
|
href: https://git.davydovcloud.com
|
||||||
|
description: Personal Git server
|
||||||
|
ping: https://git.davydovcloud.com
|
||||||
|
icon: gitea.png
|
||||||
|
server: vm-tools-100-65
|
||||||
|
container: gitea
|
||||||
|
siteMonitor: https://git.davydovcloud.com
|
||||||
|
widget:
|
||||||
|
type: gitea
|
||||||
|
url: https://git.davydovcloud.com
|
||||||
|
key: 9ba1d59d59826be79c11d0c87fdd11ad9ec11d2c
|
||||||
|
- Vaultwarden:
|
||||||
|
href: https://vault.davydovcloud.com
|
||||||
|
description: Passwords and Secrets
|
||||||
|
ping: https://vault.davydovcloud.com
|
||||||
|
icon: vaultwarden.png
|
||||||
|
server: vm-tools-100-65
|
||||||
|
container: vaultwarden
|
||||||
|
siteMonitor: https://vault.davydovcloud.com
|
||||||
|
- Search:
|
||||||
|
href: https://search.davydovcloud.com
|
||||||
|
description: Meta Search Engine
|
||||||
|
ping: https://search.davydovcloud.com
|
||||||
|
icon: searxng.png
|
||||||
|
server: vm-tools-100-65
|
||||||
|
container: meta_search_engine_gui
|
||||||
|
siteMonitor: https://search.davydovcloud.com
|
||||||
|
- Omni-Tools:
|
||||||
|
href: https://omni-tools.davydovcloud.com
|
||||||
|
description: Set of different Tools
|
||||||
|
ping: https://omni-tools.davydovcloud.com
|
||||||
|
icon: omni-tools.png
|
||||||
|
server: vm-tools-100-65
|
||||||
|
container: omni-tools
|
||||||
|
siteMonitor: https://omni-tools.davydovcloud.com
|
||||||
|
- Pastebin:
|
||||||
|
href: https://pastebin.davydovcloud.com
|
||||||
|
description: Paste and send. Securely
|
||||||
|
ping: https://pastebin.davydovcloud.com
|
||||||
|
icon: enclosed.png
|
||||||
|
server: vm-tools-100-65
|
||||||
|
container: enclosed_pastebin
|
||||||
|
siteMonitor: https://pastebin.davydovcloud.com
|
||||||
|
- YouTube Downloader:
|
||||||
|
href: https://metube.davydovcloud.com
|
||||||
|
description: Download any YouTube video
|
||||||
|
ping: https://metube.davydovcloud.com
|
||||||
|
icon: metube.png
|
||||||
|
server: vm-tools-100-65
|
||||||
|
container: yt_download_stack_metube
|
||||||
|
siteMonitor: https://metube.davydovcloud.com
|
||||||
|
- vm-media-100-55:
|
||||||
|
- Audiobookshelf:
|
||||||
|
href: https://audiobooks.davydovcloud.com
|
||||||
|
description: Audiobooks collection 📚
|
||||||
|
ping: https://audiobooks.davydovcloud.com
|
||||||
|
icon: audiobookshelf.png
|
||||||
|
server: vm-media-100-55
|
||||||
|
container: audiobookshelf
|
||||||
|
siteMonitor: https://audiobooks.davydovcloud.com
|
||||||
|
- Navidrome:
|
||||||
|
href: https://music.davydovcloud.com
|
||||||
|
description: Music Collection 🎶
|
||||||
|
ping: https://music.davydovcloud.com
|
||||||
|
icon: navidrome.png
|
||||||
|
server: vm-media-100-55
|
||||||
|
container: navidrome_music
|
||||||
|
siteMonitor: https://music.davydovcloud.com
|
||||||
|
- LinkWarden:
|
||||||
|
href: https://link.davydovcloud.com
|
||||||
|
description: Links storage 🔗
|
||||||
|
ping: https://link.davydovcloud.com
|
||||||
|
icon: linkwarden.png
|
||||||
|
server: vm-media-100-55
|
||||||
|
container: linkwarden_main
|
||||||
|
siteMonitor: https://link.davydovcloud.com
|
||||||
|
- Jellyfin:
|
||||||
|
href: https://jellyfin.davydovcloud.com
|
||||||
|
description: Movies & TV Shows 🎞️
|
||||||
|
ping: https://jellyfin.davydovcloud.com
|
||||||
|
icon: jellyfin.png
|
||||||
|
server: vm-media-100-55
|
||||||
|
container: jellyfin
|
||||||
|
showStats: true
|
||||||
|
siteMonitor: https://jellyfin.davydovcloud.com
|
||||||
|
- DavydovCloud:
|
||||||
|
href: https://davydovcloud.com
|
||||||
|
description: Nextcloud instance ☁️
|
||||||
|
ping: https://davydovcloud.com
|
||||||
|
icon: nextcloud.png
|
||||||
|
server: vm-media-100-55
|
||||||
|
container: nextcloud-aio-mastercontainer
|
||||||
|
showStats: true
|
||||||
|
siteMonitor: https://davydovcloud.com
|
||||||
|
- vm-personal-100-16:
|
||||||
|
- Portainer:
|
||||||
|
href: https://portainer.davydovcloud.com
|
||||||
|
description: Main Portainer
|
||||||
|
ping: https://portainer.davydovcloud.com
|
||||||
|
icon: portainer.png
|
||||||
|
server: vm-personal-100-16
|
||||||
|
container: portainer
|
||||||
|
siteMonitor: https://portainer.davydovcloud.com
|
||||||
|
showStats: true
|
||||||
|
|
||||||
|
- node-100-50:
|
||||||
|
- True Nas:
|
||||||
|
href: https://nas.davydovcloud.com
|
||||||
|
description: Main Portainer
|
||||||
|
ping: https://nas.davydovcloud.com
|
||||||
|
icon: truenas.png
|
||||||
|
siteMonitor: https://nas.davydovcloud.com
|
||||||
22
services/homepage/config/settings.yaml
Executable file
22
services/homepage/config/settings.yaml
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
# For configuration options and examples, please see:
|
||||||
|
# https://gethomepage.dev/configs/settings/
|
||||||
|
|
||||||
|
title: Davydov's Cloud
|
||||||
|
headerStyle: clean
|
||||||
|
language: ru
|
||||||
|
hideVersion: true
|
||||||
|
statusStyle: "basic"
|
||||||
|
background:
|
||||||
|
image: https://davydovcloud.com/s/J9mMTHjYbKYs8HS/download/background_3.jpg
|
||||||
|
blur: sm # sm, "", md, xl... see https://tailwindcss.com/docs/backdrop-blur
|
||||||
|
saturate: 70 # 0, 50, 100... see https://tailwindcss.com/docs/backdrop-saturate
|
||||||
|
brightness: 70 # 0, 50, 75... see https://tailwindcss.com/docs/backdrop-brightness
|
||||||
|
opacity: 70 # 0-100
|
||||||
|
layout:
|
||||||
|
node-100-99:
|
||||||
|
icon: https://davydovcloud.com/s/rBYZWxWNmi555DA/download/server.png
|
||||||
|
style: row
|
||||||
|
columns: 4
|
||||||
|
node-100-50:
|
||||||
|
icon: https://davydovcloud.com/s/rBYZWxWNmi555DA/download/server.png
|
||||||
25
services/homepage/config/widgets.yaml
Executable file
25
services/homepage/config/widgets.yaml
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
# For configuration options and examples, please see:
|
||||||
|
# https://gethomepage.dev/configs/info-widgets/
|
||||||
|
|
||||||
|
- logo:
|
||||||
|
icon: https://davydovcloud.com/s/mWzY8nwSBXMsobG/download/davydovcloud-icon.png
|
||||||
|
|
||||||
|
- search:
|
||||||
|
provider: custom
|
||||||
|
url: https://search.davydovcloud.com/search?q=
|
||||||
|
target: _blank
|
||||||
|
suggestionUrl: https://duckduckgo.com/ac/?type=list&q= # Optional
|
||||||
|
showSearchSuggestions: true # Optional
|
||||||
|
|
||||||
|
# 1/23/22, 1:37 PM
|
||||||
|
- datetime:
|
||||||
|
text_size: xl
|
||||||
|
format:
|
||||||
|
dateStyle: short
|
||||||
|
timeStyle: short
|
||||||
|
hourCycle: h23
|
||||||
|
timeZone: Europe/Helsinki
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
18
services/homepage/docker-compose.yml
Normal file
18
services/homepage/docker-compose.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Docker Compose for service homepage created at Sat May 10 09:14:42 PM EEST 2025
|
||||||
|
services:
|
||||||
|
homepage:
|
||||||
|
image: ghcr.io/gethomepage/homepage:latest
|
||||||
|
container_name: homepage
|
||||||
|
environment:
|
||||||
|
HOMEPAGE_ALLOWED_HOSTS: "${ALLOWED_HOSTS}" # required, may need port. See gethomepage.dev/installation/#homepage_allowed_hosts
|
||||||
|
PID: 1001:1001
|
||||||
|
GID: 1001:1001
|
||||||
|
TZ: "Europe/Helsinki" # Set the timezone
|
||||||
|
ports:
|
||||||
|
- ${SVC_PORT_1}:3000
|
||||||
|
volumes:
|
||||||
|
- ${HOMEPAGE_CONFIG}:/app/config # Make sure your local config directory exists
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
- /etc/timezone:/etc/timezone:ro # optional, for docker integrations
|
||||||
|
restart: unless-stopped
|
||||||
6
services/portainer/.dockerignore
Normal file
6
services/portainer/.dockerignore
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
scripts
|
||||||
|
.github
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
data
|
||||||
|
Dockerfile.tmp
|
||||||
1
services/portainer/.env
Normal file
1
services/portainer/.env
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Dot Env for service portainer created at Sun May 11 08:03:31 PM EEST 2025
|
||||||
3
services/portainer/.gitignore
vendored
Normal file
3
services/portainer/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
node_modules
|
||||||
|
data
|
||||||
|
Dockerfile.tmp
|
||||||
15
services/portainer/Dockerfile
Normal file
15
services/portainer/Dockerfile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
FROM portainer/portainer-ce:latest as portainer
|
||||||
|
FROM node:18-alpine3.17
|
||||||
|
|
||||||
|
WORKDIR /
|
||||||
|
COPY --from=portainer . .
|
||||||
|
|
||||||
|
WORKDIR /proxy
|
||||||
|
|
||||||
|
RUN npm i express http-proxy-middleware
|
||||||
|
COPY app.js .
|
||||||
|
|
||||||
|
COPY docker-entrypoint.sh /
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/docker-entrypoint.sh" ]
|
||||||
|
|
||||||
20
services/portainer/LICENCE
Normal file
20
services/portainer/LICENCE
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Copyright (c) 2012-2022 Scott Chacon and others
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy 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 copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
32
services/portainer/README.md
Normal file
32
services/portainer/README.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# portainer-ce-without-annoying
|
||||||
|
|
||||||
|
This is a drop-in replacement for [portainer/portainer-ce](https://hub.docker.com/r/portainer/portainer-ce), without annoying UI elements.
|
||||||
|
|
||||||
|
`portainer-ce-without-annoying` is **NOT** a fork of `portainer-ce`. It is just an overlay script / proxy to inject styles / scripts, allow removing DOM elements.
|
||||||
|
|
||||||
|
| Before || After |
|
||||||
|
|---|---|---|
|
||||||
|
|  | ==> |  |
|
||||||
|
|  | ==> |  |
|
||||||
|
|  | ==> |  |
|
||||||
|
|
||||||
|
**Bonus**: tracking script is also removed. See [this issue](https://github.com/ngxson/portainer-ce-without-annoying/issues/5)
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
If you already have `portainer-ce` installation, just replace `portainer/portainer-ce:latest` with `ngxson/portainer-ce-without-annoying:latest`
|
||||||
|
|
||||||
|
For example, if you use the command from the [official installation guide](https://docs.portainer.io/start/install-ce/server/docker/linux), the command will be:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker volume create portainer_data
|
||||||
|
docker run -d \
|
||||||
|
-p 8000:8000 -p 9443:9443 \
|
||||||
|
--name portainer \
|
||||||
|
--restart=always \
|
||||||
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
-v portainer_data:/data \
|
||||||
|
ngxson/portainer-ce-without-annoying:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can use [this docker-compose.yml](https://github.com/ngxson/portainer-ce-without-annoying/blob/master/docker-compose.yml)
|
||||||
115
services/portainer/app.js
Normal file
115
services/portainer/app.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
const https = require('https');
|
||||||
|
const http = require('http');
|
||||||
|
const fs = require('fs');
|
||||||
|
const spawn = require('child_process').spawn;
|
||||||
|
const express = require('express');
|
||||||
|
const { createProxyMiddleware } = require('http-proxy-middleware');
|
||||||
|
|
||||||
|
const INJECTED_HTML = `
|
||||||
|
<style>
|
||||||
|
/* hide Upgrade to Business on sidebar */
|
||||||
|
div.sidebar > button {display: none !important;}
|
||||||
|
|
||||||
|
/* hide Authentication logs */
|
||||||
|
[aria-label="Authentication logs"] {display: none !important;}
|
||||||
|
|
||||||
|
/* hide everything having the BE Feature banner */
|
||||||
|
.be-indicator-container, .limited-be {display: none !important;}
|
||||||
|
|
||||||
|
/* FIXME: hot fix to show OAuth save button #10 */
|
||||||
|
.oauth-save-settings-button {display: inline-block !important;}
|
||||||
|
|
||||||
|
/* this should not be hidden, but let's make it more subtle */
|
||||||
|
.be-indicator {
|
||||||
|
filter: saturate(0) !important;
|
||||||
|
opacity: 0.2 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
// Block tracking script matomo.cloud
|
||||||
|
// https://github.com/ngxson/portainer-ce-without-annoying/issues/5
|
||||||
|
(function () {
|
||||||
|
var headNode = document.getElementsByTagName('script')[0].parentNode;
|
||||||
|
|
||||||
|
// save the original function
|
||||||
|
headNode.originalInsertBefore = headNode.insertBefore;
|
||||||
|
|
||||||
|
// intercept the function call
|
||||||
|
headNode.insertBefore = function(newNode, referenceNode) {
|
||||||
|
if (newNode && newNode.src && newNode.src.indexOf('matomo') !== -1) {
|
||||||
|
console.log('Blocked insertion of matomo script node');
|
||||||
|
} else {
|
||||||
|
headNode.originalInsertBefore(newNode, referenceNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
`;
|
||||||
|
const TARGET_URL = 'http://localhost:19000';
|
||||||
|
const SSL_CERT_PATH = '/data/certs/cert.pem';
|
||||||
|
const SSL_KEY_PATH = '/data/certs/key.pem';
|
||||||
|
const FORWARDED_ARGS = process.argv.slice(2);
|
||||||
|
|
||||||
|
// proxy logic
|
||||||
|
const app = express();
|
||||||
|
app.get('/', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(TARGET_URL);
|
||||||
|
const body = await response.text();
|
||||||
|
const newBody = body.replace('<head>', `<head>${INJECTED_HTML}`);
|
||||||
|
res.send(newBody);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
res.status(500).json(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app.get('/api/motd', (req, res) => {
|
||||||
|
// hide the "Latest News From Portainer"
|
||||||
|
// https://github.com/portainer/portainer/blob/master/app/portainer/views/home/home.html
|
||||||
|
res.json({});
|
||||||
|
});
|
||||||
|
app.use(createProxyMiddleware({
|
||||||
|
target: TARGET_URL,
|
||||||
|
ws: true,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// http + https server
|
||||||
|
async function waitUntilCertAvailable() {
|
||||||
|
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
||||||
|
while (!fs.existsSync(SSL_CERT_PATH)) {
|
||||||
|
await sleep(1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
async function runServer() {
|
||||||
|
http.createServer(app).listen(9000);
|
||||||
|
await waitUntilCertAvailable();
|
||||||
|
https.createServer({
|
||||||
|
key: fs.readFileSync(SSL_KEY_PATH),
|
||||||
|
cert: fs.readFileSync(SSL_CERT_PATH),
|
||||||
|
}, app).listen(9443);
|
||||||
|
}
|
||||||
|
|
||||||
|
// child process for portainer
|
||||||
|
function runPortainer() {
|
||||||
|
const fwdArgs = FORWARDED_ARGS.join(' ');
|
||||||
|
console.log(`Launching portainer with args ${fwdArgs}`)
|
||||||
|
const child = spawn('/bin/sh', [
|
||||||
|
'-c',
|
||||||
|
`/portainer --bind=":19000" --bind-https=":19443" ${fwdArgs}`
|
||||||
|
]);
|
||||||
|
child.stdout.pipe(process.stdout);
|
||||||
|
child.stderr.pipe(process.stderr);
|
||||||
|
child.on('exit', function (code) {
|
||||||
|
console.log(`portainer exited with status code ${code}`);
|
||||||
|
process.exit(code);
|
||||||
|
});
|
||||||
|
process.on('SIGTERM', function () {
|
||||||
|
child.kill('SIGTERM');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// run it
|
||||||
|
runPortainer();
|
||||||
|
runServer();
|
||||||
|
|
||||||
16
services/portainer/docker-compose.yml
Normal file
16
services/portainer/docker-compose.yml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Docker Compose for service portainer created at Sun May 11 08:03:31 PM EEST 2025
|
||||||
|
|
||||||
|
services:
|
||||||
|
portainer:
|
||||||
|
build: .
|
||||||
|
privileged: true
|
||||||
|
container_name: portainer
|
||||||
|
hostname: portainer
|
||||||
|
ports:
|
||||||
|
- ${SVC_PORT_1}:9443
|
||||||
|
volumes:
|
||||||
|
- portainer_data:/data:Z
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
portainer_data:
|
||||||
3
services/portainer/docker-entrypoint.sh
Executable file
3
services/portainer/docker-entrypoint.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
node app.js "$@"
|
||||||
18
services/portainer/scripts/build_and_push.sh
Executable file
18
services/portainer/scripts/build_and_push.sh
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Get newest tag from https://hub.docker.com/r/portainer/portainer-ce/tags
|
||||||
|
# Also build one for :latest
|
||||||
|
|
||||||
|
IMAGE="ngxson/portainer-ce-without-annoying"
|
||||||
|
ARCHS="linux/amd64,linux/arm64,linux/arm/v7"
|
||||||
|
|
||||||
|
if [ -z "$TAG" ]; then
|
||||||
|
echo "Please set TAG environment variable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp Dockerfile Dockerfile.tmp
|
||||||
|
sed -i "s/portainer-ce:latest/portainer-ce:$TAG/g" Dockerfile.tmp
|
||||||
|
|
||||||
|
echo "Multi-arch build..."
|
||||||
|
docker buildx build --platform=$ARCHS --push -t "$IMAGE:$TAG" -f Dockerfile.tmp .
|
||||||
101
services/portainer/scripts/ci_cd.js
Normal file
101
services/portainer/scripts/ci_cd.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const { spawn } = require('child_process');
|
||||||
|
|
||||||
|
const ACCEPTED_TAGS_FROM = '2.17.0';
|
||||||
|
const UPSTREAM_REPO = 'portainer/portainer-ce';
|
||||||
|
const OUTPUT_REPO = 'ngxson/portainer-ce-without-annoying';
|
||||||
|
const NUMBER_OF_TAGS_REBUILD = 5;
|
||||||
|
|
||||||
|
const shouldRebuild = !!process.argv.join(' ').match(/rebuild=true/);
|
||||||
|
|
||||||
|
function build_and_push(tag) {
|
||||||
|
const cwd = path.join(__dirname, '..');
|
||||||
|
const command = `TAG=${tag} ./scripts/build_and_push.sh`;
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const subproc = spawn('/bin/sh', ['-c', command], { cwd });
|
||||||
|
subproc.stdout.pipe(process.stdout);
|
||||||
|
subproc.stderr.pipe(process.stderr);
|
||||||
|
subproc.on('close', () => resolve());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompt to ChatGPT: write js function that converts semver to int, for example 12.34.567 to 012034567. take into account case that input maybe 12.34 (output should be 012034000) or just 12 (output is 012000000)
|
||||||
|
*/
|
||||||
|
|
||||||
|
function semverToInt(semver) {
|
||||||
|
const versionParts = semver.split('.');
|
||||||
|
const paddedVersionParts = versionParts.map((part, index) => {
|
||||||
|
const paddedPart = part.padStart(3, '0');
|
||||||
|
return index < 2 ? paddedPart : paddedPart + '0'.repeat(6 - (versionParts.length - 1) * 3);
|
||||||
|
});
|
||||||
|
return parseInt(paddedVersionParts.join(''));
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompt to ChatGPT: now, I have docker hub api to return a list of tags of a repo, it's in results[i].name (a semver string)
|
||||||
|
* the api url is `https://hub.docker.com/v2/repositories/${repoName}/tags/`
|
||||||
|
* write nodejs code using fetch (async - await) to:
|
||||||
|
* 1. fetch name of all tags of repo_a and repo_b
|
||||||
|
* 2. get a list of difference of tags between the 2 (for example, repo_a has tag 1, 2, 3 and repo_b has 1, 2 ==> difference of tags is the "3")
|
||||||
|
* 3. for each difference of tags, call build_and_push(tag)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Utility function to fetch tags for a given repo
|
||||||
|
async function fetchTags(repoName) {
|
||||||
|
const url = `https://hub.docker.com/v2/repositories/${repoName}/tags/?page_size=50&page=1`;
|
||||||
|
const response = await fetch(url);
|
||||||
|
return (await response.json())
|
||||||
|
.results.map(result => result.name)
|
||||||
|
.filter(t => t.match(/^(latest|[\d.]+)$/));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility function to find the difference between two tag arrays
|
||||||
|
function findTagDifference(tagsA, tagsB) {
|
||||||
|
return tagsA.filter(tag => !tagsB.includes(tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main function to fetch tags, find the difference, and call build_and_push
|
||||||
|
async function processRepos(repoA, repoB) {
|
||||||
|
try {
|
||||||
|
const tagsA = await fetchTags(repoA);
|
||||||
|
const tagsB = await fetchTags(repoB);
|
||||||
|
console.log({ tagsA, tagsB });
|
||||||
|
|
||||||
|
const tagDifference = shouldRebuild
|
||||||
|
? [...tagsB]
|
||||||
|
.sort((a, b) => semverToInt(b) - semverToInt(a)) // sort desc
|
||||||
|
.filter(t => t !== 'latest')
|
||||||
|
.slice(0, NUMBER_OF_TAGS_REBUILD)
|
||||||
|
: findTagDifference(tagsA, tagsB);
|
||||||
|
|
||||||
|
// added by me
|
||||||
|
const acceptTagsFrom = semverToInt(ACCEPTED_TAGS_FROM);
|
||||||
|
const acceptedTags = tagDifference.filter(tag => semverToInt(tag) >= acceptTagsFrom);
|
||||||
|
acceptedTags.sort((a, b) => semverToInt(a) - semverToInt(b));
|
||||||
|
if (acceptedTags.length > 0) acceptedTags.push('latest');
|
||||||
|
|
||||||
|
if (acceptedTags.length === 0) {
|
||||||
|
console.log('No new tags to build, exit now');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Tags to build:', acceptedTags);
|
||||||
|
for (const tag of acceptedTags) {
|
||||||
|
console.log(`============= Building ${tag} =============`);
|
||||||
|
await build_and_push(tag);
|
||||||
|
console.log(`============= Done ${tag} =============`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processRepos(UPSTREAM_REPO, OUTPUT_REPO);
|
||||||
@ -2,6 +2,10 @@ defaultServiceValues: &defaultServiceValues
|
|||||||
composeFile: "docker-compose.yml"
|
composeFile: "docker-compose.yml"
|
||||||
envFile: ".env"
|
envFile: ".env"
|
||||||
|
|
||||||
|
vm-personal-100-16: &vm-personal-100-16
|
||||||
|
ip: "localhost"
|
||||||
|
user: tylen
|
||||||
|
|
||||||
vm-network-100-75: &vm-network-100-75
|
vm-network-100-75: &vm-network-100-75
|
||||||
ip: "192.168.100.75"
|
ip: "192.168.100.75"
|
||||||
user: vm-user
|
user: vm-user
|
||||||
@ -15,6 +19,23 @@ vm-media-100-55: &vm-media-100-55
|
|||||||
user: vm-user
|
user: vm-user
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
# ================================
|
||||||
|
# vm-personal-100-16
|
||||||
|
# ================================
|
||||||
|
- name: "homepage"
|
||||||
|
ports:
|
||||||
|
- 3018
|
||||||
|
host:
|
||||||
|
<<: *vm-personal-100-16
|
||||||
|
<<: *defaultServiceValues
|
||||||
|
|
||||||
|
- name: "portainer"
|
||||||
|
ports:
|
||||||
|
- 9443
|
||||||
|
host:
|
||||||
|
<<: *vm-personal-100-16
|
||||||
|
<<: *defaultServiceValues
|
||||||
|
|
||||||
# ================================
|
# ================================
|
||||||
# vm-media-100-55
|
# vm-media-100-55
|
||||||
# ================================
|
# ================================
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user