Prepare your system for creating an air-gapped repository.

Procedure

  1. Deploy Photon OS 3.0 Rev 3 on a physical host or on a virtual machine. The default password of the OVA is changeme. You must set a new password after logging in for the first time.
    Note: Photon OS 3.0 Rev 3 is the only supported version in this setup. Other versions of Photon OS are not suitable for the air-gapped environment.
  2. (Optional) If you are configuring with two NICs, where one arm connects to the public network (Internet) and the other to the intranet, Photon OS places the intranet gateway at the top of the router table. The virtual machine then cannot access the Internet and you cannot SSH into the virtual machine from the public network. To resolve this issue, you must set up the network. The following steps illustrate a setup with two NICs installed on one virtual machine. The first NIC (eth0) connects to the public network. The second NIC (eth1) connects to the intranet.
    1. Go to the system folder /etc/systemd/network/.
      #cd /etc/systemd/network/
    2. Remove the default network configuration file and create two new files:
      #rm 99-dhcp-en.network
      #touch 10-dhcp-eth0.network
      #touch 20-dhcp-eth1.network
      #chmod 644 *.network
    3. Edit the two files with the following information:
      === content of 10-dhcp-eth0.network ===
      [Match]
      Name=eth0
      
      [Network]
      DHCP=ipv4
      IPv6AcceptRA=no
      LinkLocalAddressing=no
      
      [DHCP]
      RouteMetric=10
      ==============   end  ============
      === content of 20-dhcp-eth1.network ===
      [Match]
      Name=eth1
      
      [Network]
      DHCP=ipv4
      IPv6AcceptRA=no
      LinkLocalAddressing=no
      
      [DHCP]
      RouteMetric=20
      ==============   end  ============
    4. Restart the network service and verify the router table:
      #systemctl restart systemd-networkd.service
      #systemctl status systemd-networkd.service
      #route -v
      #ping packages.vmware.com
      #ping www.google.com
      #ping <ip or FQDN on intranet>
    The network configuration is successful if:
    1. No error message are found in the network status.
    2. The default gateway of eth0 is on top of the router list.
    3. All pings receive appropriate responses.
  3. (Optional) If your air-gapped server is in an Internet-restricted environment but it requires Internet access, set up a proxy network. This setup is applicable for corporate networks that require access to the Internet through a proxy. Using the vi Editor, copy the following script to a file:
    #!/bin/bash
    
    HTTP_PROXY=$1
    NO_PROXY_NETS=$2
    
    export HTTP_PROXY=${HTTP_PROXY}
    export HTTPS_PROXY=${HTTP_PROXY}
    export NO_PROXY_NODE="localhost,${NO_PROXY_NETS}"
    export NO_PROXY_RUNTIME="localhost,100.64.0.0/13,100.96.0.0/11"
    
    echo "export http_proxy=${HTTP_PROXY}" >> /etc/environment
    echo "export https_proxy=${HTTPS_PROXY}" >> /etc/environment
    echo "export no_proxy=${NO_PROXY_NODE}" >> /etc/environment
    echo "export no_proxy_runtime=${NO_PROXY_RUNTIME}" >> /etc/profile
    echo "export no_proxy_runtime=${NO_PROXY_RUNTIME}" >> /etc/environment
    echo "export http_proxy=${HTTP_PROXY}" >> /etc/profile
    echo "export https_proxy=${HTTPS_PROXY}" >> /etc/profile
    echo "export no_proxy=${NO_PROXY_NODE}" >> /etc/profile
    
    source /etc/profile
    
    
    mkdir -p /etc/systemd/system/docker.service.d/
    cat <<EOF > /etc/systemd/system/docker.service.d/http_proxy.conf
    [Service]
    Environment="HTTP_PROXY=$HTTP_PROXY"
    Environment="HTTPS_PROXY=$HTTP_PROXY"
    Environment="NO_PROXY=localhost,$NO_PROXY_NETS"
    EOF
    
    systemctl daemon-reload
    systemctl restart docker.service
    echo "setup proxy done"
    
    1. Save the script as set_proxy.sh. Modify the file on demand and run the script using the following steps. Ensure that the proxy steps are enabled to /etc/profile after the setup.
      # chmod u+x set_proxy.sh
      #./set_proxy.sh <proxy url> <no proxy nets sperated by comma>
      For e.g:
      #./set_proxy.sh http://proxy.eng.vmware.com:8118 “192.168.111.0/24,agserver.eng.vmware.com”
      # source /etc/profile
    2. Verify that the proxy setup is running:
      #curl https://www.vmware.com --head
      Expect at least 200 OK returns. If not, apply /etc/profile again with the following command and retry:
      #source /etc/profile
  4. (Optional) Modify the IP configurations.
    By default, all NICs in Photon OS are configured with DHCP and the configuration file is at /etc/systemd/network/. The default configuration filename is 99-dhcp-en.network and its content is:
    [Match]
    Name=e*
    
    [Network]
    DHCP=yes
    IPv6AcceptRA=no
    To configure the static IP address, perform the following steps:
    1. Run the following commands:
      #touch 10-static-ethX.network  //X can be replaced by nic number, for exp: eth1
      #chmod 644 10-static-ethX.network  
    2. Open the editor and enter the following configuration:
      [Match]
      Name=eth1
      
      [Network]	
      Address=192.168.111.123/24
      Gateway=192.168.111.1
      DNS=192.168.111.1
    3. Save the configuration file and restart the network service:
      #systemctl restart systemd-networkd
      
      For detailed information, see the Photon OS official document here.
  5. After deploying the Photon OS, update it, and reboot the system. This step upgrades the system kernel to a newer version. Open a command prompt and run the following command:
    #tdnf makecache
    #tdnf update
    #reboot
    
  6. Verify that the TDNF package manager upgrades to version 3.1.0 or later, that contains the reposync feature. Run the following command:
    #tdnf --version
  7. The default firewall rules of Photon OS blocks external access, except SSH. Ensure that you enable access to HTTPS for Harbor and repository services:
    # iptables -A INPUT -p tcp --dport 443 -j ACCEPT
    1. To ensure that the service is available on reboot, add the rule to the saved list:
      # vi /etc/systemd/scripts/ip4save
    2. Add the new rule below the row -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT.
      -A INPUT -p tcp --dport 443 -j ACCEPT
    3. Save the file.
  8. Install the following missing tools. These tools are required during setup:
    1. wget - #tdnf install wget
    2. tar - #tdnf install tar
    3. imgpkg -
      #wget https://github.com/vmware-tanzu/carvel-imgpkg/releases/download/v0.12.0/imgpkg-linux-amd64
      #cp imgpkg-linux-amd64 /usr/local/bin/imgpkg
    4. yq -
      #wget https://github.com/mikefarah/yq/releases/download/v4.9.1/yq_linux_amd64
      #cp yq_linux_amd64 /usr/local/bin/yq
    5. jq -
      #wget https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
      #cp jq-linux64 /usr/local/bin/jq
    6. Change the permissions of the imgpkg, jq, and yq tools under /usr/local/bin:
      #cd /usr/local/bin
      #chmod 755 imgpkg jq yq
    7. Install the OpenSSL rehash tool:
      # tdnf install openssl-c_rehash -y
  9. Load the veth kernel module and restart the Docker service.
    #lsmod |grep veth
    If the module does not load, run the commands:
    #modprobe veth
    #lsmod |grep veth
    For the module to auto-load on reboot, make the following change:
    #echo "veth" > /etc/modules-load.d/20-veth.conf
    1. Restart the Docker service:
      #systemctl restart docker.service
      
    2. Verify that the Docker service restarted successfully:
      #systemctl status docker.service
    3. Enable Docker service on boot:
      #systemctl enable docker.service
  10. The repositories of Photon OS require 50 GB of memory. Considering future expansion, allocate about 100 GB of disk space for them. Harbor repository requires about 15 GB of disk space and Docker requires about 30 GB of disk space. In total, add a 200 GB disk to the virtual machine. Then perform the following steps:
    1. Use fdisk to create partitions on the disk:
      #root@photon-machine [ ~ ]# fdisk /dev/sdb  <use real disk name in your setup>
      Welcome to fdisk (util-linux 2.32.1).
      Changes will remain in memory only, until you decide to write them.
      Be careful before using the write command.
      
      Device does not contain a recognized partition table.
      Created a new DOS disklabel with disk identifier 0x8515b285.
      
      Command (m for help): n <<<<<< create 1st new partition
      Partition type
         p   primary (0 primary, 0 extended, 4 free)
         e   extended (container for logical partitions)
      Select (default p): p   <<<<<< set as primary partition
      Partition number (1-4, default 1): 1
      First sector (2048-419430399, default 2048): 
      Last sector, +sectors or +size{K,M,G,T,P} (2048-419430399, default 419430399): +50GB   <<<<<< first partition allocate 50GB
      
      Created a new partition 1 of type 'Linux' and of size 46.6 GiB.
      
      Command (m for help): n <<<<<< create 2nd new partition
      Partition type
         p   primary (1 primary, 0 extended, 3 free)
         e   extended (container for logical partitions)
      Select (default p): p   <<<<<< set as primary partition
      Partition number (2-4, default 2): 2
      First sector (97658880-419430399, default 97658880): 
      Last sector, +sectors or +size{K,M,G,T,P} (97658880-419430399, default 419430399): +50GB   <<<<<< second partition allocate 50GB
      
      Created a new partition 2 of type 'Linux' and of size 46.6 GiB.
      
      Command (m for help): n <<<<<< create 3rd new partition
      Partition type
         p   primary (2 primary, 0 extended, 2 free)
         e   extended (container for logical partitions)
      Select (default p): p   <<<<<< set as primary partition
      Partition number (3,4, default 3): 3
      First sector (195315712-419430399, default 195315712): 
      Last sector, +sectors or +size{K,M,G,T,P} (195315712-419430399, default 419430399):   <<<<<< click return here to use all the left space on disk
      
      Created a new partition 3 of type 'Linux' and of size 106.9 GiB.
      
      Command (m for help): p <<<<<< print the partition table to double check
      Disk /dev/sdb: 200 GiB, 214748364800 bytes, 419430400 sectors
      Units: sectors of 1 * 512 = 512 bytes
      Sector size (logical/physical): 512 bytes / 512 bytes
      I/O size (minimum/optimal): 512 bytes / 512 bytes
      Disklabel type: dos
      Disk identifier: 0x8515b285
      
      Device     Boot     Start       End   Sectors   Size Id Type
      /dev/sdb1            2048  97658879  97656832  46.6G 83 Linux
      /dev/sdb2        97658880 195315711  97656832  46.6G 83 Linux
      /dev/sdb3       195315712 419430399 224114688 106.9G 83 Linux
      
      Command (m for help): w <<<<<< write change to disk
      
    2. Create file systems on the new partitions:
      # mkfs.ext4 /dev/sdb1
      # mkfs.ext4 /dev/sdb2
      # mkfs.ext4 /dev/sdb3
      
    3. Mount the new partitions:
      • For Harbor:
        #mkdir /data
        #mount /dev/sdb1 /data
      • For Docker:
        #systemctl stop docker.service
        #mkdir /docker
        #mount /dev/sdb2 /docker
        #mv /var/lib/docker/* /docker/
        #rmdir /var/lib/docker
        #ln -s /docker /var/lib/
        #systemctl start docker.service
        #systemctl status docker.service
      • For the Photon repository:
        #mkdir /photon-reps/
        #mount /dev/sdb3 /photon-reps/
        #mkdir -p /photon-reps/updates
        #mkdir -p /photon-reps/release
    4. Set up auto-mount for the new partitions. Edit the /etc/fstab file and add the following rows:
      /dev/sdb1   /data   ext4   defaults   0 0
        /dev/sdb2   /docker  ext4  defaults  0 0
        /dev/sdb3   /photon-reps ext4 defaults  0 0