How to migrate Jenkins to "code"?

I have a prepared ansible playbook to install Jenkins on new VMs:

  • prepare filesystem
  • technical account(s)
  • base repository
  • required OS packages
  • Jenkins base configuration for systemd mainly
  • base plugins

Is there a way to dump active Jenkins to a code? I would like to copy current configuration to a code, not necessarily ansible.
I would like to easily install Jenkins on VMs with a similar configuration. What’s the best way to go about it?

Ultimately, maybe this is the direction I would like to go: Configuration as Code

Best regards, Piotr

Most of the time you wouldn’t want to duplicate Jenkins installations. Why? Because some tasks are scheduled, and you probably don’t want the same job schedules to run multiple times (on muliple jenkins installations).

  • If you want to create a backup of jobs then you just need to copy config.xml from each job (this will not include artifacts etc).
  • If you want a create a backup of jenkins configuration then you’ll need to backup main config.xml as well as other files (probably except for workspace and jobs).
  • If you want to run multiple instances of Jenkins then you probably want to create Nodes. In which case Jenkins will install most things for you (e.g. will install Java so you can execute Maven build and tests).
1 Like

I’m stupid. After installing casc the option to download the configuration appears. But I have a problem with casc. Sometimes it works, sometimes no.
On the latest LTS Jenkins version with a set of plug-ins:

2024-02-14 12:23:50.693+0000 [id=102]	WARNING	h.ExpressionFactory2$JexlExpression#evaluate: Caught exception evaluating: it.stackTraceString in /. Reason: java.lang.reflect.InvocationTargetException
java.lang.IllegalStateException: Jenkins.instance is missing. Read the documentation of Jenkins.getInstanceOrNull to see what you are doing wrong.
	at jenkins.model.Jenkins.get(Jenkins.java:819)
	at io.jenkins.plugins.casc.impl.configurators.DataBoundConfigurator.getDescriptor(DataBoundConfigurator.java:229)
	at io.jenkins.plugins.casc.impl.configurators.DataBoundConfigurator.getName(DataBoundConfigurator.java:217)
	at io.jenkins.plugins.casc.ConfiguratorException.getMessage(ConfiguratorException.java:103)
	at java.base/java.lang.Throwable.getLocalizedMessage(Throwable.java:397)
	at java.base/java.lang.Throwable.toString(Throwable.java:496)
	at hudson.Functions.doPrintStackTrace(Functions.java:1753)
	at hudson.Functions.doPrintStackTrace(Functions.java:1744)
	at hudson.Functions.doPrintStackTrace(Functions.java:1744)
	at hudson.Functions.doPrintStackTrace(Functions.java:1744)
	at hudson.Functions.doPrintStackTrace(Functions.java:1744)
	at hudson.Functions.doPrintStackTrace(Functions.java:1744)
	at hudson.Functions.printThrowable(Functions.java:1727)

@Nux
Yes, I want to duplicate Jenkins instance/installation. In short, I need additional Jenkins to:

  • testing new version, plug-ins
  • to switch to the stable version of Jenkins production

Sometimes after an upgrade of Jenkins, more plug-ins, Jenkins doesn’t get up or something doesn’t work as it should.

In that case I would say your safest and most accurate way would be to install Jenkins on a virtual machine. And just duplicate the machine when you want to test new things. Otherwise it would be very hard to make exactly the same environment (including e.g. out going SSH connections, saved authentications etc).

I regularly use segments from the configuration as code “View configuration” to update the container image that I use to make my test environment portable across multiple machines. I’ve been doing that successfully for several years. Others have been doing similar things for even longer.

The configuration as code page on the Jenkins controller says:

Export is not intended to offer a directly usable jenkins.yaml configuration. It can be used for inspiration writing your own, be aware export can be partial, or fail for some components.

Those are some of the reasons why I use configuration as code as well. I also use it to test new JDK versions and to test new Jenkins releases and to test large scale administrative changes. It works great for all those things.

I disagree with the recommendation from @Nux because I find it easier to represent a Jenkins controller as a container image than as a virtual machine. Both can be done, but container definition is easier for me than virtual machine definition.

I also agree. For me, JCAsC would be a big improvement. But, I do not know why, in some cases, this plugin does not work on my Jenkins installation. Interestingly, on others, it works.

I don’t know if the plugin itself is messing something up, or more a set of plugins, some conflict between plugins.

I have another problem that I recently noticed. During migration, API user tokens are not copied by me. Where does Jenkins keep the API user tokens?

In the file /users/user/config.xml I have:

          <jenkins.security.apitoken.ApiTokenStore_-HashedToken>
            <uuid>uuid</uuid>
            <name>name</name>
            <creationDate>2024-01-24 18:39:53.435 UTC</creationDate>
            <value>
              <version>11</version>
              <hash>hash</hash>
            </value>
          </jenkins.security.apitoken.ApiTokenStore_-HashedToken>

All secret* files are the same on both Jenkins, but I can only see the API token on one.

Reference: Ability to preconfigure an API token via JCasC · Issue #1830 · jenkinsci/configuration-as-code-plugin · GitHub
I can create a token, but I don’t know how to migrate all users’ tokens by copying a file or files.

I’m using VMs for that. But I don’t have access to a hypervisor. I am aware that I will not duplicate everything.