ARTIFACTORY: Installation Quick Start Guide - Helm
What will you get?This guide provides step-by-step instructions for deploying Artifactory using Helm in a production-ready configuration. In this example, we will carry out the installation on an EKS cluster. All commands presented are compatible with Helm version 3 and above. For experienced users seeking more in-depth information, we recommend consulting our Advanced User Guide for topics not covered in this quick-start tutorial.
Prerequisites- Kubernetes 1.27+
- 3 Artifactory HA license ( One licenses per node )
- Default storageclass for dynamic PV creation
- Load balancer Resources for exposing artifactory service
- TLS certificates for your domain if you are using SSL
Source Code and ReleasesArtifactory-HA charts can be found on github or chartcenter.
For information about the default Artifactory version associated with each chart release, please refer to the release notes. We also recommend consulting our official documentation for the most recent updates.
Environment DetailsIn the table below we will list the environment details for the sample deployment we are going to demonstrate. You can find more information about the system resources requirements here.
|
Aspect |
Detail |
|
Versions |
107.104.10
|
|
Resources |
|
|
Network |
|
|
Persistence |
Cloud file system with direct S3
|
|
Database |
Postgresql Database
|
|
License |
3 enterprise/enterprise plus licenses are needed
|
We will be deploying the release under namespace: jfrog and as release-name: artifactory-haSteps to InstallGet the chartBefore installing JFrog helm charts, you need to add the JFrog helm repository to your helm client$ helm repo add jfrog https://charts.jfrog.io
Now, update the repository.$ helm repo update
Prepare ConfigurationsMaster Key and Join KeyArtifactory will generate the following keys upon installation. It is essential to configure these keys during a fresh installation in a production environment, as failing to do so will result in the use of default placeholder key values. Please ensure that you securely save these key values for future reference.Create a unique Master Key# Create a key
export MASTER_KEY=$(openssl rand -hex 32)
echo ${MASTER_KEY}Create a “masterkey-secret” to hold the value$ kubectl create secret generic masterkey-secret --from-literal=master-key=${MASTER_KEY}Create a unique Join KeyBy default, the chart will also set a Join Key value for you. For a production environment, we highly recommend setting a unique value.# Create a join key
export JOIN_KEY=$(openssl rand -hex 32)
echo ${JOIN_KEY}Create a secret containing the key. The key in the secret must be named join-key$ kubectl create secret generic joinkey-secret --from-literal=join-key=${JOIN_KEY}License secretTo activate Artifactory High Availability (HA), you need to install the appropriate licenses.
In this guide, we will demonstrate how to pass the license as a secret, assuming you have been provided with the trial license key.
Please note that this step is optional. If you are installing Artifactory with a fresh database, you will be prompted to enter the license key or add the license bucket during your first visit to Artifactory, without the need to provide the license as a secret.
1. Prepare a text file with the license(s) written in it. If writing multiple licenses (must be in the same file),
it's important to put **two new lines between each license block**!
2. Create the Kubernetes secret (assuming the local license file is 'art.lic')
$ kubectl create secret generic artifactory-cluster-license -n artifactory-ha --from-file=./art.lic
# Pass the license to helm
helm upgrade --install artifactory-ha --set artifactory.license.secret=artifactory-cluster-license,artifactory.license.dataKey=art.lic
ResourcesIn this sample deployment, we will refer the large sizing documents here. It is important to validate the actual resources available on your worker nodes to ensure there are sufficient resources to host these pods.
For further sizing recommendations, please refer to the relevant documentation hereIf you notice that Artifactory is underperforming despite having ample physical resources, we recommend reviewing the tuning section in the glossary for optimization tips.
Artifactory now supports active-active clustering; therefore, we will only scale the primary StatefulSet in the HA chart, leaving the node.replicaCount set to 0.
We will incorporate these properties into the values.yaml file.
splitServicesToContainers: true
artifactory:
primary:
replicaCount: 3
podAntiAffinity:
type: "hard"
resources:
requests:
cpu: "2"
memory: 10Gi
limits:
# cpu: "14"
memory: 12Gi
javaOpts:
other: >
-XX:InitialRAMPercentage=40
-XX:MaxRAMPercentage=65
-Dartifactory.async.corePoolSize=80
-Dartifactory.async.poolMaxQueueSize=20000
-Dartifactory.http.client.max.total.connections=100
-Dartifactory.http.client.max.connections.per.route=100
-Dartifactory.access.client.max.connections=125
-Dartifactory.metadata.event.operator.threads=4
-XX:MaxMetaspaceSize=512m
-Djdk.nio.maxCachedBufferSize=524288
-XX:MaxDirectMemorySize=512m
tomcat:
connector:
maxThreads: 500
extraConfig: 'acceptCount="800" acceptorThreadCount="2" compression="off" connectionLinger="-1" connectionTimeout="120000" enableLookups="false"'
database:
maxOpenConnections: 100
extraEnvironmentVariables:
- name: MALLOC_ARENA_MAX
value: "8"
- name: SKIP_WAIT_FOR_EXTERNAL_DB
value: "true"
access:
tomcat:
connector:
maxThreads: 125
javaOpts:
other: >
-XX:InitialRAMPercentage=20
-XX:MaxRAMPercentage=60
database:
maxOpenConnections: 100
resources:
requests:
cpu: 1
memory: 2Gi
limits:
# cpu: 2
memory: 3Gi
extraEnvironmentVariables:
- name: MALLOC_ARENA_MAX
value: "8"
- name: SKIP_WAIT_FOR_EXTERNAL_DB
value: "true"
router:
resources:
requests:
cpu: 400m
memory: 800Mi
limits:
# cpu: "8"
memory: 2Gi
frontend:
resources:
requests:
cpu: 200m
memory: 300Mi
limits:
# cpu: "3"
memory: 1Gi
metadata:
database:
maxOpenConnections: 100
resources:
requests:
cpu: 200m
memory: 200Mi
limits:
# cpu: "4"
memory: 1Gi
onemodel:
resources:
requests:
cpu: 200m
memory: 160Mi
limits:
# cpu: "1"
memory: 250Mi
event:
resources:
requests:
cpu: 100m
memory: 50Mi
limits:
# cpu: 500m
memory: 250Mi
observability:
resources:
requests:
cpu: 100m
memory: 50Mi
limits:
# cpu: 500m
memory: 250Mi
jfconnect:
resources:
requests:
cpu: 50m
memory: 100Mi
limits:
# cpu: 500m
memory: 250Mi
topology:
resources:
requests:
cpu: 100m
memory: 1000Mi
limits:
memory: 1500Mi
extraEnvironmentVariables:
- name: MALLOC_ARENA_MAX
value: "8"
PersistenceIn this example, we will configure the binary provider to use direct-s3 with an IAM role as it is the recommended provider for using a block provider like s3. For additional options, you may also refer to the documentation for the filestore provider.
Please note that even though your filestore is now based on S3, the deployment will still attempt to create one PersistentVolumeClaim (PVC) per pod to persist the Artifactory home folder, which includes all your configurations and logs. Ensure that you have a default StorageClass set up to provision these PVCs, or specify the desired StorageClass name that you wish to use. If you do not need to persist logs and configurations, you also have the option to disable persistence.
To set up your direct-s3 binarystore
Create the binarystore.xml secret or pull the values from environment variables.
$ kubectl create secret generic my-binarystore --from-file=binarystore.xml
binarystore.xml:
<config version="2">
<chain>
<provider id="cache-fs" type="cache-fs">
<provider id="s3-storage-v3" type="s3-storage-v3"/>
</provider>
</chain>
<provider id="s3-storage-v3" type="s3-storage-v3">
<endpoint>s3.amazonaws.com</endpoint>
<bucketName>bucketName</bucketName>
<path>pathPrefix</path>
<usePresigning>true</usePresigning>
<signatureExpirySeconds>600</signatureExpirySeconds>
<maxConnections>50</maxConnections>
<connectionTimeout>10000</connectionTimeout>
<useInstanceCredentials>true</useInstanceCredentials>
</provider>
<provider type="cache-fs" id="cache-fs">
<maxCacheSize>5000000000</maxCacheSize>
</provider>
</config>
Then, create an IAM role with AmazonS3FullAccess permission
Associate an IAM role to the service account in values-artifactory.yaml by specifying the ARN:
serviceAccount: create: true annotations: eks.amazonaws.com/role-arn: arn:aws:iam::<ACCOUNT_ID>:role/<IAM_ROLE_NAME>
We will add the properties above to the values.yamlartifactory:
serviceAccount:
create: true
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<ACCOUNT_ID>:role/<IAM_ROLE_NAME>
persistence:
enabled: true
storageClassName: myclass
accessMode: ReadWriteOnce
size: 100Gi
customBinarystoreXmlSecret: my-binarystore
DatabaseFor this example, we assume you already have a production-ready database that is reachable from the cluster you are deploying to.
To quickly start the installation with the bundled postgresql database, follow our installation guide here
To prepare the database or checkout other database options, please reference here
Database secret
Database credentials can also be supplied with a secret.kubectl create secret generic my-database --from-literal=db-url='database_url' --from-literal=db-user='admin_user' --from-literal=db-password='password' -n jfrog
We will then reference the database in values.yaml:postgresql:
enabled: false
database:
type: "postgresql"
driver: org.postgresql.Driver
secrets:
user:
name: "my-database"
key: "db-user"
password:
name: "my-database"
key: "db-password"
url:
name: "my-database"
key: "db-url"
NetworkThere are various methods to expose the Artifactory service and establish SSL connections.
For this deployment, we will utilize the bundled NGINX deployment and expose it using a LoadBalancer service type as a quickstart.
In this setup, NGINX will handle SSL termination and then forward the traffic to the Artifactory service. To achieve this, we will first create a TLS secret to store the SSL certificate.
$ kubectl create secret tls artifactory-tls --cert=path/to/tls.cert --key=path/to/tls.key -n jfrog
We will add the properties above to a values.yaml ingress:
enabled: false
nginx:
enabled: true
service:
type: LoadBalancer
ssloffload: true
tlsSecretName: artifactory-tls
replicaCount: 3
disableProxyBuffering: true
resources:
requests:
cpu: "1"
memory: "500Mi"
limits:
# cpu: "4"
memory: "1Gi"
Install your releasesNow that we have all the properties in place, we are ready to deploy
Here are all the env variables we will be passing to chart:
$ env POSTGRES_USERNAME=artifactory POSTGRES_PASSWORD=password
Here is the final values.yaml file:splitServicesToContainers: true
artifactory:
serviceAccount:
create: true
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<ACCOUNT_ID>:role/<IAM_ROLE_NAME>
persistence:
enabled: true
storageClassName: myclass
accessMode: ReadWriteOnce
size: 100Gi
customBinarystoreXmlSecret: my-binarystore
primary:
replicaCount: 3
podAntiAffinity:
type: "hard"
resources:
requests:
cpu: "2"
memory: 10Gi
limits:
# cpu: "14"
memory: 12Gi
javaOpts:
other: >
-XX:InitialRAMPercentage=40
-XX:MaxRAMPercentage=65
-Dartifactory.async.corePoolSize=80
-Dartifactory.async.poolMaxQueueSize=20000
-Dartifactory.http.client.max.total.connections=100
-Dartifactory.http.client.max.connections.per.route=100
-Dartifactory.access.client.max.connections=125
-Dartifactory.metadata.event.operator.threads=4
-XX:MaxMetaspaceSize=512m
-Djdk.nio.maxCachedBufferSize=524288
-XX:MaxDirectMemorySize=512m
tomcat:
connector:
maxThreads: 500
extraConfig: 'acceptCount="800" acceptorThreadCount="2" compression="off" connectionLinger="-1" connectionTimeout="120000" enableLookups="false"'
database:
maxOpenConnections: 100
extraEnvironmentVariables:
- name: MALLOC_ARENA_MAX
value: "8"
- name: SKIP_WAIT_FOR_EXTERNAL_DB
value: "true"
access:
tomcat:
connector:
maxThreads: 125
javaOpts:
other: >
-XX:InitialRAMPercentage=20
-XX:MaxRAMPercentage=60
database:
maxOpenConnections: 100
resources:
requests:
cpu: 1
memory: 2Gi
limits:
# cpu: 2
memory: 3Gi
extraEnvironmentVariables:
- name: MALLOC_ARENA_MAX
value: "8"
- name: SKIP_WAIT_FOR_EXTERNAL_DB
value: "true"
router:
resources:
requests:
cpu: 400m
memory: 800Mi
limits:
# cpu: "8"
memory: 2Gi
frontend:
resources:
requests:
cpu: 200m
memory: 300Mi
limits:
# cpu: "3"
memory: 1Gi
metadata:
database:
maxOpenConnections: 100
resources:
requests:
cpu: 200m
memory: 200Mi
limits:
# cpu: "4"
memory: 1Gi
onemodel:
resources:
requests:
cpu: 200m
memory: 160Mi
limits:
# cpu: "1"
memory: 250Mi
event:
resources:
requests:
cpu: 100m
memory: 50Mi
limits:
# cpu: 500m
memory: 250Mi
observability:
resources:
requests:
cpu: 100m
memory: 50Mi
limits:
# cpu: 500m
memory: 250Mi
jfconnect:
resources:
requests:
cpu: 50m
memory: 100Mi
limits:
# cpu: 500m
memory: 250Mi
topology:
resources:
requests:
cpu: 100m
memory: 1000Mi
limits:
memory: 1500Mi
extraEnvironmentVariables:
- name: MALLOC_ARENA_MAX
value: "8"
postgresql:
enabled: false
database:
## To run Artifactory with any database other than PostgreSQL allowNonPostgresql set to true.
allowNonPostgresql: false
type: "postgresql"
driver: org.postgresql.Driver
secrets:
user:
name: "my-database"
key: "db-user"
password:
name: "my-database"
key: "db-password"
url:
name: "my-database"
key: "db-url"
ingress:
enabled: false
nginx:
enabled: true
service:
type: LoadBalancer
ssloffload: true
tlsSecretName: artifactory-tls
replicaCount: 3
disableProxyBuffering: true
resources:
requests:
cpu: "1"
memory: "500Mi"
limits:
# cpu: "4"
memory: "1Gi"If you are passing the license key:$ helm install artifactory-ha \
--set artifactory.license.secret=artifactory-cluster-license \
--set artifactory.license.dataKey=art.lic \
-f values.yaml \
--namespace jfrog jfrog/artifactory-ha --version 107.104.10
Else:$ helm install artifactory-ha \ --set artifactory.license.secret=artifactory-cluster-license \ --set artifactory.license.dataKey=art.lic \ -f values.yaml \ --namespace jfrog jfrog/artifactory-ha --version 107.104.10
Deleting InstallationIf you ever need to delete the current release, you can dohelm delete artifactory-ha --namespace jfrog
However, this will not remove any persistent volumes. You need to explicitly remove the pvc if you intend for a fresh start.kubectl delete pvc -l release=artifactory-ha -n jfrog
kubectl delete pvc -l app.kubernetes.io/instance=artifactory-ha -n jfrog
Upgrade ArtifactoryIt’s recommended passing all the values in the previous release explicitly when running the upgrade command. This is to avoid falling back to any default values. Pay extreme attention to the secret you created, as failing to reference those in an upgrade action could result in new different values generated and breaking artifactory. It'd be difficult to recover from such a case. Updates minor version or updating values.yamlFor regular upgrade command when you just want to upgrade values:helm upgrade --install artifactory-ha \
--set databaseUpgradeReady=true \
-f values-new.yaml \
--namespace jfrog jfrog/artifactory-ha --version 107.x.x
If you want to upgrade the artifactory version, but the version does not come by default with the current chart version. Note that you must always pass the version explicitly after doing this to avoid falling back to an old version:helm upgrade --install artifactory-ha \
--set databaseUpgradeReady=true \
--set global.versions.artifactory= 7.x.x\
-f values.yaml \
--namespace jfrog jfrog/artifactory-ha --version 107.x.x
Updates chart versionhelm upgrade --install artifactory-ha \
--set databaseUpgradeReady=true \
-f values.yaml \
--namespace jfrog jfrog/artifactory-ha --version 107.x.x
Always check the changelog first for any major version jump.
It’s recommended to upgrade the chart version when you are upgrading Artifactory to a version that comes default to a new chart version.
Note
1. The databaseUpgradeReady flag is only required when using the bundled PostgreSQL chart. This flag is designed to encourage caution by prompting you to verify that no unintended property changes have been introduced to the bundled database. We recommend using the --dry-run option to evaluate any potential unexpected changes before proceeding with the upgrade of the bundled PostgreSQL database.
2. If you are upgrading from a chart version earlier than 4.x.x that specifies postgresql.image.tag values of 9.x, 10.x, or 12.x, ensure that you pass the appropriate postgresql.image.tag and set databaseUpgradeReady=true
GlossaryTuning - https://jfrog.com/knowledge-base/how-do-i-tune-artifactory-for-heavy-loads/
System Requirements: https://www.jfrog.com/confluence/display/JFROG/System+Requirements
Filestore - https://www.jfrog.com/confluence/display/JFROG/Configuring+the+Filestore
External Database - https://www.jfrog.com/confluence/display/JFROG/Configuring+the+Database
Chart Source Code - https://github.com/jfrog/charts/tree/master/stable/artifactory-ha
Official Artifactory Helm documents - https://www.jfrog.com/confluence/display/JFROG/Installing+Artifactory#InstallingArtifactory-HelmHAInstallation
Helm charts for Advanced users - https://www.jfrog.com/confluence/display/JFROG/Helm+Charts+for+Advanced+Users
Kubernetes Load Balancer Service -https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/
Kubernetes Default Storage Class -https://kubernetes.io/docs/tasks/administer-cluster/change-default-storage-class/
Kubernetes dynamic provision PV -https://kubernetes.io/docs/concepts/storage/dynamic-provisioning/