Compare commits

..

7 commits

Author SHA1 Message Date
09f054b888 Use headless chromium
Some checks are pending
Build and Push Docker Image / build-and-push (push) Waiting to run
2025-09-11 09:59:28 +00:00
cdd36afd33 Change base image for OSI to trixie:slim 2025-09-11 09:23:02 +00:00
46b32d6aa7 Change base image for OCI 2025-09-11 08:08:43 +00:00
7c2a58c894 Add env setting to workflow 2025-09-11 07:57:09 +00:00
e1911bf5e8 Fix dockerhub image name 2025-09-11 07:45:35 +00:00
root
fb133dff6c Add Github Workflow 2025-09-11 07:31:31 +00:00
root
ff1330868e Add Github Workflow 2025-09-11 07:31:02 +00:00
4 changed files with 96 additions and 85 deletions

View file

@ -1,42 +0,0 @@
name: Build and Push Docker Image
on:
push:
branches:
- main
paths:
- '**/*' # Триггер при любом изменении репозитория
jobs:
build-and-push:
runs-on: docker
container:
image: docker:24.0.1
steps:
# Установка Docker CLI (если не в базовом образе)
- name: Setup Docker CLI
run: |
apk add --no-cache docker-cli
# Авторизация в Docker Hub - токен необходимо добавить в Secrets
- name: Login to Docker Hub
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: |
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
# Клонирование исходников — встроено в Forgejo Actions
# Сборка Docker образа
- name: Build Docker Image
run: |
docker build -t ${DOCKER_USERNAME}/playwright-domain-scanner:latest .
# Push образ на Docker Hub
- name: Push Docker Image
run: |
docker push ${DOCKER_USERNAME}/playwright-domain-scanner:latest

View file

@ -0,0 +1,28 @@
name: Build and Push Docker Image
on:
push:
branches:
- main
jobs:
build-and-push:
runs-on: ubuntu-latest
environment: dockerhub
steps:
- name: Checkout the repository
uses: actions/checkout@v3
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
push: true
tags: ${{ secrets.DOCKER_USERNAME }}/gekata:latest

View file

@ -1,46 +1,48 @@
# Use official Node.js LTS base image
FROM node:20-slim
# Base minimal Debian
FROM debian:bookworm-slim
# Install dependencies for running Chromium
RUN apt-get update && apt-get install -y \
ca-certificates \
fonts-liberation \
libasound2 \
libatk-bridge2.0-0 \
libatk1.0-0 \
libcups2 \
libdbus-1-3 \
libdrm2 \
libgbm1 \
libgtk-3-0 \
libnspr4 \
libnss3 \
libx11-xcb1 \
libxcomposite1 \
libxdamage1 \
libxrandr2 \
xdg-utils \
wget \
--no-install-recommends && \
rm -rf /var/lib/apt/lists/*
# Prevent tzdata prompts
ENV DEBIAN_FRONTEND=noninteractive
# Set working directory
WORKDIR /usr/src/app
# Install Node.js, Chromium and minimal runtime libs
# Note: chromium package on Debian provides /usr/bin/chromium
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl gnupg \
nodejs npm \
chromium \
# Minimal GUI/Chromium runtime libs often needed by Playwright Chromium
libx11-6 libxcomposite1 libxdamage1 libxrandr2 libxkbcommon0 \
libgtk-3-0 libnss3 libdrm2 libgbm1 libasound2 fonts-liberation \
# Useful for font rendering
fonts-dejavu-core \
&& rm -rf /var/lib/apt/lists/*
# Copy package files and install dependencies
# App directory
WORKDIR /app
# Install only production deps
COPY package*.json ./
COPY ignore-domains.txt ./
RUN npm ci
ENV CI=true
RUN npm ci --omit=dev
# Install Playwright browsers (Chromium)
RUN npx playwright install chromium
# Copy app sources
# Copy source
COPY . .
# Expose port
# Security: run as non-root
RUN useradd -ms /bin/bash nodeuser && chown -R nodeuser:nodeuser /app
USER nodeuser
# Environment for service
ENV PORT=3000 \
# Ensure Playwright uses system Chromium and does not download browsers
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 \
PLAYWRIGHT_BROWSERS_PATH=0 \
# Explicit executable if needed in code; here server uses default, so optional
CHROMIUM_PATH=/usr/bin/chromium
# Expose service port
EXPOSE 3000
# Run the service
CMD ["npm", "start"]
# Start the service
CMD ["node", "server.js"]

View file

@ -1,9 +1,22 @@
// server.js
const express = require('express');
const { chromium } = require('playwright');
const app = express();
const port = process.env.PORT || 3000;
// Использовать системный Chromium, если задан путь (например, /usr/bin/chromium в Debian)
const executablePath = process.env.CHROMIUM_PATH || undefined; // можно оставить undefined, если Chromium в PATH [1][2]
// Базовый набор флагов для контейнера без systemd/dbus и без install-deps
const chromiumArgs = [
'--no-sandbox', // запуск без setuid sandbox в контейнере [14]
'--disable-setuid-sandbox', // отключение setuid sandbox [14]
'--disable-dev-shm-usage', // использовать /tmp вместо /dev/shm (если нет --ipc=host) [15][16]
'--disable-gpu', // headless окружение [14]
'--no-zygote', // упрощение процессов в контейнере [14]
];
app.use(express.json());
function extractDomain(url) {
@ -23,12 +36,17 @@ app.get('/domains', async (req, res) => {
const url = `https://${domain}`;
const seenDomains = new Set();
let browser;
let context;
try {
const browser = await chromium.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox']
browser = await chromium.launch({
executablePath, // берётся из CHROMIUM_PATH при наличии [1][2]
headless: true, // явный headless режим для контейнера [14]
args: chromiumArgs, // флаги для стабильности в Docker [15][14]
});
const context = await browser.newContext();
context = await browser.newContext();
const page = await context.newPage();
page.on('request', request => {
@ -37,15 +55,20 @@ app.get('/domains', async (req, res) => {
});
await page.goto(url, { waitUntil: 'load', timeout: 30000 });
// Фильтрация доменов после закрытия страницы
await context.close();
await browser.close();
// Фильтрация доменов
const filteredDomains = Array.from(seenDomains).filter(d =>
!d.includes('doubleclick') && !d.includes('google')
).sort();
const filteredDomains = Array.from(seenDomains)
.filter(d => !d.includes('doubleclick') && !d.includes('google'))
.sort();
res.json({ domains: filteredDomains });
} catch (e) {
// Безопасно закрыть ресурсы при ошибке
try { if (context) await context.close(); } catch {}
try { if (browser) await browser.close(); } catch {}
res.status(500).json({ error: e.message || 'Internal server error' });
}
});