Replace Docker Registry with Harbor
Some checks are pending
Some checks are pending
This commit is contained in:
parent
88b07e2930
commit
d26fc3df93
6 changed files with 695 additions and 192 deletions
|
@ -8,7 +8,7 @@ This guide covers setting up a complete Continuous Integration/Continuous Deploy
|
|||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Forgejo Host │ │ CI/CD Linode │ │ Production Linode│
|
||||
│ (Repository) │ │ (Actions Runner)│ │ (Docker Deploy) │
|
||||
│ │ │ + Docker Registry│ │ │
|
||||
│ │ │ + Harbor Registry│ │ │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
│ │ │
|
||||
|
@ -22,7 +22,7 @@ This guide covers setting up a complete Continuous Integration/Continuous Deploy
|
|||
1. **Code Push**: Developer pushes code to Forgejo repository
|
||||
2. **Automated Testing**: CI/CD Linode runs tests on backend and frontend
|
||||
3. **Image Building**: If tests pass, Docker images are built
|
||||
4. **Registry Push**: Images are pushed to private registry on CI/CD Linode
|
||||
4. **Registry Push**: Images are pushed to Harbor registry on CI/CD Linode
|
||||
5. **Production Deployment**: Production Linode pulls images and deploys
|
||||
6. **Health Check**: Application is verified and accessible
|
||||
|
||||
|
@ -45,9 +45,10 @@ This guide covers setting up a complete Continuous Integration/Continuous Deploy
|
|||
|
||||
### CI/CD Linode Features
|
||||
- Forgejo Actions runner for automated builds
|
||||
- Local Docker registry for image storage
|
||||
- Registry web UI for image management
|
||||
- Automated cleanup of old images
|
||||
- Harbor container registry for image storage
|
||||
- Harbor web UI for image management
|
||||
- Built-in vulnerability scanning with Trivy
|
||||
- Role-based access control and audit logs
|
||||
- Secure SSH communication with production
|
||||
|
||||
### Production Linode Features
|
||||
|
@ -452,9 +453,9 @@ sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
|||
sudo usermod -aG docker SERVICE_USER
|
||||
```
|
||||
|
||||
### Step 5: Set Up Docker Registry
|
||||
### Step 5: Set Up Harbor Container Registry
|
||||
|
||||
#### 5.1 Create Registry Directory
|
||||
#### 5.1 Create Harbor Directory
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /opt/registry
|
||||
|
@ -464,7 +465,7 @@ sudo chown SERVICE_USER:SERVICE_USER /opt/registry
|
|||
#### 5.2 Generate SSL Certificates
|
||||
|
||||
```bash
|
||||
# Create system SSL directory for registry certificates
|
||||
# Create system SSL directory for Harbor certificates
|
||||
sudo mkdir -p /etc/ssl/registry
|
||||
|
||||
# Get your actual IP address
|
||||
|
@ -485,23 +486,7 @@ sudo chmod 644 /etc/ssl/registry/registry.crt
|
|||
- `registry.key`: `600` (owner read/write only) - private key must be secure
|
||||
- `registry.crt`: `644` (owner read/write, group/others read) - certificate can be read by services
|
||||
|
||||
#### 5.3 Create Authentication File
|
||||
|
||||
```bash
|
||||
# Create system auth directory for registry authentication
|
||||
sudo mkdir -p /etc/registry/auth
|
||||
|
||||
# Create htpasswd file for authentication (required for push operations only)
|
||||
sudo htpasswd -Bbn push-user "$(openssl rand -base64 32)" > /tmp/auth.htpasswd
|
||||
sudo mv /tmp/auth.htpasswd /etc/registry/auth/auth.htpasswd
|
||||
```
|
||||
|
||||
**What this does**: Creates user credentials for registry authentication in the system auth directory.
|
||||
- `push-user`: Can push images (used by CI/CD pipeline for deployments)
|
||||
|
||||
**Note**: Pull operations are public and don't require authentication, but push operations require these credentials.
|
||||
|
||||
#### 5.4 Update Configuration with Actual IP Address and Application Name
|
||||
#### 5.3 Update Harbor Configuration with Actual IP Address
|
||||
|
||||
```bash
|
||||
# Switch to SERVICE_USER (registry directory owner)
|
||||
|
@ -513,9 +498,9 @@ cd /opt/APP_NAME/registry
|
|||
YOUR_ACTUAL_IP=$(curl -4 -s ifconfig.me)
|
||||
echo "Your IP address is: $YOUR_ACTUAL_IP"
|
||||
|
||||
# Replace placeholder IP addresses in configuration files
|
||||
# Replace placeholder IP addresses in Harbor configuration files
|
||||
sed -i "s/YOUR_CI_CD_IP/$YOUR_ACTUAL_IP/g" harbor.yml
|
||||
sed -i "s/YOUR_CI_CD_IP/$YOUR_ACTUAL_IP/g" docker-compose.yml
|
||||
sed -i "s/YOUR_CI_CD_IP/$YOUR_ACTUAL_IP/g" nginx.conf
|
||||
|
||||
# Replace placeholder application name in configuration files
|
||||
sed -i "s/APP_NAME/ACTUAL_APP_NAME/g" docker-compose.yml
|
||||
|
@ -524,16 +509,26 @@ sed -i "s/APP_NAME/ACTUAL_APP_NAME/g" docker-compose.yml
|
|||
exit
|
||||
```
|
||||
|
||||
**Important**: This step replaces all instances of `YOUR_CI_CD_IP` with your actual CI/CD Linode IP address and all instances of `APP_NAME` with the actual application name in both the docker-compose.yml and nginx.conf files in the repository.
|
||||
**Important**: This step replaces all instances of `YOUR_CI_CD_IP` with your actual CI/CD Linode IP address and all instances of `APP_NAME` with the actual application name in the Harbor configuration files.
|
||||
|
||||
#### 5.5 Install Required Tools
|
||||
#### 5.4 Set Harbor Environment Variables
|
||||
|
||||
```bash
|
||||
# Install htpasswd utility
|
||||
sudo apt install -y apache2-utils
|
||||
# Set environment variables for Harbor
|
||||
export HARBOR_HOSTNAME=$YOUR_ACTUAL_IP
|
||||
export HARBOR_ADMIN_PASSWORD="Harbor12345"
|
||||
export DB_PASSWORD="your-db-password"
|
||||
|
||||
# Update Harbor configuration with secure passwords
|
||||
cd /opt/APP_NAME/registry
|
||||
sed -i "s/Harbor12345/$HARBOR_ADMIN_PASSWORD/g" harbor.yml
|
||||
sed -i "s/your-db-password/$DB_PASSWORD/g" harbor.yml
|
||||
sed -i "s/your-db-password/$DB_PASSWORD/g" docker-compose.yml
|
||||
```
|
||||
|
||||
#### 5.6 Start Registry
|
||||
**Important**: Change the default passwords for production use. The default admin password is `Harbor12345` - change this immediately after first login.
|
||||
|
||||
#### 5.5 Start Harbor
|
||||
|
||||
```bash
|
||||
# Switch to SERVICE_USER (registry directory owner)
|
||||
|
@ -546,111 +541,133 @@ docker compose up -d
|
|||
exit
|
||||
```
|
||||
|
||||
**Important**: The registry uses standard authentication, but nginx provides intelligent routing to enable public read access for specific operations (manifests, blobs, tags) while requiring authentication for write operations (push, delete). This implements the "public read, authenticated write" model through nginx configuration. The health check is performed on nginx (port 8080) since it handles the public access logic.
|
||||
**Important**: Harbor startup can take 2-3 minutes as it initializes the database and downloads vulnerability databases. The health check will ensure all services are running properly.
|
||||
|
||||
#### 5.7 Test Registry Setup
|
||||
#### 5.6 Wait for Harbor Startup
|
||||
|
||||
```bash
|
||||
# Check if containers are running
|
||||
# Monitor Harbor startup progress
|
||||
cd /opt/APP_NAME/registry
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
**Expected output**: You should see logs from all Harbor services (core, database, redis, registry, portal, nginx, jobservice, trivy) starting up. Wait until you see "Harbor has been installed and started successfully" or similar success messages.
|
||||
|
||||
#### 5.7 Test Harbor Setup
|
||||
|
||||
```bash
|
||||
# Check if all Harbor containers are running
|
||||
cd /opt/APP_NAME/registry
|
||||
docker compose ps
|
||||
|
||||
# Test registry API (HTTPS via nginx)
|
||||
curl -k https://localhost:8080/v2/_catalog
|
||||
# Test Harbor API (HTTPS)
|
||||
curl -k https://localhost:8080/api/v2.0/health
|
||||
|
||||
# Test registry UI (HTTPS via nginx)
|
||||
curl -I https://localhost:8080
|
||||
# Test Harbor UI (HTTPS)
|
||||
curl -k -I https://localhost:8080
|
||||
|
||||
# Test Docker push/pull (optional but recommended)
|
||||
# Create a test image
|
||||
echo "FROM alpine:latest" > /tmp/test.Dockerfile
|
||||
echo "RUN echo 'Hello from test image'" >> /tmp/test.Dockerfile
|
||||
|
||||
# Build and tag test image
|
||||
docker build -f /tmp/test.Dockerfile -t localhost:8080/test:latest /tmp
|
||||
|
||||
# Push to registry
|
||||
docker push localhost:8080/test:latest
|
||||
|
||||
# Verify image is in registry
|
||||
curl -k https://localhost:8080/v2/_catalog
|
||||
curl -k https://localhost:8080/v2/test/tags/list
|
||||
|
||||
# Pull image back (verifies pull works)
|
||||
docker rmi localhost:8080/test:latest
|
||||
docker pull localhost:8080/test:latest
|
||||
|
||||
# Clean up test image completely
|
||||
# Remove from local Docker
|
||||
docker rmi localhost:8080/test:latest
|
||||
|
||||
# Clean up test file
|
||||
rm /tmp/test.Dockerfile
|
||||
|
||||
# Get the manifest digest for the 'latest' tag
|
||||
curl -k -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
|
||||
https://localhost:8080/v2/test/manifests/latest
|
||||
|
||||
# Copy the "config.digest" value from the output above (starts with "sha256:")
|
||||
# Then delete the tag using that digest:
|
||||
curl -k -X DELETE https://localhost:8080/v2/test/manifests/<digest>
|
||||
|
||||
# Run garbage collection to remove orphaned blobs
|
||||
docker compose exec registry /bin/registry garbage-collect /etc/docker/registry/config.yml --delete-untagged
|
||||
|
||||
# Remove the repository directory structure
|
||||
docker compose exec registry rm -rf /var/lib/registry/docker/registry/v2/repositories/test
|
||||
|
||||
# Verify registry is empty
|
||||
echo "Verifying registry is now empty..."
|
||||
curl -k https://localhost:8080/v2/_catalog
|
||||
|
||||
# Exit SERVICE_USER shell
|
||||
exit
|
||||
# Expected output: HTTP/1.1 200 OK
|
||||
```
|
||||
|
||||
**Important Notes:**
|
||||
- **Registry API**: Uses HTTPS on port 5000 (secure)
|
||||
- **Registry UI**: Uses HTTPS on port 8080 (secure, via nginx reverse proxy)
|
||||
- **Access URLs**:
|
||||
- Registry UI: `https://YOUR_CI_CD_IP:8080` (use HTTPS)
|
||||
- Registry API: `https://YOUR_CI_CD_IP:5000`
|
||||
- **Browser Access**: Both services now use HTTPS for secure communication
|
||||
**Important**: All Harbor services should show as "Up" in the `docker compose ps` output. The health check should return a JSON response indicating all services are healthy.
|
||||
|
||||
**Expected Output**:
|
||||
- `docker-compose ps` should show both `registry` and `registry-ui` as "Up"
|
||||
- `curl -k https://localhost:5000/v2/_catalog` should return `{"repositories":[]}` (empty initially)
|
||||
- `curl -I https://localhost:8080` should return HTTP 200
|
||||
- Push/pull test should complete successfully
|
||||
#### 5.8 Access Harbor Web UI
|
||||
|
||||
**If something goes wrong**:
|
||||
- Check container logs: `docker compose logs`
|
||||
- Verify ports are open: `netstat -tlnp | grep :5000`
|
||||
- Check Docker daemon config: `cat /etc/docker/daemon.json`
|
||||
- Restart registry: `docker compose restart`
|
||||
1. **Open your browser** and navigate to: `https://YOUR_CI_CD_IP:8080`
|
||||
2. **Login with default credentials**:
|
||||
- Username: `admin`
|
||||
- Password: `Harbor12345` (or your configured password)
|
||||
3. **Change the admin password** when prompted (required on first login)
|
||||
|
||||
### Step 6: Configure Docker for Registry Access
|
||||
#### 5.9 Configure Harbor for Public Read, Authenticated Write
|
||||
|
||||
#### 6.1 Configure Docker for Registry Access
|
||||
1. **Create a Public Project**:
|
||||
- Go to **Projects** → **New Project**
|
||||
- Set **Project Name**: `public`
|
||||
- Set **Access Level**: `Public`
|
||||
- Click **OK**
|
||||
|
||||
2. **Create a Private Project** (for authenticated writes):
|
||||
- Go to **Projects** → **New Project**
|
||||
- Set **Project Name**: `private`
|
||||
- Set **Access Level**: `Private`
|
||||
- Click **OK**
|
||||
|
||||
3. **Create a User for CI/CD**:
|
||||
- Go to **Administration** → **Users** → **New User**
|
||||
- Set **Username**: `ci-user`
|
||||
- Set **Email**: `ci@example.com`
|
||||
- Set **Password**: `your-secure-password`
|
||||
- Set **Role**: `Developer`
|
||||
- Click **OK**
|
||||
|
||||
#### 5.10 Test Harbor Authentication and Access Model
|
||||
|
||||
```bash
|
||||
# Get the push user credentials
|
||||
PUSH_USER="push-user"
|
||||
PUSH_PASSWORD=$(grep push-user /etc/registry/auth/auth.htpasswd | cut -d: -f2)
|
||||
# Test Docker login to Harbor
|
||||
docker login YOUR_CI_CD_IP:8080
|
||||
# Enter: ci-user and your-secure-password
|
||||
|
||||
# Create a test image
|
||||
echo "FROM alpine:latest" > /tmp/test.Dockerfile
|
||||
echo "RUN echo 'Hello from Harbor test image'" >> /tmp/test.Dockerfile
|
||||
|
||||
# Build and tag test image for public project
|
||||
docker build -f /tmp/test.Dockerfile -t YOUR_CI_CD_IP:8080/public/test:latest /tmp
|
||||
|
||||
# Push to Harbor (requires authentication)
|
||||
docker push YOUR_CI_CD_IP:8080/public/test:latest
|
||||
|
||||
# Verify image is in Harbor
|
||||
curl -k https://localhost:8080/v2/_catalog
|
||||
|
||||
# Test public pull (no authentication required)
|
||||
docker logout YOUR_CI_CD_IP:8080
|
||||
docker pull YOUR_CI_CD_IP:8080/public/test:latest
|
||||
|
||||
# Clean up test image
|
||||
docker rmi YOUR_CI_CD_IP:8080/public/test:latest
|
||||
```
|
||||
|
||||
**Expected behavior**:
|
||||
- ✅ **Push requires authentication**: `docker push` only works when logged in
|
||||
- ✅ **Pull works without authentication**: `docker pull` works without login for public projects
|
||||
- ✅ **Web UI accessible**: Harbor UI is available at `https://YOUR_CI_CD_IP:8080`
|
||||
|
||||
#### 5.11 Harbor Access Model Summary
|
||||
|
||||
Your Harbor registry is now configured with the following access model:
|
||||
|
||||
**Public Projects** (like `public`):
|
||||
- ✅ **Pull (read)**: No authentication required
|
||||
- ✅ **Push (write)**: Requires authentication
|
||||
- ✅ **Web UI**: Accessible to view images
|
||||
|
||||
**Private Projects** (like `private`):
|
||||
- ✅ **Pull (read)**: Requires authentication
|
||||
- ✅ **Push (write)**: Requires authentication
|
||||
- ✅ **Web UI**: Requires authentication
|
||||
|
||||
**Security Features**:
|
||||
- ✅ **Vulnerability scanning**: Automatic CVE scanning with Trivy
|
||||
- ✅ **Role-based access control**: Different user roles (admin, developer, guest)
|
||||
- ✅ **Audit logs**: Complete trail of all operations
|
||||
- ✅ **Image signing**: Content trust features available
|
||||
|
||||
### Step 6: Configure Docker for Harbor Access
|
||||
|
||||
#### 6.1 Configure Docker for Harbor Access
|
||||
|
||||
```bash
|
||||
# Copy the certificate to Docker's trusted certificates
|
||||
sudo cp /etc/ssl/registry/registry.crt /usr/local/share/ca-certificates/registry.crt
|
||||
sudo update-ca-certificates
|
||||
|
||||
# Configure Docker to trust Harbor registry
|
||||
sudo tee /etc/docker/daemon.json << EOF
|
||||
{
|
||||
"insecure-registries": ["YOUR_CI_CD_IP:8080"],
|
||||
"registry-mirrors": [],
|
||||
"auths": {
|
||||
"YOUR_CI_CD_IP:8080": {
|
||||
"auth": "$(echo -n "${PUSH_USER}:${PUSH_PASSWORD}" | base64)"
|
||||
}
|
||||
}
|
||||
"registry-mirrors": []
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
@ -663,40 +680,52 @@ EOF
|
|||
sudo systemctl restart docker
|
||||
```
|
||||
|
||||
### Public Registry Access Model
|
||||
### Harbor Access Model
|
||||
|
||||
Your registry is now configured with the following access model:
|
||||
Your Harbor registry is now configured with the following access model:
|
||||
|
||||
#### **Public Read Access**
|
||||
Anyone can pull images without authentication:
|
||||
Anyone can pull images from public projects without authentication:
|
||||
```bash
|
||||
# From any machine (public access)
|
||||
docker pull YOUR_CI_CD_IP:5000/APP_NAME/backend:latest
|
||||
docker pull YOUR_CI_CD_IP:5000/APP_NAME/frontend:latest
|
||||
# From any machine (public access to public projects)
|
||||
docker pull YOUR_CI_CD_IP:8080/public/backend:latest
|
||||
docker pull YOUR_CI_CD_IP:8080/public/frontend:latest
|
||||
```
|
||||
|
||||
#### **Authenticated Write Access**
|
||||
Only the CI/CD Linode can push images (using credentials):
|
||||
Only authenticated users can push images:
|
||||
```bash
|
||||
# From CI/CD Linode only (authenticated)
|
||||
docker push YOUR_CI_CD_IP:5000/APP_NAME/backend:latest
|
||||
docker push YOUR_CI_CD_IP:5000/APP_NAME/frontend:latest
|
||||
# Login to Harbor first
|
||||
docker login YOUR_CI_CD_IP:8080
|
||||
# Enter: ci-user and your-secure-password
|
||||
|
||||
# Then push to Harbor
|
||||
docker push YOUR_CI_CD_IP:8080/public/backend:latest
|
||||
docker push YOUR_CI_CD_IP:8080/public/frontend:latest
|
||||
```
|
||||
|
||||
#### **Registry UI Access**
|
||||
Public web interface for browsing images:
|
||||
#### **Harbor Web UI Access**
|
||||
Modern web interface for managing images:
|
||||
```
|
||||
https://YOUR_CI_CD_IP:8080
|
||||
```
|
||||
|
||||
#### **Client Configuration**
|
||||
For other machines to pull images, they only need:
|
||||
For other machines to pull images from public projects, they only need:
|
||||
```bash
|
||||
# Add to /etc/docker/daemon.json on client machines
|
||||
{
|
||||
"insecure-registries": ["YOUR_CI_CD_IP:5000"]
|
||||
"insecure-registries": ["YOUR_CI_CD_IP:8080"]
|
||||
}
|
||||
# No authentication needed for pulls
|
||||
# No authentication needed for pulls from public projects
|
||||
```
|
||||
|
||||
#### **CI/CD Pipeline Configuration**
|
||||
For automated deployments, use the `ci-user` credentials:
|
||||
```bash
|
||||
# In CI/CD pipeline
|
||||
echo "ci-user:your-secure-password" | docker login YOUR_CI_CD_IP:8080 --username ci-user --password-stdin
|
||||
docker push YOUR_CI_CD_IP:8080/public/backend:latest
|
||||
```
|
||||
|
||||
### Step 7: Set Up SSH for Production Communication
|
||||
|
@ -894,7 +923,7 @@ crontab -l
|
|||
- **Runs automatically**: The cleanup script runs every day at 3:00 AM
|
||||
- **Frequency**: Daily cleanup to prevent disk space issues
|
||||
- **Logging**: All cleanup output is logged to `/tmp/cleanup.log`
|
||||
- **What it cleans**: Unused Docker images, volumes, networks, and registry images
|
||||
- **What it cleans**: Unused Docker images, volumes, networks, and Harbor images
|
||||
|
||||
### Step 10: Configure Firewall
|
||||
|
||||
|
@ -903,13 +932,11 @@ sudo ufw --force enable
|
|||
sudo ufw default deny incoming
|
||||
sudo ufw default allow outgoing
|
||||
sudo ufw allow ssh
|
||||
sudo ufw allow 5000/tcp # Docker registry (public read access)
|
||||
sudo ufw allow 8080/tcp # Registry UI (public read access)
|
||||
sudo ufw allow 8080/tcp # Harbor registry (public read access)
|
||||
```
|
||||
|
||||
**Security Model**:
|
||||
- **Port 5000 (Registry)**: Public read access, authenticated write access
|
||||
- **Port 8080 (UI)**: Public read access for browsing images
|
||||
- **Port 8080 (Harbor)**: Public read access for public projects, authenticated write access
|
||||
- **SSH**: Restricted to your IP addresses
|
||||
- **All other ports**: Blocked
|
||||
|
||||
|
@ -922,17 +949,21 @@ docker --version
|
|||
docker compose --version
|
||||
```
|
||||
|
||||
#### 11.2 Check Registry Status
|
||||
#### 11.2 Check Harbor Status
|
||||
|
||||
```bash
|
||||
cd /opt/registry
|
||||
cd /opt/APP_NAME/registry
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
#### 11.3 Test Registry Access
|
||||
#### 11.3 Test Harbor Access
|
||||
|
||||
```bash
|
||||
curl http://localhost:5000/v2/_catalog
|
||||
# Test Harbor API
|
||||
curl -k https://localhost:8080/api/v2.0/health
|
||||
|
||||
# Test Harbor UI
|
||||
curl -k -I https://localhost:8080
|
||||
```
|
||||
|
||||
#### 11.4 Get Public Key for Production Server
|
||||
|
@ -1142,7 +1173,7 @@ The repository doesn't include a `.env.example` file for security reasons. The C
|
|||
cat > /opt/APP_NAME/.env << 'EOF'
|
||||
# Production Environment Variables
|
||||
POSTGRES_PASSWORD=your_secure_password_here
|
||||
REGISTRY=YOUR_CI_CD_IP:5000
|
||||
REGISTRY=YOUR_CI_CD_IP:8080
|
||||
IMAGE_NAME=APP_NAME
|
||||
IMAGE_TAG=latest
|
||||
|
||||
|
@ -1160,14 +1191,14 @@ EOF
|
|||
|
||||
**Important**: Replace `YOUR_CI_CD_IP` with your actual CI/CD Linode IP address and `your_secure_password_here` with a strong password.
|
||||
|
||||
#### 18.4 Configure Docker for Registry Access
|
||||
#### 18.4 Configure Docker for Harbor Access
|
||||
|
||||
```bash
|
||||
# Add the CI/CD registry to Docker's insecure registries
|
||||
# Add the CI/CD Harbor registry to Docker's insecure registries
|
||||
sudo mkdir -p /etc/docker
|
||||
sudo tee /etc/docker/daemon.json << EOF
|
||||
{
|
||||
"insecure-registries": ["YOUR_CI_CD_IP:5000"]
|
||||
"insecure-registries": ["YOUR_CI_CD_IP:8080"]
|
||||
}
|
||||
EOF
|
||||
|
||||
|
@ -1212,11 +1243,11 @@ docker --version
|
|||
docker compose --version
|
||||
```
|
||||
|
||||
#### 20.2 Test Registry Access
|
||||
#### 20.2 Test Harbor Access
|
||||
|
||||
```bash
|
||||
# Test pulling an image from the CI/CD registry
|
||||
docker pull YOUR_CI_CD_IP:5000/APP_NAME/backend:latest
|
||||
# Test pulling an image from the CI/CD Harbor registry
|
||||
docker pull YOUR_CI_CD_IP:8080/public/backend:latest
|
||||
```
|
||||
|
||||
**Important**: Replace `YOUR_CI_CD_IP` with your actual CI/CD Linode IP address.
|
||||
|
@ -1431,7 +1462,7 @@ crontab -l
|
|||
- **Runs automatically**: The cleanup script runs every day at 3:00 AM
|
||||
- **Frequency**: Daily cleanup to prevent disk space issues
|
||||
- **Logging**: All cleanup output is logged to `/tmp/cleanup.log`
|
||||
- **What it cleans**: Unused Docker images, volumes, networks, and registry images
|
||||
- **What it cleans**: Unused Docker images, volumes, networks, and Harbor images
|
||||
|
||||
### Step 23: Test Complete Pipeline
|
||||
|
||||
|
@ -1453,7 +1484,7 @@ The pipeline should execute these steps in order:
|
|||
6. **Push to Registry**: Push images to your private registry
|
||||
7. **Deploy to Production**: Deploy to production server
|
||||
|
||||
#### 23.3 Check Registry
|
||||
#### 23.3 Check Harbor
|
||||
|
||||
```bash
|
||||
# On CI/CD Linode
|
||||
|
@ -1463,8 +1494,8 @@ cd /opt/APP_NAME/registry
|
|||
curl -k https://localhost:8080/v2/_catalog
|
||||
|
||||
# Check specific repository tags
|
||||
curl -k https://localhost:8080/v2/APP_NAME/backend/tags/list
|
||||
curl -k https://localhost:8080/v2/APP_NAME/frontend/tags/list
|
||||
curl -k https://localhost:8080/v2/public/backend/tags/list
|
||||
curl -k https://localhost:8080/v2/public/frontend/tags/list
|
||||
```
|
||||
|
||||
#### 23.4 Verify Production Deployment
|
||||
|
@ -1600,7 +1631,7 @@ tail -f /tmp/monitor.log
|
|||
You have successfully set up a complete CI/CD pipeline with:
|
||||
|
||||
- ✅ **Automated testing** on every code push
|
||||
- ✅ **Docker image building** and registry storage
|
||||
- ✅ **Docker image building** and Harbor registry storage
|
||||
- ✅ **Automated deployment** to production
|
||||
- ✅ **Health monitoring** and logging
|
||||
- ✅ **Backup and cleanup** automation
|
||||
|
|
|
@ -50,3 +50,188 @@ The setup process will:
|
|||
- Configuration is version controlled and easily auditable
|
||||
- All communication uses HTTPS
|
||||
- Clear separation between config, auth, and data
|
||||
|
||||
# Harbor Registry Setup
|
||||
|
||||
This directory contains the configuration for Harbor, an enterprise-grade container registry that provides:
|
||||
|
||||
- **Public read access** - Anyone can pull images without authentication
|
||||
- **Authenticated write access** - Only authenticated users can push images
|
||||
- **Web UI** - Modern web interface for managing images
|
||||
- **Vulnerability scanning** - Built-in security scanning with Trivy
|
||||
- **Role-based access control** - Fine-grained permissions
|
||||
- **Multi-tenancy** - Project-based organization
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Docker and Docker Compose installed
|
||||
2. SSL certificates for HTTPS (recommended for production)
|
||||
3. At least 4GB RAM and 10GB disk space
|
||||
|
||||
## Configuration
|
||||
|
||||
### 1. Update Configuration Files
|
||||
|
||||
Before starting Harbor, update the following files:
|
||||
|
||||
- `harbor.yml`: Update `hostname` and `harbor_admin_password`
|
||||
- `docker-compose.yml`: Update secrets and passwords
|
||||
|
||||
### 2. SSL Certificates
|
||||
|
||||
Place your SSL certificates in `/etc/ssl/registry/`:
|
||||
- `registry.crt` - SSL certificate
|
||||
- `registry.key` - SSL private key
|
||||
|
||||
### 3. Environment Variables
|
||||
|
||||
Set the following environment variables:
|
||||
```bash
|
||||
export HARBOR_HOSTNAME=YOUR_CI_CD_IP
|
||||
export HARBOR_ADMIN_PASSWORD=your-secure-password
|
||||
export DB_PASSWORD=your-db-password
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
1. **Stop existing registry** (if running):
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
2. **Start Harbor**:
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
3. **Wait for startup** (can take 2-3 minutes):
|
||||
```bash
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
## Initial Setup
|
||||
|
||||
1. **Access Harbor UI**: https://YOUR_CI_CD_IP:8080
|
||||
2. **Login with default credentials**:
|
||||
- Username: `admin`
|
||||
- Password: `Harbor12345` (or your configured password)
|
||||
|
||||
3. **Change admin password** on first login
|
||||
|
||||
## Configuration for Public Read, Authenticated Write
|
||||
|
||||
### 1. Create a Public Project
|
||||
|
||||
1. Go to **Projects** → **New Project**
|
||||
2. Set **Project Name**: `public`
|
||||
3. Set **Access Level**: `Public`
|
||||
4. Click **OK**
|
||||
|
||||
### 2. Create a Private Project (for authenticated writes)
|
||||
|
||||
1. Go to **Projects** → **New Project**
|
||||
2. Set **Project Name**: `private`
|
||||
3. Set **Access Level**: `Private`
|
||||
4. Click **OK**
|
||||
|
||||
### 3. Create Users
|
||||
|
||||
1. Go to **Administration** → **Users** → **New User**
|
||||
2. Create users with appropriate roles:
|
||||
- **Developer**: Can push/pull to private projects
|
||||
- **Guest**: Can only pull from public projects
|
||||
|
||||
## Usage
|
||||
|
||||
### Docker Login
|
||||
```bash
|
||||
docker login YOUR_CI_CD_IP:8080
|
||||
```
|
||||
|
||||
### Push Images
|
||||
```bash
|
||||
# Tag your image
|
||||
docker tag myimage:latest YOUR_CI_CD_IP:8080/public/myimage:latest
|
||||
|
||||
# Push to public project (requires authentication)
|
||||
docker push YOUR_CI_CD_IP:8080/public/myimage:latest
|
||||
```
|
||||
|
||||
### Pull Images
|
||||
```bash
|
||||
# Pull from public project (no authentication required)
|
||||
docker pull YOUR_CI_CD_IP:8080/public/myimage:latest
|
||||
```
|
||||
|
||||
## Security Features
|
||||
|
||||
- **Vulnerability Scanning**: Automatic CVE scanning with Trivy
|
||||
- **Image Signing**: Content trust and image signing
|
||||
- **RBAC**: Role-based access control
|
||||
- **Audit Logs**: Complete audit trail of all operations
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Backup
|
||||
```bash
|
||||
# Backup Harbor data
|
||||
docker compose exec harbor-db pg_dump -U postgres registry > backup.sql
|
||||
```
|
||||
|
||||
### Update
|
||||
```bash
|
||||
# Pull latest images
|
||||
docker compose pull
|
||||
|
||||
# Restart services
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Logs
|
||||
```bash
|
||||
# View all logs
|
||||
docker compose logs
|
||||
|
||||
# View specific service logs
|
||||
docker compose logs harbor-core
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Startup takes too long**: Harbor needs time to initialize database and download vulnerability databases
|
||||
2. **SSL certificate errors**: Ensure certificates are properly placed and have correct permissions
|
||||
3. **Authentication issues**: Check user permissions and project access levels
|
||||
|
||||
### Health Check
|
||||
```bash
|
||||
# Check service status
|
||||
docker compose ps
|
||||
|
||||
# Check Harbor health
|
||||
curl -k https://YOUR_CI_CD_IP:8080/api/v2.0/health
|
||||
```
|
||||
|
||||
## Migration from Docker Registry
|
||||
|
||||
If migrating from the previous Docker Registry setup:
|
||||
|
||||
1. **Backup existing images**:
|
||||
```bash
|
||||
docker pull YOUR_OLD_REGISTRY/image:tag
|
||||
```
|
||||
|
||||
2. **Push to Harbor**:
|
||||
```bash
|
||||
docker tag YOUR_OLD_REGISTRY/image:tag YOUR_CI_CD_IP:8080/public/image:tag
|
||||
docker push YOUR_CI_CD_IP:8080/public/image:tag
|
||||
```
|
||||
|
||||
3. **Update CI/CD pipelines** to use new registry URL
|
||||
|
||||
## Resources
|
||||
|
||||
- [Harbor Documentation](https://goharbor.io/docs/)
|
||||
- [Harbor GitHub](https://github.com/goharbor/harbor)
|
||||
- [CNCF Harbor](https://landscape.cncf.io/card-mode?category=container-registry&grouping=category&selected=harbor)
|
|
@ -1,51 +1,139 @@
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
registry:
|
||||
image: registry:2
|
||||
volumes:
|
||||
- /opt/APP_NAME/registry/config.yml:/etc/docker/registry/config.yml:ro
|
||||
- /etc/ssl/registry/registry.crt:/etc/docker/registry/ssl/registry.crt:ro
|
||||
- /etc/ssl/registry/registry.key:/etc/docker/registry/ssl/registry.key:ro
|
||||
- registry_data:/var/lib/registry
|
||||
harbor-core:
|
||||
image: goharbor/harbor-core:v2.10.0
|
||||
container_name: harbor-core
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- registry_network
|
||||
|
||||
registry-ui:
|
||||
image: joxit/docker-registry-ui:latest
|
||||
expose:
|
||||
- "80"
|
||||
depends_on:
|
||||
- harbor-db
|
||||
- harbor-redis
|
||||
- harbor-registry
|
||||
environment:
|
||||
- REGISTRY_TITLE=ShareNet Registry
|
||||
- REGISTRY_URL=https://YOUR_CI_CD_IP:8080
|
||||
depends_on:
|
||||
- registry
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- registry_network
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- "8080:443"
|
||||
- CONFIG_PATH=/etc/harbor/app.conf
|
||||
- CORE_SECRET=your-core-secret
|
||||
- JOBSERVICE_SECRET=your-jobservice-secret
|
||||
- TRIVY_ADAPTER_URL=http://harbor-trivy:8080
|
||||
- TRIVY_ADAPTER_URL_INSECURE=true
|
||||
volumes:
|
||||
- /etc/ssl/registry:/etc/nginx/ssl:ro
|
||||
- /etc/registry/auth/auth.htpasswd:/etc/nginx/auth/auth.htpasswd:ro
|
||||
- /opt/APP_NAME/registry/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
depends_on:
|
||||
- registry-ui
|
||||
restart: unless-stopped
|
||||
- ./harbor.yml:/etc/harbor/app.conf:ro
|
||||
- harbor_core:/var/log/harbor
|
||||
- harbor_data:/data
|
||||
networks:
|
||||
- registry_network
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "https://localhost:443/v2/_catalog", "--no-check-certificate"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
- harbor
|
||||
|
||||
harbor-db:
|
||||
image: goharbor/harbor-db:v2.10.0
|
||||
container_name: harbor-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_DB=registry
|
||||
- POSTGRES_PASSWORD=your-db-password
|
||||
- POSTGRES_USER=postgres
|
||||
volumes:
|
||||
- harbor_db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- harbor
|
||||
|
||||
harbor-redis:
|
||||
image: goharbor/redis-photon:v2.10.0
|
||||
container_name: harbor-redis
|
||||
restart: unless-stopped
|
||||
command: redis-server --appendonly yes
|
||||
volumes:
|
||||
- harbor_redis:/data
|
||||
networks:
|
||||
- harbor
|
||||
|
||||
harbor-registry:
|
||||
image: goharbor/registry-photon:v2.10.0
|
||||
container_name: harbor-registry
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- harbor-core
|
||||
environment:
|
||||
- REGISTRY_STORAGE_DELETE_ENABLED=true
|
||||
- REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR=inmemory
|
||||
- REGISTRY_STORAGE_FILESYSTEM_MAXTHREADS=100
|
||||
volumes:
|
||||
- harbor_registry:/storage
|
||||
- ./registry-config.yml:/etc/registry/config.yml:ro
|
||||
networks:
|
||||
- harbor
|
||||
|
||||
harbor-portal:
|
||||
image: goharbor/harbor-portal:v2.10.0
|
||||
container_name: harbor-portal
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- harbor-core
|
||||
environment:
|
||||
- CONFIG_PATH=/etc/harbor/app.conf
|
||||
volumes:
|
||||
- ./harbor.yml:/etc/harbor/app.conf:ro
|
||||
networks:
|
||||
- harbor
|
||||
|
||||
harbor-nginx:
|
||||
image: goharbor/nginx-photon:v2.10.0
|
||||
container_name: harbor-nginx
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
depends_on:
|
||||
- harbor-core
|
||||
- harbor-portal
|
||||
- harbor-registry
|
||||
volumes:
|
||||
- ./harbor.yml:/etc/harbor/app.conf:ro
|
||||
- /etc/ssl/registry:/etc/ssl/certs:ro
|
||||
- harbor_nginx:/var/log/harbor
|
||||
networks:
|
||||
- harbor
|
||||
|
||||
harbor-jobservice:
|
||||
image: goharbor/harbor-jobservice:v2.10.0
|
||||
container_name: harbor-jobservice
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- harbor-core
|
||||
- harbor-redis
|
||||
environment:
|
||||
- CONFIG_PATH=/etc/harbor/app.conf
|
||||
- CORE_SECRET=your-core-secret
|
||||
- JOBSERVICE_SECRET=your-jobservice-secret
|
||||
volumes:
|
||||
- ./harbor.yml:/etc/harbor/app.conf:ro
|
||||
- harbor_jobservice:/var/log/harbor
|
||||
networks:
|
||||
- harbor
|
||||
|
||||
harbor-trivy:
|
||||
image: goharbor/trivy-adapter-photon:v2.10.0
|
||||
container_name: harbor-trivy
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- harbor-core
|
||||
environment:
|
||||
- CONFIG_PATH=/etc/harbor/app.conf
|
||||
- CORE_SECRET=your-core-secret
|
||||
volumes:
|
||||
- ./harbor.yml:/etc/harbor/app.conf:ro
|
||||
- harbor_trivy:/var/log/harbor
|
||||
networks:
|
||||
- harbor
|
||||
|
||||
volumes:
|
||||
registry_data:
|
||||
harbor_core:
|
||||
harbor_data:
|
||||
harbor_db:
|
||||
harbor_redis:
|
||||
harbor_registry:
|
||||
harbor_portal:
|
||||
harbor_nginx:
|
||||
harbor_jobservice:
|
||||
harbor_trivy:
|
||||
|
||||
networks:
|
||||
registry_network:
|
||||
harbor:
|
||||
driver: bridge
|
177
registry/harbor.yml
Normal file
177
registry/harbor.yml
Normal file
|
@ -0,0 +1,177 @@
|
|||
# Configuration file of Harbor
|
||||
|
||||
# The IP address or hostname to access admin UI and registry service.
|
||||
# DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
|
||||
hostname: YOUR_CI_CD_IP
|
||||
|
||||
# http related config
|
||||
http:
|
||||
# port for http, default is 80. If https enabled, this port will redirect to https port
|
||||
port: 8080
|
||||
|
||||
# https related config
|
||||
https:
|
||||
# https port for harbor, default is 443
|
||||
port: 8080
|
||||
# The path of cert and key files for nginx
|
||||
certificate: /etc/ssl/certs/registry.crt
|
||||
private_key: /etc/ssl/certs/registry.key
|
||||
|
||||
# Uncomment external_url if you want to enable external proxy
|
||||
# And when it enabled the hostname will no longer used
|
||||
# external_url: https://reg.mydomain.com:8433
|
||||
|
||||
# The initial password of Harbor admin
|
||||
# Change it from default after updating for the first time
|
||||
harbor_admin_password: Harbor12345
|
||||
|
||||
# Harbor DB configuration
|
||||
database:
|
||||
# The password for the root user of Harbor DB. Change this before any production use.
|
||||
password: your-db-password
|
||||
# The maximum number of connections in the idle connection pool. If it <=0, no idle connections are retained.
|
||||
max_idle_conns: 50
|
||||
# The maximum number of open connections to the database. If it <= 0, then there is no limit on the number of open connections.
|
||||
# Note: the default number of connections is 100 for postgres.
|
||||
max_open_conns: 100
|
||||
|
||||
# The default data volume
|
||||
data_volume: /data
|
||||
|
||||
# Harbor Storage settings by default is using /data as default volume.
|
||||
# Uncomment storage_service setting If you want to using external storage.
|
||||
# storage_service:
|
||||
# # ca_bundle is the path to the custom root ca certificate, which will be injected into the truststore
|
||||
# # of registry's and chart repository's containers. This is usually needed when the user hosts a internal storage with self signed certificate.
|
||||
# ca_bundle:
|
||||
|
||||
# # storage backend, default is filesystem, options include filesystem, azure, gcs, s3, swift and oss
|
||||
# # for more info about this configuration please refer https://docs.docker.com/registry/configuration/
|
||||
# filesystem:
|
||||
# maxthreads: 100
|
||||
# # set disable_cache to true want to disable cache of redis in registry
|
||||
# # set disable_cache to false want to enable cache of redis in registry
|
||||
# disable_cache: true
|
||||
|
||||
# Trivy configuration
|
||||
trivy:
|
||||
# enabled the flag to enable Trivy scanner
|
||||
enabled: true
|
||||
# ignore update if the CVEs are already in the whitelist. It only works when scanner is V1
|
||||
ignore_unfixed: false
|
||||
# skip update if the CVEs are already in the whitelist, It only works when scanner is V2
|
||||
skip_update: false
|
||||
# generate a scan report in the JSON format
|
||||
json_output: false
|
||||
# in online mode, Trivy will download the latest database from GitHub and scan it offline
|
||||
# in offline mode, if the database does not exist locally, Trivy will exit with an error
|
||||
offline_scan: false
|
||||
# insecure Skip tls certificate verification
|
||||
insecure: false
|
||||
# github_token the github access token to download Trivy DB (see https://github.com/settings/tokens)
|
||||
# This is required only when the GitHub rate limiting is exceeded
|
||||
github_token: ""
|
||||
|
||||
# Jobservice configuration
|
||||
jobservice:
|
||||
# Maximum number of job workers in job service
|
||||
max_job_workers: 10
|
||||
|
||||
# Notification configuration
|
||||
notification:
|
||||
# Maximum retry count for webhook job
|
||||
webhook_job_max_retry: 10
|
||||
|
||||
# Log configurations
|
||||
log:
|
||||
# options are debug, info, warning, error, fatal
|
||||
level: info
|
||||
# configs for logs in local storage
|
||||
local:
|
||||
# Log files are rotated log_rotate_count times before being removed. If count is 0, old versions are removed rather than rotated.
|
||||
rotate_count: 50
|
||||
# Log files are rotated only if they grow bigger than log_rotate_size bytes. If size is followed by k, the size is assumed to be in kilobytes.
|
||||
# If the M is followed by M, the size is assumed to be in megabytes. If the G is followed by G, the size is assumed to be in gigabytes. So size 100, size 100k, size 100M and size 100G are all valid.
|
||||
rotate_size: 200M
|
||||
# The directory on your host that store log
|
||||
location: /var/log/harbor
|
||||
|
||||
# Uncomment following lines to enable external syslog endpoint.
|
||||
# external_endpoint:
|
||||
# # protocol used to transmit log to external endpoint, options is tcp or udp
|
||||
# protocol: tcp
|
||||
# # The host of external endpoint
|
||||
# host: localhost
|
||||
# # Port of external endpoint
|
||||
# port: 5140
|
||||
|
||||
#This attribute is for migrator to detect the version of the .cfg file, DO NOT MODIFY!
|
||||
_version: 2.10.0
|
||||
|
||||
# Uncomment external_database if using external database.
|
||||
# external_database:
|
||||
# harbor:
|
||||
# host: harbor_db_host
|
||||
# port: harbor_db_port
|
||||
# db_name: harbor
|
||||
# username: user
|
||||
# password: password
|
||||
# ssl_mode: disable
|
||||
# max_idle_conns: 2
|
||||
# max_open_conns: 0
|
||||
# notary_signer:
|
||||
# host: notary_signer_db_host
|
||||
# port: notary_signer_db_port
|
||||
# db_name: notary_signer
|
||||
# username: user
|
||||
# password: password
|
||||
# ssl_mode: disable
|
||||
# notary_server:
|
||||
# host: notary_server_db_host
|
||||
# port: notary_server_db_port
|
||||
# db_name: notary_server
|
||||
# username: user
|
||||
# password: password
|
||||
# ssl_mode: disable
|
||||
|
||||
# Uncomment redis if using external Redis server
|
||||
# redis:
|
||||
# host: redis_host
|
||||
# port: redis_port
|
||||
# password: redis_password
|
||||
# # db_index 0 is for core, it's unchangeable
|
||||
# registry_db_index: 1
|
||||
# jobservice_db_index: 2
|
||||
# chartmuseum_db_index: 3
|
||||
# trivy_db_index: 5
|
||||
# idle_timeout_seconds: 30
|
||||
|
||||
# Uncomment uaa for trusting the certificate of uaa instance that is hosted via self-signed cert.
|
||||
# uaa:
|
||||
# ca_file: /path/to/ca
|
||||
|
||||
# Global proxy settings
|
||||
# http_proxy:
|
||||
# https_proxy:
|
||||
# no_proxy:
|
||||
# - 127.0.0.1
|
||||
# - localhost
|
||||
# - core
|
||||
# - redis
|
||||
# - postgresql
|
||||
# - notary-db
|
||||
# - notary-signer
|
||||
# - clair
|
||||
# - trivy-adapter
|
||||
# - trivy
|
||||
# - chartmuseum
|
||||
# - jobservice
|
||||
# - registry
|
||||
# - portal
|
||||
# - log
|
||||
# - nginx
|
||||
|
||||
# metric:
|
||||
# enabled: false
|
||||
# port: 9090
|
||||
# path: /metrics
|
|
@ -20,13 +20,15 @@ http {
|
|||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
|
||||
# Public read access for all GET requests to registry API
|
||||
# Registry API - require auth for non-GET requests only
|
||||
location /v2/ {
|
||||
# Require authentication for all non-GET requests (push, delete, etc.)
|
||||
limit_except GET {
|
||||
auth_basic "Registry Realm";
|
||||
auth_basic_user_file /etc/nginx/auth/auth.htpasswd;
|
||||
}
|
||||
|
||||
# Pass through to registry
|
||||
proxy_pass https://registry_api;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
|
20
registry/registry-config.yml
Normal file
20
registry/registry-config.yml
Normal file
|
@ -0,0 +1,20 @@
|
|||
version: 0.1
|
||||
log:
|
||||
level: info
|
||||
storage:
|
||||
filesystem:
|
||||
rootdirectory: /storage
|
||||
delete:
|
||||
enabled: true
|
||||
cache:
|
||||
blobdescriptor: inmemory
|
||||
http:
|
||||
addr: :5000
|
||||
headers:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
X-Frame-Options: [DENY]
|
||||
X-XSS-Protection: [1; mode=block]
|
||||
auth:
|
||||
htpasswd:
|
||||
realm: basic-realm
|
||||
path: /etc/registry/auth/htpasswd
|
Loading…
Add table
Reference in a new issue