This the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

User Guide

The Photon OS User Guide provides information about how to use Photon OS as a developer.

The User Guide covers the basics of setting up a Network PXE Boot Server, working with Kickstart and Kubernetes, and mounting remote file systems.

Product version: 4.0

This documentation applies to all 4.0.x releases.

Intended Audiences

This information is intended for Photon OS developers who use Photon OS.

1 - Setting Up Network PXE Boot

Photon OS supports the Preboot Execution Environment, or PXE, over a network connection. This document describes how to set up a PXE boot server to install Photon OS.

Server Setup

To set up a PXE server, you will need to have the following:

  • A DHCP server to allow hosts to get an IP address.
  • A TFTP server, which is a file transfer protocol similar to FTP with no authentication.
  • Optionally, an HTTP server. The HTTP server will serve the RPMs yum repo, or you can use the official VMware Photon Packages repo. Also, this HTTP server can be used if you want to provide a kickstart config for unattended installation.

The instructions to set up the servers assume you have an Ubuntu 14.04 machine with a static IP address of

DHCP Setup

  • Install the DHCP server:

    sudo apt-get install isc-dhcp-server  
  • Edit the Ethernet interface in /etc/default/isc-dhcp-server to INTERFACES="eth0"

  • Edit the DHCP configuration in /etc/dhcp/dhcpd.conf to allow machines to boot and get an IP address via DHCP in the range -, for example:

    subnet netmask {
      option subnet-mask;
      option routers;
      option broadcast-address;
      filename "pxelinux.0";
  • Restart the DHCP server:

    sudo service isc-dhcp-server restart

TFTP Setup

  • Install the TFTP server:

    sudo apt-get install tftpd-hpa
  • Enable the boot service and restart the service:

    sudo update-inetd --enable BOOT
    sudo service tftpd-hpa restart

Optional: HTTP server setup

This step is only needed if you are planning to serve the ks (kickstart) config file through this server; refer to Kickstart support for details.

  • Serving your local yum repo.

You can install apache http web server:

sudo apt-get install apache2

Mount the Photon iso to get the RPMS repo and sample ks config file:

mkdir /mnt/photon-iso
sudo mount <photon_iso> /mnt/photon-iso/

Copy the RPMS repo:

cp -r /mnt/photon-iso/RPMS /var/www/html/

To support ks, you can copy the sample config file from the iso and edit it; refer to Kickstart support for details.

cp /mnt/photon-iso/isolinux/sample_ks.cfg /var/www/html/my_ks.cfg

PXE boot files setup

  • Mount photon.iso to get Linux and initrd images:
mkdir /mnt/photon-iso
sudo mount <photon_iso> /mnt/photon-iso/
  • Setting the PXE boot files:
tar -xvf syslinux-6.03.tar.gz
pushd /var/lib/tftpboot
cp -r /mnt/photon-iso/isolinux/* .
cp ~/syslinux-6.03/bios/com32/elflink/ldlinux/ldlinux.c32 .
cp ~/syslinux-6.03/bios/com32/lib/libcom32.c32 .
cp ~/syslinux-6.03/bios/com32/libutil/libutil.c32 .
cp ~/syslinux-6.03/bios/com32/menu/vesamenu.c32 .
cp ~/syslinux-6.03/bios/core/pxelinux.0 .
mkdir pxelinux.cfg
mv isolinux.cfg pxelinux.cfg/default
  • Update repo param to point to http yum repo; you may pass official photon packages repo.
sed -i "s/append/append repo=http:\/\/\/RPMS/g" menu.cfg

2 - Kickstart Support in Photon OS

Photon OS works with kickstart for unattended, automated installations. The kickstart configuration file can be served through an HTTP server. You can also provide the kickstart configuration file through a secondary device or a CD-ROM attached to the host.

Kickstart Capabilities

Photon OS supports the following configurations with kickstart:

  • Setting the hostname
  • Setting the password
  • Setting the disk to install
  • Selecting whether to install the full or the minimal version of Photon OS
  • Applying a post-installation script
  • Adding public keys to allow the root account to log in through SSH

Permitted JSON Fields

The following is a list of allowed JSON fields and their descriptions:


Set the target host name as string. You can also specify the name in print format.

The hostname must not start with a number or "-" and must be less than 64 characters.

Default value: "photon-"

Examples: { "photon-$((RANDOM%4096))" }, { "photon-machine" }


crypted: true/false

text: password text

crypted: true: This indicates that the "text" field is already encrypted. In this case, the specified password is used as is for the root user.

crypted: false: This indicates that the "text" field is plain text. It is then encrypted and used to create the root user's password.

text: Plain text or encrypted password.

diskIndicates the install disk.

Example: /dev/sda

partitionsAn array of partition definitions.

To create GPT partitions



{"mountpoint": "/", "size": 0, "filesystem": "ext4"},

{"mountpoint": "/boot", "size": 128, "filesystem": "ext4"},

{"mountpoint": "/root", "size": 128, "filesystem": "ext4"},

{"size": 128, "filesystem": "swap"}


To create LVM partitions



{"mountpoint": "/", "size": 0, "filesystem": "ext4", "lvm":{"vg_name":"vg1", "lv_name":"rootfs"}},

{"mountpoint": "/boot", "size": 128, "filesystem": "ext4"},

            <p>{"mountpoint": "/root", "size": 128, "filesystem": "ext4","lvm":{"vg_name":"vg1", "lv_name":"root"}},

            <p>{"size": 128, "filesystem": "swap","lvm":{"vg_name":"vg2", "lv_name":"swap"}}


Note: Mounting '/boot' partition as lvm is not supported.

packagelist_fileIndicates the name of the file that contains the list of packages to install.

Example: { "packagelist_file": "packages_minimal.json" }

additional_packagesSpecify an array of additional packages.
install_linux_esxSpecify a boolean value to use linux esx instead of generic linux.
postinstallSpecify an array of bash commands to execute after install.

See the example for partitions.

Example: { "postinstall": [ "#!/bin/sh", "echo \"Hello World\" > /etc/postinstall" ] }


The public key that you require to install for password-less logins.

This key is created in authorized_keys in the .ssh directory.


Contains a list of pairs {source file (or directory), destination file (or directory)} to copy to the target system. Source file (directory) will be looked up in "search_path" list.

Example: { "additional_files": [ {"": "/usr/local/bin/"}, {"resizefs.service": "/lib/systemd/system/resizefs.service"}]}


Provide a path containing additional RPMS that are to be bundled into the image.


Target system architecture. Should be set if target architecture is different from the host, for instance x86_64 machine building RPi image. Acceptable values are: "x86_64", "aarch64" Default value: autodetected host architecture

Example: { "arch": "aarch64" }


Sets the boot type to support: EFI, BIOS or both.

Acceptable values are: bios, efi, dualboot


Adds special partition (very first) for first stage grub.


Adds ESP (Efi Special Partition), format is as FAT and copy there EFI binaries including grub.efi


Adds two extra partitions for "bios" and "efi" modes. This target will support both modes that can be switched in bios settings without extra actions in the OS.

Default value: "dualboot" for x86_64 and "efi" for aarch64

Example: { "bootmode": "bios" }


Ejects cdrom after installation completed if set to true.

Boolean: true or false

Default value: true

Example: { "eject_cdrom": false }


Should be set to false if target system is not being run on host machine. When it set to false, installer will not add EFI boot entries, and will not generate unique machine-id.

Default value: false if "disk" is /dev/loop and true otherwise.

Example: { "live": false }


Set installer logging level.

Acceptable values are: error, warning, info, debug

Default value: info

Example: { "log_level": "debug" }


Atomic flavour of Photon OS.



Define the type of repo data used for installing the OS There are two type:

1. Default Repo(comes with ISO)

2. Custom Repo (Remote server)

Boolean: true or false

where true : Default Repo is selected

false: Custom Repo is selected

Default value: true Example: { "ostree": {"default_repo": true}}


(Required, Only If Custom Repo is selected) Supported Value: Valid "repo" URL of remote server where repo data exists


(Required, Only If Custom Repo is selected) Supported Value: Valid "ref" path which was mentioned for creation of Base Tree on remote server

Example: { "ostree": { "default_repo": false, "repo_url": "http://:/repo", "repo_ref": "photon/3.0/x86_64/minimal" } }

packagesOptional if packagelist_file set.

Contains list of packages to install.

Example: { "packages": ["minimal", "linux", "initramfs"] }


Set partition table type. Supported values are: gpt, msdos.

Default value: gpt

Example: { "partition_type": "msdos" }


Used to configure network on a live/installed system.



String; must be one of dhcp/static/vlan. Indicates how the network is being configured.


optional; when type == dhcp

String; DHCP client hostname


required; when type == static

IP String; IP address to be configured


required; when type == static

IP String; Netmask to be configured


required; when type == static

IP String; Gateway IP address to be configured


required; when type == static

IP String; Name server IP address to be configured


required; when type == vlan

ID String. (1-4094); VLAN ID number expressed as string


Contains list of scripts to run on the target after installation. Scripts will be looked up in "search_path" list.

Example: { "postinstallscripts": [""] }


List of directories to search for additional files and scripts.

Example: { "search_path": ["/home/user", "/tmp"] }


Contains encrypted root password. Short form of: { "password": { "crypted": true, "text": "encrypted password here"} }


Installer will show progress status in the UI, if it set to true. Or logging output will be printed to console - default behavior.

Boolean: true or false

Default value: false

Example: { "ui": true }

linux_flavorRequired if multiple Linux flavors are present in the list of packages to install.

Contains the flavor of Linux to install if multiple Linux flavors are present in "packages" or "packagelist_file"

Acceptable values: "linux", "linux-esx", "linux-rt", "linux-aws", and "linux-secure"

Example: { "linux_flavor": "linux-esx" }


Contains the docker image present in "packages" or "packagelist_file"

Acceptable values: "photon:1.0", "photon:2.0", "photon:3.0", "photon" and so on.

Default value: "photon:latest"

Example: { "photon_docker_image": "photon:3.0" }


Contains the photon release version.

Acceptable values: "3.0", "4.0"

Example: {"release_version": "3.0"}

For reference, look at "sample_ks.cfg" file.

Sample Configuration File

Example kickstart configuration file:

    "hostname": "photon-machine",
            "crypted": false,
            "text": "changeme"
    "disk": "/dev/sda",
	"bootmode": "bios",
    "packagelist_file": "packages_minimal.json",
    "additional_packages": [
    "postinstall": [
        "echo \"Hello World\" > /etc/postinstall"
    "public_key": "<ssh-key-here>",
    "linux_flavor": "linux",
    "network": {
        "type": "dhcp"

Installing Root Partition as LVM

In the kickstart file modify the partitions field to mount root partition as LVM.

For example:



  • vg_name : Volume Group Name
  • lv_name : Logical Volume Name

In above example rootfs, root are logical volumes in the volume group vg1 and swap is logical volume in volume group vg2, physical volumes are part of disk /dev/sda.

Multiple disks are also supported. For example:

"disk": "/dev/sda"

If disk name is not specified, the physical volumes will be part of the default disk: dev/sda.

In above example rootfs,root and swap are logical volumes in volume group vg1, physical volumes are in the disk /dev/sdb and partitions are present in /dev/sda.

Note: Mounting /boot partition as LVM is not supported.

Unattended Installation Through Kickstart

For an unattended installation, you pass the ks=<config_file> parameter to the kernel command. To pass the config file, there are three options:

  1. Provide it in the ISO through a CD-ROM attached to the host.
  2. Provide it in the ISO through a specified secondary device.
  3. Serving it from an HTTP server.

The syntax to pass the configuration file to the kernel through the CD-ROM takes the following form:


For example:


The syntax to pass the configuration file to the kernel through a secondary device takes the following form:


For example:


The syntax to serve the configuration file to the kernel from a HTTPS server takes the following form:


To use HTTP path or self-signed HTTPS path, you have to enable insecure_installation by using insecure_installation=1 along with defining the ks path. The kernel command line argument, insecure_installation, acts as a flag that user can set to 1 to allow some operations that are not normally allowed due to security concerns. This is disabled by default and it is up to the user to the ensure security when this options is enabled.

HTTP example:

ks=http://<server>/<config_file_path> insecure_installation=1

HTTPS (self-signed) example:

ks=https://<server>/<config_file_path> insecure_installation=1

Building an ISO with a Kickstart Config File

Here’s an example of how to add a kickstart config file to the Photon OS ISO by mounting the ISO on an Ubuntu machine and then rebuilding the ISO. The following example assumes you can adapt the sample kickstart configuration file that comes with the Photon OS ISO to your needs. You can obtain the Photon OS ISO for free from VMware at the following URL:

Once you have the ISO, mount it.

mkdir /tmp/photon-iso
sudo mount photon.iso /tmp/photon-iso

Then copy the content of the ISO to a writable directory and push it into the directory stack:

mkdir /tmp/photon-ks-iso
cp -r /tmp/photon-iso/* /tmp/photon-ks-iso/
pushd /tmp/photon-ks-iso/

Next, copy the sample kickstart configuration file that comes with the Photon OS ISO and modify it to suit your needs. In the ISO, the sample kickstart config file appears in the isolinux directory and is named sample_ks.cfg. The name of the directory and the name of the file might be in all uppercase letters.

cp isolinux/sample_ks.cfg isolinux/my_ks.cfg
nano isolinux/my_ks.cfg

With a copy of the sample kickstart config file open in nano, make the changes that you want.

Now add a new item to the installation menu by modifying isolinux/menu.cfg and boot/grub2/grub.cfg:

cat >> isolinux/menu.cfg << EOF
label my_unattended
	menu label ^My Unattended Install
	menu default
	kernel vmlinuz
	append initrd=initrd.img root=/dev/ram0 ks=<ks_path>/my_ks.cfg loglevel=3

cat >> boot/grub2/grub.cfg << EOF
set default=0
set timeout=3
loadfont ascii
set gfxmode="1024x768"
set theme=/boot/grub2/themes/photon/theme.txt
terminal_output gfxterm
probe -s photondisk -u ($root)

menuentry "Install" {
    linux /isolinux/vmlinuz root=/dev/ram0 ks=<ks_path>/my_ks.cfg loglevel=3$photondisk
    initrd /isolinux/initrd.img

Following is an example of the ks path:


Note: You can specify any mount media through which you want to boot Photon OS. To specify the mount media, specify the path of the mount media device in the field. You can specify the path as shown in the following syntax:<path of the Photon OS ISO>

Finally, rebuild the ISO so that it includes your kickstart config file:

mkisofs -R -l -L -D -b isolinux/isolinux.bin -c isolinux/ \
                -no-emul-boot -boot-load-size 4 -boot-info-table \
                -eltorito-alt-boot --eltorito-boot boot/grub2/efiboot.img -no-emul-boot \
                -V "PHOTON_$(date +%Y%m%d)" . > <new_iso_path>.iso


3 - Kubernetes on Photon OS

You can use Kubernetes with Photon OS. The instructions in this section present a manual configuration that gets one worker node running to help you understand the underlying packages, services, ports, and so forth.

The Kubernetes package provides several services: kube-apiserver, kube-scheduler, kube-controller-manager, kubelet, kube-proxy. These services are managed by systemd. Their configuration resides in a central location: /etc/kubernetes.

3.1 - Prerequisites

You need two or more machines with version 3.0 “GA” or later of Photon OS installed. It is recommended to use the latest 4.0 GA version.

3.2 - Running Kubernetes on Photon OS

The procedure describes how to break the services up between the hosts.

The first host, photon-master, is the Kubernetes master. This host runs the kube-apiserver, kube-controller-manager, and kube-scheduler. In addition, the master also runs etcd. Although etcd is not needed on the master if etcd runs on a different host, this guide assumes that etcd and the Kubernetes master run on the same host. The remaining host, photon-node, is the node and runs kubelet, proxy, and docker.

3.2.1 - System Information


photon-master =
photon-node =

3.2.2 - Prepare the Hosts

The following packages have to be installed. If the tdnf command returns “Nothing to do,” the package is already installed.

  • Install Kubernetes on all hosts (both photon-master and photon-node).

    tdnf install kubernetes
  • Install iptables on photon-master and photon-node:

    tdnf install iptables
  • Open the tcp port 8080 (api service) on the photon-master in the firewall

    iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
  • Open the tcp port 10250 (api service) on the photon-node in the firewall

    iptables -A INPUT -p tcp --dport 10250 -j ACCEPT
  • Install Docker on photon-node:

    tdnf install docker
  • Add master and node to /etc/hosts on all machines (not needed if the hostnames are already in DNS). Make sure that communication works between photon-master and photon-node by using a utility such as ping.

    echo "	photon-master	photon-node" >> /etc/hosts
  • Edit /etc/kubernetes/config, which will be the same on all the hosts (master and node), so that it contains the following lines:

    # Comma separated list of nodes in the etcd cluster
    # logging to stderr routes it to the systemd journal
    # journal message level, 0 is debug
    # Should this cluster be allowed to run privileged docker containers

3.2.3 - Configure Kubernetes Services on the Master

Perform the following steps to configure Kubernetes services on the master:

  1. Edit /etc/kubernetes/apiserver to appear as such. The service_cluster_ip_range IP addresses must be an unused block of addresses, not used anywhere else. They do not need to be routed or assigned to anything.

    # The address on the local server to listen to.
    # Comma separated list of nodes in the etcd cluster
    # Address range to use for services
    # Add your own
  2. Start the appropriate services on master:

    for SERVICES in etcd kube-apiserver kube-controller-manager kube-scheduler; do
    	systemctl restart $SERVICES
    	systemctl enable $SERVICES
    	systemctl status $SERVICES
  3. To add the other node, create the following node.json file on the Kubernetes master node:

        "apiVersion": "v1",
        "kind": "Node",
        "metadata": {
            "name": "photon-node",
            "labels":{ "name": "photon-node-label"}
        "spec": {
            "externalID": "photon-node"
  4. Create a node object internally in your Kubernetes cluster by running the following command:

    $ kubectl create -f ./node.json
    $ kubectl get nodes
    NAME                LABELS              STATUS
    photon-node         name=photon-node-label     Unknown

Note: The above example only creates a representation for the node photon-node internally. It does not provision the actual photon-node. Also, it is assumed that photon-node (as specified in name) can be resolved and is reachable from the Kubernetes master node.

3.2.4 - Configure the Kubernetes services on Node

Perform the following steps to configure the kubelet on the node:

  1. Edit /etc/kubernetes/kubelet to appear like this:

    # Kubernetes kubelet (node) config
    # The address for the info server to serve on (set to or "" for all interfaces)
    # You may leave this blank to use the actual hostname
    # location of the api-server
    # Add your own
  2. Make sure that the api-server end-point located in /etc/kubernetes/kubeconfig, targets the api-server in the master node and does not fall into the loopback interface:

    apiVersion: v1
    - cluster:
        server: <ip_master_node>:8080
  3. Start the appropriate services on the node (photon-node):

    for SERVICES in kube-proxy kubelet docker; do 
        systemctl restart $SERVICES
        systemctl enable $SERVICES
        systemctl status $SERVICES 
  4. Check to make sure that the cluster can now see the photon-node on photon-master and that its status changes to Ready.

    kubectl get nodes
    NAME                LABELS              STATUS
    photon-node          name=photon-node-label     Ready

    If the node status is NotReady, verify that the firewall rules are permissive for Kubernetes.

    • Deletion of nodes: To delete photon-node from your Kubernetes cluster, one should run the following on photon-master (please do not do it, it is just for information):
    kubectl delete -f ./node.json


You should have a functional cluster. You can now launch a test pod. For an introduction to working with Kubernetes, see Kubernetes documentation.

4 - Photon NFS Utilities for Mounting Remote File Systems

This document describes how to mount a remote file system on Photon OS by using nfs-utils, a commonly used package that contains tools to work with the Network File System protocol (NFS).

Check a Remote Server

showmount  -e nfs-servername or ip


showmount -e
showmount -e

Mount a Remote File System in Photon Full

The nfs-utils package is installed by default in the full version of Photon OS. Here is how to mount a directory through NFS on Photon OS:

mount -t nfs nfs-ServernameOrIp:/exportfolder /mnt/folder


mount -t nfs /mnt/filer
mount -t nfs /mnt/export

Mount a Remote File System in Photon Minimal

The nfs-utils package is not installed in the minimal version of Photon OS. You install it by running the following command:

tdnf install nfs-utils

For more information on installing packages with the tdnf command, see the Photon OS Administration Guide.

Once nfs-utils is installed, you can mount a file system by running the following commands, replacing the placeholders with the path of the directory that you want to mount:

mount nfs
mount -t nfs nfs-ServernameOrIp:/exportfolder /mnt/folder