With this scant information, it is impossible to say what might be going on.
The one sample of the wait type, suggests that the query is CPU bound.
This in its turn suggest that it may be a plan issue. While the query may have run in sub-second earlier, there is not really any guarantee that it will continue to do so. If the plan has fallen out of cache, there will be a new compilation, and if statistics have changed, or there are other changes, the optimizer may make a different choice of query plan. And, yes, sometimes that can be a plan which is disastrously slower than the previous one.
I would suggest that you peek into Query Store to verify the hypothesis. In Query Store you can also force the old plan, provided that it is still there. (It is not clear to me how you got the data into the new instance.)
The query as such could in my opinion be better written like this.
update f
set f.freight_fk = f.tracking_shipper
from fulfillment f
where f.tracking_shipper is not null
and f.freight_fk is null
and exists (select *
from freight_cost fc
where fc.tracking_shipper = f.tracking_shipper
and fc.tenant_key = f.tenant_key
and (fc.fulfillment_fk is null or fc.fulfillment_fk = f.tracking_shipper))
Whether this will be faster, I don't know, but I think it expresses the intent better. And I removed the two NOLOCK which should not be there.
Just to make sure: You are talking about Azure SQL Managed Instance and not Azure SQL Database?